Khi nào tôi nên sử dụng git pull --rebase?


806

Tôi biết một số người sử dụng git pull --rebasetheo mặc định và những người khác khăng khăng không bao giờ sử dụng nó. Tôi tin rằng tôi hiểu sự khác biệt giữa sáp nhập và nổi loạn, nhưng tôi đang cố gắng đặt điều này trong bối cảnh git pull. Có phải chỉ là không muốn thấy nhiều thông điệp cam kết hợp nhất, hoặc có vấn đề nào khác không?


1
Nguồn cho mọi người tư vấn chống git pull --rebase? Rebase hoặc git rebase là hoạt động riêng biệt từ git pull --rebase!
przemo_li

Câu trả lời:


584

Bạn nên sử dụng git pull --rebasekhi

  • những thay đổi của bạn không xứng đáng là một nhánh riêng biệt

Thật vậy - tại sao không? Nó rõ ràng hơn và không áp đặt một nhóm hợp lý vào các cam kết của bạn.


Ok, tôi cho rằng nó cần một số làm rõ. Trong Git, như bạn có thể biết, bạn được khuyến khích phân nhánh và hợp nhất. Chi nhánh địa phương của bạn, trong đó bạn kéo các thay đổi và chi nhánh từ xa thực sự là các nhánh khác nhau và git pulllà về việc hợp nhất chúng. Điều đó hợp lý, vì bạn không thường xuyên thúc đẩy và thường tích lũy một số thay đổi trước khi chúng tạo thành một tính năng hoàn chỉnh.

Tuy nhiên, đôi khi - vì bất kỳ lý do gì - bạn nghĩ rằng nó thực sự sẽ tốt hơn nếu hai thứ này - từ xa và cục bộ - là một nhánh. Giống như ở SVN. Đây là nơi mà git pull --rebaseđi vào chơi. Bạn không còn hợp nhất - bạn thực sự cam kết trên đầu chi nhánh từ xa . Đó là những gì nó thực sự là về.

Có nguy hiểm hay không là câu hỏi liệu bạn có đang đối xử với chi nhánh địa phương và từ xa như một điều không thể tách rời. Đôi khi điều đó hợp lý (khi những thay đổi của bạn nhỏ hoặc nếu bạn đang bắt đầu phát triển mạnh mẽ, khi những thay đổi quan trọng được đưa vào bởi những cam kết nhỏ). Đôi khi không phải vậy (khi bạn thường tạo một nhánh khác, nhưng bạn quá lười để làm điều đó). Nhưng đó là một câu hỏi khác nhau.


17
Tôi nghĩ nó hữu ích khi bạn làm việc trên cùng một chi nhánh, nhưng bạn có thể thay đổi máy trạm của mình. Tôi có xu hướng cam kết và thúc đẩy các thay đổi của mình từ một máy trạm, sau đó kéo rebase vào máy khác và tiếp tục làm việc trên cùng một nhánh.
Pablo Pazos

11
Đó là một cách thực hành hữu ích tốt nhất để thiết lập Git để tự động khởi động lại khi kéo git config --global pull.rebase preserve (bảo vệ nói ngoài việc bật lại, để cố gắng duy trì các phép hợp nhất nếu bạn đã thực hiện bất kỳ cục bộ nào).
Colin D Bennett

2
Tôi không đồng ý rằng bạn chỉ nên sử dụng pull --rebase khi làm việc trên một nhánh. Bạn nên sử dụng nó mọi lúc, trừ khi không thể vì một số trường hợp khác.
Tomáš Fejfar

@P Shved ... 'Tuy nhiên, đôi khi - vì bất kỳ lý do gì - bạn nghĩ rằng nó thực sự sẽ tốt hơn nếu hai thứ này - từ xa và cục bộ - là một nhánh' ... điều này có thể được thực hiện không? rằng trong môi trường địa phương, tôi có thể có chi nhánh của mình và một nhân bản chi nhánh từ xa làm nguồn gốc / chủ. Bạn có thể vui lòng cung cấp đầu vào ở đây không?
Mandroid

736

Tôi muốn cung cấp một góc nhìn khác về ý nghĩa của "git pull --rebase", bởi vì đôi khi nó dường như bị mất.

Nếu bạn đã từng sử dụng Subversion (hoặc CVS), bạn có thể được sử dụng cho hành vi "cập nhật svn". Nếu bạn có các thay đổi để cam kết và cam kết thất bại vì các thay đổi đã được thực hiện ngược dòng, bạn "cập nhật svn". Subversion tiến hành bằng cách hợp nhất các thay đổi ngược dòng với của bạn, có khả năng dẫn đến xung đột.

Những gì Subversion vừa làm, về cơ bản là "pull --rebase". Hành động tái lập các thay đổi cục bộ của bạn có liên quan đến phiên bản mới hơn là phần "khởi động lại" của nó. Nếu bạn đã thực hiện "svn diff" trước lần thử cam kết không thành công và so sánh kết quả khác với kết quả của "svn diff" sau đó, sự khác biệt giữa hai khác biệt là những gì hoạt động khởi động lại đã làm.

Sự khác biệt chính giữa Git và Subversion trong trường hợp này là trong Subversion, "thay đổi" của bạn chỉ tồn tại dưới dạng những thay đổi không cam kết trong bản sao làm việc của bạn, trong khi trong Git bạn có các cam kết thực tế cục bộ. Nói cách khác, trong Git bạn đã rẽ nhánh lịch sử; lịch sử của bạn và lịch sử ngược dòng đã chuyển hướng, nhưng bạn có một tổ tiên chung.

Theo tôi, trong trường hợp bình thường có chi nhánh địa phương của bạn chỉ đơn giản là phản ánh chi nhánh thượng nguồn và phát triển liên tục trên đó, điều đúng đắn luôn luôn là "- cơ sở", bởi vì đó là những gì bạn thực sự đang làm . Bạn và những người khác đang hack đi vào lịch sử tuyến tính dự định của một chi nhánh. Việc một người khác tình cờ đẩy nhẹ trước nỗ lực đẩy của bạn là không liên quan, và dường như phản tác dụng đối với mỗi tai nạn thời gian như vậy dẫn đến sáp nhập trong lịch sử.

Nếu bạn thực sự cảm thấy cần một cái gì đó để trở thành một chi nhánh vì bất kỳ lý do gì, đó là một mối quan tâm khác theo quan điểm của tôi. Nhưng trừ khi bạn có mong muốn cụ thể và chủ động để thể hiện các thay đổi của mình dưới dạng hợp nhất, theo tôi, hành vi mặc định sẽ là "git pull --rebase".

Vui lòng xem xét những người khác cần quan sát và hiểu lịch sử của dự án của bạn. Bạn có muốn lịch sử tràn ngập hàng trăm sự hợp nhất ở khắp mọi nơi, hoặc bạn chỉ muốn một vài sự hợp nhất được lựa chọn đại diện cho sự hợp nhất thực sự của những nỗ lực phát triển khác nhau có chủ ý?


18
@MarceloCantos Để rõ ràng, tôi không nói rằng git (công cụ) nên mặc định để rebase. Điều đó sẽ nguy hiểm vì một cuộc nổi loạn về cơ bản phá hủy lịch sử. Tôi đang nói rằng về mặt quy trình công việc, khi bạn không có ý định phân nhánh và chỉ hack ở một số chi nhánh mà người khác cũng đang làm việc, "git pull --rebase" sẽ là hành vi mặc định của người dùng.
mã hóa

1
Bạn đang nói rằng không nên git config --global branch.autosetupmerge always?
Marcelo Cantos

9
@MarceloCantos Không phải là tôi;) Cá nhân tôi sẽ để autosetupmerge ast mặc định là true (nếu tôi hợp nhất trở lại và thứ tư giữa các nhánh khác ngoài địa phương <->, tôi muốn nó rõ ràng). Tôi chỉ nói rằng với tư cách là một con người, tôi luôn sử dụng "git pull --rebase" như một phần của quy trình "lấy mới nhất trong nhánh chính" thông thường của mình, bởi vì tôi không bao giờ muốn tạo một cam kết hợp nhất trừ khi tôi phân nhánh rõ ràng.
mã hóa

9
+1 @scode. Sau nhiều giờ đau đớn vật lộn với câu hỏi rebase / merge, cuối cùng đây cũng là một câu trả lời.
AgileYogi

10
Câu trả lời này chỉ là một nỗ lực để điều chỉnh người dùng hệ thống kiểm soát phiên bản không phân tán cho Git thay vì cho họ cơ hội hiểu đúng về lợi ích của việc có các chi nhánh phù hợp.
Alexey Zimarev

211

Có lẽ cách tốt nhất để giải thích nó là với một ví dụ:

  1. Alice tạo nhánh chủ đề A và làm việc với nó
  2. Bob tạo nhánh chủ đề B không liên quan và làm việc với nó
  3. Alice nào git checkout master && git pull. Sư phụ đã được cập nhật.
  4. Bob nào git checkout master && git pull. Sư phụ đã được cập nhật.
  5. Alice làm git merge topic-branch-A
  6. Bob làm git merge topic-branch-B
  7. Bob làm git push origin mastertrước Alice
  8. Alice làm git push origin master, điều này bị từ chối vì nó không phải là một sự hợp nhất nhanh chóng.
  9. Alice nhìn vào nhật ký gốc / chủ và thấy rằng cam kết không liên quan đến cô ấy.
  10. Alice làm git pull --rebase origin master
  11. Cam kết hợp nhất của Alice là không có cơ sở, cam kết của Bob bị kéo và cam kết của Alice được áp dụng sau cam kết của Bob.
  12. Alice làm được git push origin master, và mọi người đều vui khi họ không phải đọc một cam kết hợp nhất vô dụng khi họ nhìn vào nhật ký trong tương lai.

Lưu ý rằng nhánh cụ thể được sáp nhập vào không liên quan đến ví dụ. Master trong ví dụ này có thể dễ dàng là một nhánh phát hành hoặc nhánh dev. Điểm mấu chốt là Alice & Bob đang đồng thời hợp nhất các chi nhánh địa phương của họ thành một chi nhánh từ xa được chia sẻ.


2
Đẹp. Tôi có xu hướng rõ ràng và git co master && git pull; git checkout topic-branch-A; git rebase master; git checkout master; git merge topic-branch-A; git push origin masterlặp lại nếu việc đẩy người khác xảy ra trước tôi. Mặc dù tôi có thể thấy những lợi thế cô đọng trong công thức của bạn.
HankCa

Lời giải thích hay @Cody Poll
Rajanikanta Pradhan

148

Tôi nghĩ bạn nên sử dụng git pull --rebasekhi cộng tác với những người khác trong cùng chi nhánh. Bạn đang trong công việc → cam kết → công việc → chu kỳ cam kết và khi bạn quyết định đẩy công việc của mình, việc đẩy của bạn bị từ chối, bởi vì đã có công việc song song trên cùng một chi nhánh. Lúc này tôi luôn làm a pull --rebase. Tôi không sử dụng squash (để làm phẳng các xác nhận), nhưng tôi rebase để tránh các cam kết hợp nhất thêm.

Khi kiến ​​thức Git của bạn tăng lên, bạn thấy mình nhìn vào lịch sử nhiều hơn bất kỳ hệ thống kiểm soát phiên bản nào khác mà tôi đã sử dụng. Nếu bạn có hàng tấn cam kết nhỏ, bạn sẽ dễ mất tập trung vào bức tranh lớn hơn đang diễn ra trong lịch sử của mình.

Đây thực sự là lần duy nhất tôi thực hiện rebasing (*) và phần còn lại của quy trình làm việc của tôi là hợp nhất dựa trên. Nhưng miễn là những người thường xuyên nhất của bạn làm điều này, cuối cùng lịch sử sẽ tốt hơn rất nhiều.

(*) Trong khi giảng dạy một khóa học Git, tôi đã có một sinh viên bắt giữ tôi về điều này, vì tôi cũng ủng hộ việc nổi loạn các nhánh tính năng trong một số trường hợp nhất định. Và anh ta đã đọc câu trả lời này;) Việc nổi loạn như vậy cũng có thể, nhưng nó luôn phải theo một hệ thống được sắp xếp / thỏa thuận trước, và vì thế không nên "luôn luôn" được áp dụng. Và lúc đó tôi thường không làm gì pull --rebasecả, đó là câu hỏi nói về cái gì;)


2
chắc chắn người ta có thể viết một kịch bản để ẩn các cam kết hợp nhất từ nhật ký
hasen

3
Sáp nhập cũng có thể chứa khác biệt, điều đó có nghĩa là nó không hoàn toàn tầm thường
krosenvold

9
@hasen j Có, nhưng NỘI DUNG của những sự hợp nhất đó có thể có vấn đề
krosenvold

Câu trả lời này rất mơ hồ và có ý kiến ​​so với câu trả lời được chọn: ý của bạn là "cùng một nhánh" chính xác là gì? Tuy nhiên, có một số điểm tốt, đó không phải là câu trả lời được chọn.
iwein

1
Sự mơ hồ xung quanh "chi nhánh" là khá có chủ ý, vì có rất nhiều cách để sử dụng ref; "Dòng công việc" chỉ là một lựa chọn.
krosenvold

49

Tôi không nghĩ có bao giờ một lý do để không sử dụng pull --rebase- Tôi đã thêm mã vào Git một cách cụ thể để cho phép git pulllệnh của tôi luôn luôn chống lại các cam kết ngược dòng.

Khi xem qua lịch sử, sẽ không bao giờ thú vị khi biết anh chàng / gal làm việc trên tính năng dừng lại để đồng bộ hóa. Nó có thể hữu ích cho anh chàng / cô ấy trong khi anh ấy / cô ấy đang làm điều đó, nhưng đó là những gì reflogdành cho. Nó chỉ thêm tiếng ồn cho những người khác.


2
"Khi nhìn qua lịch sử, thật không bao giờ thú vị khi biết anh chàng làm việc trên tính năng này đã dừng để đồng bộ hóa." / nhưng điều đó không có nghĩa là những cam kết trung gian đó có khả năng là các bản dựng bị hỏng?
eglasius

10
Vâng, và họ cũng không phải là "toàn bộ nhà nước". Đó là lý do tại sao chúng tôi không muốn họ. Tôi muốn biết anh ấy muốn gì, không phải làm thế nào anh ấy đến đó.
Dustin

4
Nếu pull --rebaseluôn luôn được sử dụng, tại sao không pulllàm điều đó theo mặc định?
straya

2
Tôi sợ bạn sẽ phải đưa ra ý kiến ​​của riêng bạn. Tôi đã có một số điều trong tôi .gitconfigđể làm cho một số tùy chọn thực hiện đúng. Tôi nghĩ rằng git rebase làm điều sai theo mặc định, cũng như thẻ git, v.v ... Nếu bạn không đồng ý, bạn không cần phải biện minh cho ý kiến ​​của mình.
Dustin

8
Đó có vẻ là lời khuyên tốt nếu bạn lấy từ "thượng nguồn", nói từ mastervà nếu chi nhánh bạn kéo vào chưa được công khai (chưa). Nếu bạn kéo mặt khác từ một nhánh tính năng vào masternó giống như cách khác: không bao giờ có lý do để sử dụng --rebase, phải không? Đó có thể là lý do tại sao nó không được mặc định. Tôi thấy Rebase là cách các thay đổi sẽ chuyển từ đầu phân cấp xuống dưới và hợp nhất là cách chúng chảy ngược lên trên. derekgourlay.com/blog/git-when-to-merge-vs-when-to-rebase
jolvi

38

Chỉ cần nhớ:

  • kéo = tìm nạp + hợp nhất
  • kéo --rebase = tìm nạp + rebase

Vì vậy, chọn cách bạn muốn xử lý chi nhánh của bạn.

Bạn nên biết sự khác biệt giữa hợp nhất và rebase :)


9

Tôi nghĩ rằng nó sôi lên theo sở thích cá nhân.

Bạn có muốn che giấu những sai lầm ngớ ngẩn của mình trước khi thúc đẩy những thay đổi của bạn? Nếu vậy, git pull --rebaselà hoàn hảo. Nó cho phép bạn sau đó nén các cam kết của bạn với một vài (hoặc một) cam kết. Nếu bạn đã hợp nhất trong lịch sử (chưa được xử lý) của mình, thì không dễ để thực hiệngit rebase sau này.

Cá nhân tôi không ngại xuất bản tất cả những sai lầm ngớ ngẩn của mình, vì vậy tôi có xu hướng hợp nhất thay vì rebase.


8
Lưu ý cho bất cứ ai xem câu hỏi này: câu trả lời này hoàn toàn không liên quan đến câu hỏi "khi nào tôi nên sử dụng git pull --rebase?"
Therealklanni

3
@therealklanni Tôi đã chỉnh sửa câu trả lời để nó rõ ràng hơn về cách nó có liên quan đến câu hỏi (hy vọng không phá hủy ý định).
Paŭlo Ebermann

Chia sẻ nhật ký công việc bẩn thỉu và không có cấu trúc không phải là một nỗ lực trung thực, đó chỉ là sự lười biếng. Bạn đang lãng phí thời gian của mọi người bằng cách khiến họ đuổi theo bạn qua lỗ thỏ phát triển và gỡ lỗi; cung cấp cho họ kết quả, không lan man.
kstallah

8

git pull --rebasecó thể ẩn một lịch sử viết lại từ một cộng tác viên git push --force. Tôi khuyên bạn nên sử dụng git pull --rebase chỉ nếu bạn biết bạn quên để đẩy cam kết của bạn trước khi người khác cũng làm như vậy.

Nếu bạn không cam kết bất cứ điều gì, nhưng không gian làm việc của bạn không sạch sẽ, ngay git stashtrước đó git pull. Bằng cách này, bạn sẽ không âm thầm viết lại lịch sử của mình (có thể âm thầm bỏ một số công việc của bạn).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.