Tại sao git pull thực hiện hợp nhất thay vì rebase theo mặc định?


71

Hãy xem xét tình huống sau:

  • Bạn có một bản sao của kho git
  • Bạn có một số cam kết cục bộ (các cam kết chưa được đẩy ở bất cứ đâu)
  • Kho lưu trữ từ xa có các xác nhận mới mà bạn chưa điều chỉnh

Vì vậy, một cái gì đó như thế này:

Cam kết không hợp nhất

Nếu bạn thực hiện git pullvới các cài đặt mặc định, bạn sẽ nhận được một cái gì đó như thế này:

hợp nhất cam kết

Điều này là do git thực hiện hợp nhất.

Có một sự thay thế, mặc dù. Thay vào đó, bạn có thể yêu cầu pull thực hiện rebase:

git pull --rebase

và bạn sẽ nhận được điều này:

nổi loạn

Theo tôi, phiên bản nổi loạn có rất nhiều ưu điểm mà chủ yếu xoay quanh việc giữ cả mã và lịch sử của bạn sạch sẽ, vì vậy tôi hơi bị sốc bởi thực tế là git mặc định hợp nhất. Có, giá trị băm của các cam kết tại địa phương của bạn sẽ được thay đổi, nhưng đây có vẻ là một cái giá nhỏ để trả cho lịch sử đơn giản hơn mà bạn nhận được.

Mặc dù vậy, tôi không cho rằng đây là một mặc định xấu hay sai. Tôi chỉ gặp khó khăn khi nghĩ về lý do tại sao hợp nhất có thể được ưa thích cho mặc định. Chúng ta có cái nhìn sâu sắc về lý do tại sao nó được chọn? Có những lợi ích làm cho nó phù hợp hơn như một mặc định?

Động lực chính cho câu hỏi này là công ty của tôi đang cố gắng thiết lập một số tiêu chuẩn cơ bản (hy vọng, giống như hướng dẫn hơn) về cách chúng tôi tổ chức và quản lý kho lưu trữ của mình để giúp các nhà phát triển tiếp cận với kho lưu trữ mà họ chưa từng làm việc trước đây. Tôi quan tâm đến việc tạo ra một trường hợp mà chúng ta thường nên rebase trong loại tình huống này (và có lẽ là để khuyến nghị các nhà phát triển đặt cấu hình toàn cầu của họ thành rebase theo mặc định), nhưng nếu tôi phản đối điều đó, tôi chắc chắn sẽ hỏi tại sao rebase lại không ' t mặc định nếu nó rất tuyệt Vì vậy, tôi tự hỏi nếu có một cái gì đó tôi đang thiếu.

Có ý kiến ​​cho rằng câu hỏi này là một bản sao của Tại sao nhiều trang web lại thích ăn gừng rebase trên hơn so với trên git ; tuy nhiên, câu hỏi đó có phần ngược lại với câu hỏi này. Nó thảo luận về giá trị của rebase so với hợp nhất, trong khi câu hỏi này hỏi về lợi ích của việc hợp nhất so với rebase. Các câu trả lời phản ánh điều này, tập trung vào các vấn đề với hợp nhất và lợi ích của rebase.



Vấn đề khác là nếu bạn vô tình cam kết làm chủ, sau đó thực hiện một thao tác kéo hợp nhất, hai chủ có thể không đồng bộ mặc dù việc hợp nhất trông có vẻ bình thường. Đây là lý do tại sao bí danh kéo của tôi bao gồm - chỉ.
Ixrec

Nếu sourcetree từng thay đổi chế độ xem biểu đồ của nó để nó hiển thị các lần khởi động / sáp nhập khác nhau, bạn sẽ chuyển sang hợp nhất chứ?
Ewan

1
@Ewan SourceTree không nên thay đổi chế độ xem biểu đồ của nó. Nó thể hiện chính xác biểu đồ.
jpmc26

4
Đối với những người bỏ phiếu lừa đảo, xin lưu ý rằng nội dung trong câu trả lời tôi chấp nhận chắc chắn không có trong câu hỏi mà bạn cho là trùng lặp.
jpmc26

Câu trả lời:


56

Thật khó để biết chắc chắn tại sao hợp nhất là mặc định mà không nghe từ người đưa ra quyết định đó.

Đây là một lý thuyết ...

Git không thể cho rằng nó ổn khi - kéo dài mỗi lần kéo. Nghe cách âm thanh đó. "Rebase mọi kéo." chỉ âm thanh sai nếu bạn sử dụng yêu cầu kéo hoặc tương tự. Bạn sẽ rebase theo yêu cầu kéo?

Trong một nhóm không chỉ sử dụng Git để kiểm soát nguồn tập trung ...

  • Bạn có thể kéo từ thượng nguồn và từ hạ lưu. Một số người làm rất nhiều việc kéo từ hạ lưu, từ những người đóng góp, v.v.

  • Bạn có thể làm việc trên các tính năng phối hợp chặt chẽ với các nhà phát triển khác, lấy từ chúng hoặc từ một nhánh chủ đề được chia sẻ và đôi khi vẫn được cập nhật từ thượng nguồn. Nếu bạn luôn nổi loạn thì cuối cùng bạn sẽ thay đổi lịch sử chia sẻ, chưa kể đến các chu kỳ xung đột vui vẻ.

Git được thiết kế cho một nhóm phân phối cao , nơi mọi người không kéo và đẩy đến một repo trung tâm duy nhất. Vì vậy, mặc định có ý nghĩa.

  • Các nhà phát triển không biết khi nào thì okase sẽ hợp nhất theo mặc định.
  • Các nhà phát triển có thể nổi loạn khi họ muốn.
  • Những người làm công việc kéo nhiều và có nhiều lần kéo có được mặc định phù hợp nhất với họ.

Để có bằng chứng về ý định, đây là một liên kết đến một email nổi tiếng từ Linus Torvalds với quan điểm của ông về việc khi nào họ không nên phản công. Email kéo Dri-devel

Nếu bạn theo dõi toàn bộ chuỗi, bạn có thể thấy một nhà phát triển đang kéo từ một nhà phát triển khác và Linus đang kéo từ cả hai. Ông làm cho ý kiến ​​của mình khá rõ ràng. Vì anh ta có thể đã quyết định mặc định của Git, điều này có thể giải thích tại sao.

Rất nhiều người bây giờ sử dụng Git theo cách tập trung, trong đó mọi người trong một nhóm nhỏ chỉ kéo từ một repo trung tâm ngược dòng và đẩy đến cùng một điều khiển từ xa. Kịch bản này tránh một số tình huống trong đó một cuộc nổi loạn không tốt, nhưng thường không loại bỏ chúng.

Gợi ý: Đừng đưa ra chính sách thay đổi mặc định. Bất cứ khi nào bạn đặt Git cùng với một nhóm lớn các nhà phát triển, một số nhà phát triển sẽ không hiểu Git sâu sắc (bao gồm cả tôi). Họ sẽ truy cập Google, SO, nhận lời khuyên về sách dạy nấu ăn và sau đó tự hỏi tại sao một số thứ không hoạt động, ví dụ tại sao lại git checkout --ours <path>lấy phiên bản sai của tệp? Bạn luôn có thể sửa đổi môi trường địa phương của bạn, tạo bí danh, vv để phù hợp với sở thích của bạn.


5
+1 vì không thay đổi mặc định - thay vì thực hiện quy trình git của riêng bạn, có lẽ tốt hơn là lấy một cái tồn tại (ví dụ: bất kỳ cái nào được tài liệu của Atlassian atlassian.com/git/tutorials/compared-workflows/ tựa )
Rob Church

1
Cảm ơn câu trả lời. Thông tin về việc kéo từ hạ lưu là những gì tôi đã thiếu. Ngoài ra, thú vị đủ, liên kết mà bạn đã khuyến khích chính xác những gì tôi muốn đạt được: "Mọi người có thể (và có lẽ nên) rebase họ tin cây (công việc của mình)."
jpmc26

2
@jpmc Tuyệt vời. Thật. Nổi loạn cây tư nhân có thể giữ rất nhiều crud phân tâm ra khỏi lịch sử được chia sẻ. Tôi làm điều đó. Đó là sự rõ ràng khi không làm điều đó quan trọng.
joshp

"Một số nhà phát triển sẽ không hiểu Git sâu sắc". Rebase KHÔNG phải là một tính năng siêu lạ mắt ("sâu sắc", v.v.) của Git. Bạn có thực sự xem xét điều này là khó hiểu? Tôi nghĩ rằng đây nên là một kích hoạt để gọi dev không đủ năng lực.
Victor Yarema

15

Nếu bạn đọc trang git cho rebase, nó sẽ nói :

Rebasing (hoặc bất kỳ hình thức viết lại nào khác) một nhánh mà những người khác đã làm việc dựa trên đó là một ý tưởng tồi: bất kỳ ai ở hạ lưu của nó đều bị buộc phải tự sửa lịch sử của họ. Phần này giải thích cách thực hiện sửa chữa theo quan điểm của hạ lưu. Tuy nhiên, cách khắc phục thực sự sẽ là tránh việc ngược dòng ở vị trí đầu tiên.

Tôi nghĩ rằng nó đủ tốt để làm lý do không sử dụng rebase, hãy để một mình tự động làm điều đó cho mỗi lần kéo. Một số người coi rebase là có hại . Có lẽ nó không bao giờ nên được đưa vào git, vì tất cả những gì nó làm là làm đẹp thêm lịch sử, một điều không cần thiết trong bất kỳ SCM nào có công việc thiết yếu duy nhất là bảo tồn lịch sử.

Khi bạn nói 'giữ ... lịch sử sạch sẽ', hãy nghĩ rằng bạn đã sai. Nó có thể trông đẹp hơn, nhưng đối với một công cụ được thiết kế để giữ lịch sử sửa đổi, việc giữ mọi cam kết sẽ sạch sẽ hơn nhiều để bạn có thể thấy những gì đã xảy ra. Vệ sinh lịch sử sau đó cũng giống như đánh bóng patin đi, làm cho một cổ vật phong phú trông giống như một lời trách móc sáng bóng :-)


3
@Ewan IMHO "không hoạt động nhưng trông khá đẹp" là thứ chỉ nên dành riêng cho ngành thời trang không phải CNTT. IMHO git nên loại bỏ nó vì nó rõ ràng khuyến khích quá nhiều người nghĩ rằng phong cách quan trọng hơn chất.
gbjbaanb

12
Tôi sẽ tranh luận đề nghị của bạn rằng giữ cho lịch sử sạch sẽ là vô ích. Không phải vậy. Một lịch sử kho lưu trữ được dành cho tiêu dùng của con người, và như vậy, có rất nhiều giá trị trong việc làm cho nó có thể đọc được. Trong trường hợp sử dụng cụ thể của tôi, chúng tôi thậm chí còn dự định rằng Người quản lý dự án không phải là nhà phát triển sẽ có thể đọc lịch sử. Một lịch sử sạch chỉ có thể giúp với điều đó và nó có thể giúp một nhà phát triển mới chưa bao giờ nhìn thấy cơ sở mã và phải đi sâu vào và sửa một lỗi hiểu những gì đã xảy ra trong một khu vực cụ thể của mã.
jpmc26

3
Mã tồn tại đầu tiên và quan trọng nhất được thực thi bởi một máy (có thể sau khi được biên dịch). Áp dụng triết lý của bạn ở trên, chúng tôi sẽ kết luận rằng khả năng đọc mã không thành vấn đề vì không có khả năng đọc nào sẽ giải quyết được khó khăn trong việc hiểu mã. Tôi không bao giờ đề nghị rằng bất cứ điều gì nên được nghiền nát. Tôi chỉ đơn thuần nói rằng một biểu đồ phức tạp phân ra thành nhiều đường chéo rất khó theo dõi, vì vậy, đáng để đầu tư một chút để giữ cho lịch sử của bạn khá sạch sẽ. Cũng lưu ý rằng một lịch sử tuyến tính có lợi hơn cho việc tận dụng các công cụ git như đổ lỗi và chia đôi.
jpmc26

6
Các tài liệu không nói "không nổi loạn." Nó nói, "đừng phản đối những thay đổi ngược dòng của người khác ." Có một thế giới của sự khác biệt giữa hai. Linus tự khuyên một số cuộc nổi loạn để tổ chức lịch sử, như có thể thấy trong liên kết trong câu trả lời được chấp nhận. Và làm thế nào để bất kỳ công cụ nào biết những cam kết nào không liên quan (đặc biệt là nếu các công cụ gặp khó khăn trong việc phân tích lịch sử phi tuyến tính!), Và làm thế nào bạn biết bạn muốn cam kết với điều gì (đặc biệt là không thể tìm hiểu lịch sử!)? Bạn đang có một lời cảnh báo về một tình huống cụ thể đến cực đoan giáo điều.
jpmc26

4
Bạn chắc chắn không muốn "giữ lịch sử sửa đổi" nếu điều đó bao gồm mọi cam kết mà nhà phát triển đã từng thực hiện. Theo logic đó, chúng ta cũng nên ghi lại phiên bản mã gốc mỗi lần nhấn phím backspace. Mỗi cam kết phải là một thay đổi tối thiểu và đầy đủ mà vẫn giữ cho toàn bộ dự án ở trạng thái ổn định. Nếu sau đó, cam kết ban đầu của bạn bị phát hiện là có lỗi, tốt hơn hết là bạn nên rebase / chỉnh sửa / sửa đổi cam kết hơn là tạo một cam kết khác. Tuy nhiên, xem thêm mail-archive.com/dri-devel@lists.sourceforge.net/msg39091.html
Mikko Rantalainen

12

Bạn đã đúng, giả sử bạn chỉ có một kho lưu trữ cục bộ / đã thay đổi. Tuy nhiên, xem xét có một PC cục bộ thứ hai, ví dụ.

Khi bản sao cục bộ / sửa đổi của bạn được đẩy vào một nơi khác, việc đánh lại sẽ làm hỏng các bản sao đó. Tất nhiên, bạn có thể buộc đẩy, nhưng điều đó nhanh chóng trở nên phức tạp. Điều gì xảy ra nếu một hoặc nhiều trong số này có một cam kết hoàn toàn mới?

Như bạn có thể thấy, nó rất tình huống, nhưng chiến lược cơ bản dường như (với tôi) thực tế hơn rất nhiều trong các trường hợp không đặc biệt / hợp tác.


Một điểm khác biệt thứ hai: Chiến lược hợp nhất sẽ giữ một cấu trúc nhất quán và rõ ràng về thời gian. Sau khi nổi loạn, rất có thể các cam kết cũ hơn có thể đi theo những thay đổi mới hơn, làm cho toàn bộ lịch sử và dòng chảy của nó trở nên khó hiểu hơn.


1
"Sau khi nổi loạn, rất có thể các cam kết cũ hơn có thể đi theo những thay đổi mới hơn" - tuy nhiên, điều đó cũng xảy ra với sự hợp nhất, đó là lý do tại sao bạn (có thể) cần biểu đồ đẹp để hiểu ý nghĩa của nó. Thời gian mà một cam kết được thực hiện có thể là rất lâu trước khi hợp nhất đưa nó vào chi nhánh này.
Steve Jessop

6

Lý do lớn có lẽ là hành vi mặc định sẽ "chỉ hoạt động" trong các repos công khai. Lịch sử nổi loạn mà những người khác đã sáp nhập sẽ gây rắc rối cho họ. Tôi biết bạn đang nói về repo riêng của mình, nhưng nói chung git không biết hoặc không quan tâm đến riêng tư hay công khai, vì vậy mặc định được chọn sẽ là mặc định cho cả hai.

Tôi sử dụng git pull --rebasekhá nhiều trong repo riêng của mình, nhưng ngay cả ở đó nó cũng có một nhược điểm tiềm tàng, đó là lịch sử của tôi HEADkhông còn phản ánh cây như tôi thực sự làm việc trên nó.

Vì vậy, đối với một ví dụ lớn, giả sử rằng tôi luôn chạy thử nghiệm và đảm bảo chúng vượt qua trước khi thực hiện cam kết. Điều này có ít liên quan hơn sau khi tôi thực hiện git pull --rebase, bởi vì thực tế không phải là cây ở mỗi cam kết của tôi đã vượt qua các bài kiểm tra. Miễn là các thay đổi không can thiệp theo bất kỳ cách nào và mã tôi kéo đã được kiểm tra, thì có lẽ nó sẽ vượt qua các thử nghiệm, nhưng chúng tôi không biết vì tôi chưa bao giờ thử. Nếu tích hợp liên tục là một phần quan trọng trong quy trình làm việc của bạn, thì bất kỳ loại rebase nào trong một repo đang được CIed đều gặp rắc rối.

Tôi không thực sự bận tâm về điều này, nhưng nó làm phiền một số người: họ thích rằng lịch sử của họ trong git phản ánh mã họ thực sự làm việc (hoặc có lẽ vào thời điểm họ đẩy nó, một phiên bản đơn giản của sự thật sau khi sử dụng của "sửa chữa").

Tôi không biết liệu vấn đề này cụ thể là lý do mà Linus chọn hợp nhất thay vì nổi loạn theo mặc định. Có thể có những bất lợi khác mà tôi chưa gặp phải. Nhưng vì anh ấy không ngại bày tỏ ý kiến ​​của mình bằng mã, tôi khá chắc chắn rằng nó phù hợp với những gì anh ấy nghĩ là một quy trình làm việc phù hợp cho những người không muốn nghĩ về nó quá nhiều (và đặc biệt là những người làm việc ở nơi công cộng hơn là một repo tư nhân). Tránh các đường song song trong biểu đồ đẹp, ủng hộ một đường thẳng sạch sẽ không đại diện cho sự phát triển song song như nó đã xảy ra, có lẽ không phải là ưu tiên hàng đầu của anh ấy mặc dù đó là 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.