Git Pull Force - Cách ghi đè các thay đổi cục bộ bằng Git

Khi bạn học viết mã, sớm hay muộn bạn cũng sẽ học về Hệ thống kiểm soát phiên bản. Và trong khi có nhiều công cụ cạnh tranh trong lĩnh vực này, một trong số chúng là tiêu chuẩn thực tế được hầu hết mọi người trong ngành sử dụng. Nó phổ biến đến mức có những công ty sử dụng tên của nó trong thương hiệu của họ. Tất nhiên, chúng ta đang nói về Git.

Mặc dù Git là một công cụ mạnh mẽ, nhưng sức mạnh của nó lại được giấu kín. Có một số khái niệm cần thiết mà bạn cần hiểu để trở nên thực sự thành thạo với Git. Tin tốt là một khi bạn học chúng, bạn sẽ hiếm khi gặp rắc rối mà bạn không thể thoát khỏi.

Quy trình làm việc điển hình

Trong một quy trình làm việc Git điển hình, bạn sẽ sử dụng một kho lưu trữ cục bộ, một kho lưu trữ từ xa và một hoặc nhiều chi nhánh. Kho lưu trữ tất cả các thông tin về dự án, bao gồm toàn bộ lịch sử của nó và tất cả các chi nhánh. Một nhánh về cơ bản là một tập hợp các thay đổi dẫn từ một dự án trống đến trạng thái hiện tại.

Sau khi nhân bản kho lưu trữ, bạn làm việc trên bản sao cục bộ của mình và giới thiệu các thay đổi mới. Cho đến khi bạn đẩy các thay đổi cục bộ vào kho lưu trữ từ xa, tất cả công việc của bạn chỉ có sẵn trên máy của bạn.

Khi bạn hoàn thành một nhiệm vụ, đã đến lúc đồng bộ hóa với kho lưu trữ từ xa. Bạn muốn thực hiện các thay đổi từ xa để theo kịp tiến độ của dự án và bạn muốn thực hiện các thay đổi cục bộ để chia sẻ công việc của mình với những người khác.

Thay đổi cục bộ

Tất cả đều tốt khi bạn và những người còn lại trong nhóm của bạn đang làm việc trên các tệp hoàn toàn riêng biệt. Dù có chuyện gì xảy ra, các bạn sẽ không giẫm lên chân nhau.

Tuy nhiên, có những lúc bạn và đồng đội của mình đồng thời đưa ra những thay đổi ở cùng một nơi. Và đó thường là nơi các vấn đề bắt đầu.

Bạn đã bao giờ thực hiện git pullchỉ để nhìn thấy sự sợ hãi error: Your local changes to the following files would be overwritten by merge:? Không sớm thì muộn, mọi người đều gặp phải vấn đề đó.

Điều khó hiểu hơn ở đây là bạn không muốn hợp nhất bất cứ thứ gì, chỉ cần kéo, phải không? Trên thực tế, kéo phức tạp hơn một chút so với bạn có thể nghĩ.

Git Pull hoạt động chính xác như thế nào?

Kéo không phải là một hoạt động đơn lẻ. Nó bao gồm tìm nạp dữ liệu từ máy chủ từ xa và sau đó hợp nhất các thay đổi với kho lưu trữ cục bộ. Hai thao tác này có thể được thực hiện thủ công nếu bạn muốn:

git fetch git merge origin/$CURRENT_BRANCH

Một origin/$CURRENT_BRANCHphần có nghĩa là:

  • Git sẽ hợp nhất các thay đổi từ kho lưu trữ từ xa có tên origin( kho lưu trữ bạn đã sao chép từ đó)
  • đã được thêm vào $CURRENT_BRANCH
  • chưa có trong chi nhánh trả phòng tại địa phương của bạn

Vì Git chỉ thực hiện hợp nhất khi không có thay đổi nào chưa được cam kết, mỗi khi bạn chạy git pullvới các thay đổi chưa được cam kết có thể khiến bạn gặp rắc rối. May mắn thay, có nhiều cách để thoát khỏi rắc rối trong một mảnh!

Chúng ta là gia đình

Phương pháp tiếp cận khác nhau

Khi bạn có các thay đổi cục bộ chưa được cam kết và vẫn muốn lấy phiên bản mới từ máy chủ từ xa, trường hợp sử dụng của bạn thường rơi vào một trong các trường hợp sau. Hoặc:

  • bạn không quan tâm đến các thay đổi cục bộ và muốn ghi đè chúng,
  • bạn rất quan tâm đến những thay đổi và muốn áp dụng chúng sau những thay đổi từ xa,
  • bạn muốn tải xuống các sửa đổi từ xa nhưng chưa áp dụng chúng

Mỗi cách tiếp cận yêu cầu một giải pháp khác nhau.

Bạn không quan tâm đến các thay đổi cục bộ

Trong trường hợp này, bạn chỉ muốn bỏ tất cả các thay đổi cục bộ chưa cam kết. Có lẽ bạn đã sửa đổi một tệp để thử nghiệm, nhưng bạn không cần sửa đổi nữa. Tất cả những gì bạn quan tâm là được cập nhật với thượng nguồn.

Điều này có nghĩa là bạn phải thêm một bước nữa giữa tìm nạp các thay đổi từ xa và hợp nhất chúng. Bước này sẽ đặt lại nhánh về trạng thái chưa sửa đổi, do đó cho phép git mergehoạt động.

git fetch git reset --hard HEAD git merge origin/$CURRENT_BRANCH

Nếu bạn không muốn gõ tên chi nhánh mỗi khi bạn chạy lệnh này, Git có một phím tắt thoải mái trỏ đến các chi nhánh thượng nguồn: @{u}. Nhánh ngược dòng là nhánh trong kho lưu trữ từ xa mà bạn đẩy đến và tìm nạp từ đó.

Đây là cách các lệnh trên trông như thế nào với phím tắt:

git fetch git reset --hard HEAD git merge '@{u}'

Chúng tôi đang trích dẫn phím tắt trong ví dụ để ngăn trình bao thông dịch nó.

Bạn rất quan tâm đến những thay đổi cục bộ

Khi những thay đổi chưa cam kết của bạn có ý nghĩa quan trọng đối với bạn, có hai tùy chọn. Bạn có thể cam kết chúng và sau đó thực hiện git pullhoặc bạn có thể lưu trữ chúng.

Stashing có nghĩa là tạm dừng các thay đổi để đưa chúng trở lại sau. Nói chính xác hơn, hãy git stashtạo một cam kết không hiển thị trên chi nhánh hiện tại của bạn, nhưng vẫn có thể truy cập được bằng Git.

Để khôi phục các thay đổi đã lưu trong kho cuối cùng, bạn sử dụng git stash poplệnh. Sau khi áp dụng thành công các thay đổi đã lưu trữ, lệnh này cũng xóa cam kết lưu trữ vì nó không còn cần thiết nữa.

Quy trình làm việc sau đó có thể trông như thế này:

git fetch git stash git merge '@{u}' git stash pop

By default, the changes from the stash will become staged. If you want to unstage them, use the command git restore --staged (if using Git newer than 2.25.0).

You Just Want to Download the Remote Changes

The last scenario is a little different from the previous ones. Let's say that you are in the middle of a very messy refactoring. Neither losing the changes nor stashing them is an option. Yet, you still want to have the remote changes available to run git diff against them.

As you have probably figured out, downloading the remote changes does not require git pull at all! git fetch is just enough.

One thing to note is that by default, git fetch will only bring you changes from the current branch. To get all the changes from all the branches, use git fetch --all. And if you'd like to clean up some of the branches that no longer exist in the remote repository, git fetch --all --prune will do the cleaning up!

Some Automation

Have you heard of Git Config? It's a file where Git stores all of the user-configured settings. It resides in your home directory: either as ~/.gitconfig or ~/.config/git/config. You can edit it to add some custom aliases that will be understood as Git commands.

For example, to have a shortcut equivalent to git diff --cached (that shows the difference between the current branch and the staged files), you'd add the following section:

[alias] dc = diff --cached

After that, you can run git dc whenever you wish to review the changes. Going this way, we can set up a few aliases related to the previous use cases.

[alias] pull_force = !"git fetch --all; git reset --hard HEAD; git merge @{u}" pf = pull_force pull_stash = !"git fetch --all; git stash; git merge @{u}; git stash pop"

This way, running git pull_force will overwrite the local changes, while git pull_stash will preserve them.

The Other Git Pull Force

Curious minds may have already discovered that there is such a thing as git pull --force. However, this is a very different beast to what's presented in this article.

It may sound like something that would help us overwrite local changes. Instead, it lets us fetch the changes from one remote branch to a different local branch. git pull --force only modifies the behavior of the fetching part. It is therefore equivalent to git fetch --force.

Like git push, git fetch allows us to specify which local and remote branch do we want to operate on. git fetch origin/feature-1:my-feature will mean that the changes in the feature-1 branch from the remote repository will end up visible on the local branch my-feature. When such an operation modifies the existing history, it is not permitted by Git without an explicit --force parameter.

Just like git push --force allows overwriting remote branches, git fetch --force (or git pull --force) allows overwriting local branches. It is always used with source and destination branches mentioned as parameters. An alternative approach to overwriting local changes using git --pull force could be git pull --force "@{u}:HEAD".

Conclusion

Thế giới của Git rất rộng lớn. Bài viết này chỉ đề cập đến một trong những khía cạnh của bảo trì kho lưu trữ: kết hợp các thay đổi từ xa vào kho lưu trữ cục bộ. Ngay cả tình huống hàng ngày này cũng yêu cầu chúng tôi xem xét sâu hơn một chút vào các cơ chế bên trong của công cụ kiểm soát phiên bản này.

Tìm hiểu các trường hợp sử dụng thực tế sẽ giúp bạn hiểu rõ hơn về cách hoạt động của Git. Điều này sẽ khiến bạn cảm thấy được tiếp thêm sức mạnh bất cứ khi nào bạn gặp khó khăn. Tất cả chúng ta đều làm điều đó theo thời gian.