git pull
có lẽ đang tạo ra các cam kết. Nếu bạn thực hiện một cam kết cục bộ và sau đó chạy git pull
sau khi người khác đẩy một cam kết lên kho lưu trữ, Git tải xuống cam kết của nhà phát triển khác và sau đó hợp nhất nó vào chi nhánh địa phương của bạn.
Làm thế nào để tránh những cam kết hợp nhất này trong tương lai
Bạn có thể sử dụng git pull --rebase
để ngăn chặn điều này xảy ra trong tương lai, nhưng việc nổi loạn có những nguy hiểm và tôi khuyên bạn nên tránh pull
hoàn toàn .
Thay vào đó, tôi khuyến khích bạn làm theo mô hình sử dụng này:
# download the latest commits
git remote update -p
# update the local branch
git merge --ff-only @{u}
# if the above fails with a complaint that the local branch has
# diverged:
git rebase -p @{u}
Giải trình
git remote update -p
tải xuống tất cả các cam kết trong kho lưu trữ từ xa và cập nhật các nhánh theo dõi từ xa (ví dụ origin/master
:). Nó KHÔNG chạm vào thư mục làm việc, chỉ mục hoặc các nhánh cục bộ của bạn.
Các -p
đối số cắt tỉa xóa chi nhánh thượng nguồn. Do đó, nếu foo
nhánh bị xóa trong origin
kho lưu trữ, git remote update -p
sẽ tự động xóa origin/foo
ref của bạn .
git merge --ff-only @{u}
nói với Git để hợp nhất nhánh ngược dòng ( @{u}
đối số) vào nhánh cục bộ của bạn nhưng chỉ khi nhánh cục bộ của bạn có thể được "chuyển tiếp nhanh" đến nhánh ngược dòng (nói cách khác, nếu nó không được chuyển hướng).
git rebase -p @{u}
di chuyển một cách hiệu quả các cam kết bạn đã thực hiện nhưng chưa được đẩy lên trên nhánh thượng nguồn, điều này giúp loại bỏ nhu cầu tạo ra các cam kết ngớ ngẩn mà bạn đang cố gắng tránh. Điều này cải thiện tính tuyến tính của lịch sử phát triển, giúp dễ dàng xem xét hơn.
Các -p
tùy chọn cho Git để giữ gìn hòa trộn. Điều này ngăn Git tuyến tính hóa các cam kết bị từ chối. Điều này rất quan trọng nếu, ví dụ, bạn đã hợp nhất một nhánh tính năng vào master
. Nếu không -p
, mọi cam kết trên nhánh tính năng sẽ được sao chép trên master
một phần của quá trình tuyến tính hóa được thực hiện bởi git rebase
. Điều này sẽ làm cho lịch sử phát triển khó xem xét hơn, không dễ dàng hơn.
Coi chừng : git rebase
có thể không làm những gì bạn mong đợi, vì vậy hãy xem lại kết quả trước khi đẩy. Ví dụ:
git log --graph --oneline --decorate --date-order --color --boundary @{u}..
Tôi thích cách tiếp cận này hơn git pull --rebase
vì những lý do sau:
- Nó cho phép bạn xem các cam kết ngược dòng đến trước khi sửa đổi lịch sử của bạn để kết hợp chúng.
- Nó cho phép bạn chuyển tùy chọn
-p
( --preserve-merges
) git rebase
trong trường hợp bạn cần khởi động lại một sự hợp nhất có chủ ý (ví dụ: hợp nhất một nhánh tính năng đã được đẩy vào master
).
Tốc ký: git up
thay vìgit pull
Để dễ thực hiện những điều trên, tôi khuyên bạn nên tạo một bí danh có tên up
:
git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'
Bây giờ tất cả những gì bạn cần làm để đưa chi nhánh của bạn cập nhật là chạy:
git up
thay vì git pull
. Nếu bạn gặp lỗi vì chi nhánh địa phương của bạn đã chuyển hướng từ nhánh ngược dòng, đó là gợi ý của bạn để phản ứng lại.
Tại sao không git pull --rebase
?
Chạy git pull --rebase
tương đương với chạy git fetch
theo sau git rebase
. Điều này cố gắng chuyển nhanh tới các cam kết ngược dòng mới, nhưng nếu điều đó là không thể thì nó sẽ phản hồi các cam kết cục bộ của bạn lên các cam kết ngược dòng mới. Điều này thường ổn, nhưng hãy cẩn thận:
- Rebase là một chủ đề nâng cao, và bạn nên hiểu ý nghĩa trước khi nổi loạn.
git pull --rebase
không cho bạn cơ hội kiểm tra các cam kết trước khi kết hợp chúng. Tùy thuộc vào những gì thay đổi ở thượng nguồn, nó khá có thể là rebase là hoạt động-một sai lầm rebase --onto
, merge
, reset
, hoặc push -f
có thể thích hợp hơn một đồng bằng rebase
.
- Hiện tại không thể chuyển
--preserve-merges
sang hoạt động rebase, do đó, bất kỳ sự hợp nhất có chủ ý nào của nhánh tính năng sẽ được tuyến tính hóa, phát lại (và do đó sao chép) tất cả các cam kết của nhánh tính năng.
"Sửa" một cam kết hợp nhất hiện có được tạo bởi git pull
Nếu bạn chưa đẩy một cam kết hợp nhất được tạo bởi git pull
, bạn có thể loại bỏ cam kết hợp nhất. Giả sử bạn chưa thực hiện bất kỳ sự hợp nhất có chủ ý nào (ví dụ: hợp nhất một nhánh tính năng đã được đẩy vào nhánh hiện tại của bạn), thì những điều sau đây nên làm:
git rebase @{u}
Lệnh trên yêu cầu Git chọn tất cả các cam kết không hợp nhất có thể truy cập từ HEAD
(cam kết hiện tại), trừ tất cả các cam kết có thể truy cập từ @{u}
(đó là tốc ký cho "nhánh ngược dòng", nghĩa là, origin/master
nếu HEAD
là master
), phát lại (cherry-pick ) chúng trên đỉnh của nhánh ngược dòng, và sau đó di chuyển tham chiếu nhánh hiện tại để trỏ đến kết quả của việc phát lại các xác nhận. Điều này có hiệu quả di chuyển các cam kết không hợp nhất vào cam kết ngược dòng gần đây nhất, loại bỏ việc hợp nhất được tạo bởi git pull
.
Nếu bạn có một cam kết hợp nhất có chủ ý, bạn không muốn chạy git rebase @{u}
vì nó sẽ phát lại mọi thứ từ nhánh khác. Đối phó với trường hợp này thực sự phức tạp hơn, đó là lý do tại sao nó tốt để sử dụng git up
và tránh git pull
hoàn toàn. Có lẽ bạn sẽ phải sử dụng reset
để hoàn tác việc hợp nhất được tạo bởi pull
và sau đó thực hiện git rebase -p @{u}
. Đối -p
số git rebase
đã không hoạt động đáng tin cậy đối với tôi, vì vậy cuối cùng bạn có thể phải sử dụng reset
để hoàn tác hợp nhất có chủ ý, cập nhật chi nhánh địa phương của bạn @{u}
và sau đó làm lại hợp nhất có chủ ý (đó là một nỗi đau nếu có nhiều hợp nhất lông xung đột).