Làm thế nào tôi có thể xem trước một hợp nhất trong git?


397

Tôi có một nhánh git (ví dụ đường chính) và tôi muốn hợp nhất trong một nhánh phát triển khác. Hay là tôi?

Để quyết định xem tôi có thực sự muốn hợp nhất chi nhánh này hay không, tôi muốn xem một số loại xem trước về việc hợp nhất sẽ làm gì. Tốt nhất là với khả năng xem danh sách các cam kết đang được áp dụng.

Cho đến nay, điều tốt nhất tôi có thể nghĩ ra là merge --no-ff --no-commit, và sau đó diff HEAD.


17
Tôi chỉ git mergegit reset --keep HEAD@{1}nếu tôi không thích kết quả.
Jan Hudec

3
Lưu ý rằng việc xem danh sách các cam kết với diff của chúng không nhất thiết phải kể toàn bộ câu chuyện - nếu việc hợp nhất là không tầm thường và đặc biệt là nếu có xung đột, kết quả thực tế của việc hợp nhất có thể hơi thú vị.
Cascabel

2
Phương pháp ban đầu của bạn làm chính xác điều đó. Quan điểm của tôi là mặc dù nhìn vào các khác biệt đều tốt và tốt, nhưng nếu bạn có một sự hợp nhất phức tạp, bạn có thể sẽ có kết quả đáng ngạc nhiên ngay cả khi tất cả các cam kết được hợp nhất là tốt độc lập.
Cascabel

2
@Jan: Vì một số lý do, git reset --keep HEAD@{1}trả lại fatal: Cannot do a keep reset in the middle of a merge.Trợ giúp?
moey

3
Tại sao không có --previewtùy chọn trong git-merge?
Gaui

Câu trả lời:


285

Tôi thấy rằng giải pháp tốt nhất cho tôi là chỉ thực hiện hợp nhất và hủy bỏ nó nếu có xung đột . Cú pháp đặc biệt này cảm thấy sạch sẽ và đơn giản với tôi. Đây là Chiến lược 2 dưới đây.

Tuy nhiên, nếu bạn muốn đảm bảo rằng bạn không làm xáo trộn chi nhánh hiện tại của mình hoặc bạn chưa sẵn sàng hợp nhất bất kể sự tồn tại của xung đột, chỉ cần tạo một nhánh con mới từ chi nhánh đó và hợp nhất:

Chiến lược 1: Cách an toàn - hợp nhất một chi nhánh tạm thời:

git checkout mybranch
git checkout -b mynew-temporary-branch
git merge some-other-branch

Bằng cách đó, bạn có thể chỉ cần vứt bỏ nhánh tạm thời nếu bạn chỉ muốn xem những xung đột là gì. Bạn không cần phải "hủy bỏ" việc hợp nhất và bạn có thể quay lại công việc của mình - chỉ cần kiểm tra lại 'mybranch' và bạn sẽ không có bất kỳ mã hợp nhất hoặc hợp nhất nào trong chi nhánh của mình.

Điều này về cơ bản là chạy khô.

Chiến lược 2: Khi bạn chắc chắn muốn hợp nhất, nhưng chỉ khi không có xung đột

git checkout mybranch
git merge some-other-branch

Nếu git báo cáo xung đột (và CHỈ NẾU CÓ xung đột), bạn có thể thực hiện:

git merge --abort

Nếu hợp nhất thành công, bạn không thể hủy bỏ nó (chỉ đặt lại).

Nếu bạn chưa sẵn sàng để hợp nhất, hãy sử dụng cách an toàn hơn ở trên.

[EDIT: 2016-Nov - Tôi đã hoán đổi chiến lược 1 cho 2, vì dường như hầu hết mọi người đang tìm kiếm "cách an toàn". Chiến lược 2 bây giờ có nhiều lưu ý rằng bạn chỉ có thể hủy bỏ hợp nhất nếu hợp nhất có xung đột mà bạn chưa sẵn sàng để giải quyết. Hãy ghi nhớ nếu đọc bình luận!]


2
+1 cho chiến lược 2. Chi nhánh tạm thời hiển thị chính xác những gì sẽ đi vào khi hợp nhất. Chiến lược 1 là những gì tôi đang cố gắng tránh cho trường hợp cụ thể này.
Gordolio

2
Tôi đề nghị thay đổi các chiến lược xung quanh để đầu tiên an toàn hơn (đào tạo tâm lý của tôi sắp diễn ra - hầu hết mọi người sẽ cho rằng lựa chọn tốt nhất sẽ là lựa chọn đầu tiên, mặc dù sử dụng rõ ràng từ "an toàn hơn"), nhưng, ngoài điều đó, tuyệt vời việc làm.
paxdiablo

6
Bạn có thể làm git merge --no-ff --no-commitnếu bạn không muốn thực hiện các thay đổi trực tiếp. Điều này giúp loại bỏ "nhu cầu" cho một nhánh khác giúp việc xem xét các thay đổi trở nên dễ dàng hơn một chút.
Gerard van Helden

và nếu bạn quyết định bạn không muốn hợp nhất chút nào và thực tế sẽ viết thêm một số mã và sau đó cam kết với chi nhánh của bạn để bạn có thể triển khai CHỈ chi nhánh của mình trên máy chủ thử nghiệm, bạn vẫn phải hoàn nguyên git merge --no-ff --no-commitchứ? Tôi đoán bạn vẫn có thể làm git merge --abortsau đó nếu bạn không thích những gì bạn thấy? Ngay cả khi hợp nhất không tạo ra xung đột?
Kasapo

Hầu hết mọi người thích sao chép và dán và không suy nghĩ quá nhiều. Do đó, đối với Chiến lược 1, có lẽ cũng thêm cách hủy bỏ hợp nhất trong nhánh cục bộ tạm thời git reset --hard HEADvà sau đó kiểm tra một nhánh khác git checkout <different branch name>và xóa nhánh tạm thời git delete -b <name of temporary branch>.
dùng3613932

401
  • git log ..otherbranch
    • danh sách các thay đổi sẽ được sáp nhập vào chi nhánh hiện tại.
  • git diff ...otherbranch
    • khác với tổ tiên chung (cơ sở hợp nhất) đến đầu của những gì sẽ được hợp nhất. Lưu ý ba dấu chấm , có ý nghĩa đặc biệt so với hai dấu chấm (xem bên dưới).
  • gitk ...otherbranch
    • đại diện đồ họa của các chi nhánh kể từ khi chúng được sáp nhập thời gian qua.

Chuỗi rỗng ngụ ý HEAD, vì vậy đó là lý do tại sao chỉ ..otherbranchthay vì HEAD..otherbranch.

Hai so với ba dấu chấm có ý nghĩa khác nhau đối với diff so với các lệnh liệt kê các sửa đổi (log, gitk, v.v.). Đối với nhật ký và những người khác, hai dấu chấm ( a..b) có nghĩa là tất cả mọi thứ nằm trong bnhưng không avà ba dấu chấm ( a...b) có nghĩa là tất cả mọi thứ chỉ trong một ahoặc b. Nhưng diff hoạt động với hai phiên bản và ở đó trường hợp đơn giản hơn được biểu thị bằng hai dấu chấm ( a..b) là sự khác biệt đơn giản từ ađến bvà ba dấu chấm ( a...b) có nghĩa là sự khác biệt giữa tổ tiên chung và b( git diff $(git merge-base a b)..b).


7
Dấu chấm thứ ba là phần tôi bị thiếu, cảm ơn! Cách tiếp cận log cũng hoạt động tốt, log -p --reverse ..therbranch có vẻ như là một cách tốt để xem những gì sẽ được hợp nhất.
Glenjamin

1
Tôi đã mất tích git checkout mastertrước khi tôi thử điều này. Tôi đã tự hỏi tại sao nó lại nói rằng tất cả những thay đổi của tôi sẽ được viết quá mức ...
Droogans

5
git show ..otherbranchsẽ hiển thị một danh sách các thay đổi và khác biệt sẽ được sáp nhập vào chi nhánh hiện tại.
Gaui

4
Điều này không hoàn toàn chính xác, đặc biệt là đối với những quả anh đào.
void.pulum

2
@ void.pulum, git không đối xử đặc biệt với cherry-picks trong hợp nhất thông thường nên nó cũng không ở đây. Một chiến lược hợp nhất có thể được viết ra, nhưng theo tôi biết, nó không bao giờ được như vậy.
Jan Hudec

19

Nếu bạn giống tôi, bạn đang tìm kiếm tương đương svn update -n. Sau đây xuất hiện để làm các thủ thuật. Lưu ý rằng hãy đảm bảo thực hiện git fetchtrước để repo cục bộ của bạn có các bản cập nhật phù hợp để so sánh với.

$ git fetch origin
$ git diff --name-status origin/master
D       TableAudit/Step0_DeleteOldFiles.sh
D       TableAudit/Step1_PopulateRawTableList.sh
A       manbuild/staff_companies.sql
M       update-all-slave-dbs.sh

hoặc nếu bạn muốn tìm khác biệt từ đầu đến điều khiển từ xa:

$ git fetch origin
$ git diff origin/master

IMO giải pháp này dễ dàng hơn và ít xảy ra lỗi hơn (và do đó ít rủi ro hơn nhiều) so với giải pháp hàng đầu đề xuất "hợp nhất sau đó hủy bỏ".


1
nên $ git checkout target-branchvà sau đó $ git diff --name-status ...branch-to-be-merged(ba dấu chấm là rất cần thiết vì vậy hãy nhập chúng như vậy)
Lu55

Một điều còn thiếu: nó không cho bạn thấy các tệp nào sẽ có xung đột - chúng có cùng dấu "M" như các tệp đã được sửa đổi trên nhánh nhưng có thể được hợp nhất mà không có xung đột.
peterflynn

Có thể mọi thứ đã khác trong năm 2012, nhưng những ngày này, việc hủy bỏ hợp nhất có vẻ khá đáng tin cậy, vì vậy tôi không nghĩ rằng thật công bằng khi mô tả điều này là "dễ dàng hơn và ít bị lỗi hơn" ngay bây giờ.
David Z

8

Hầu hết các câu trả lời ở đây đều yêu cầu một thư mục hoạt động sạch sẽ và nhiều bước tương tác (không tốt cho kịch bản) hoặc không hoạt động cho tất cả các trường hợp, ví dụ: các phép hợp nhất trong quá khứ đã mang lại một số thay đổi nổi bật vào nhánh mục tiêu của bạn hoặc chọn cherry tương tự.

Để thực sự thấy những gì sẽ thay đổi trong masterchi nhánh nếu bạn sáp nhập developvào nó, ngay bây giờ:

git merge-tree $(git merge-base master develop) master develop

Vì nó là một lệnh hệ thống ống nước, nó không đoán được ý của bạn, bạn phải rõ ràng. Nó cũng không tô màu đầu ra hoặc sử dụng máy nhắn tin của bạn, vì vậy lệnh đầy đủ sẽ là:

git merge-tree $(git merge-base master develop) master develop | colordiff | less -R

- https://git.seveas.net/previewing-a-merge-result.html

(cảm ơn David Normington cho liên kết)

Tái bút

Nếu bạn nhận được xung đột hợp nhất, chúng sẽ hiển thị với các dấu xung đột thông thường trong đầu ra, ví dụ:

$ git merge-tree $(git merge-base a b ) a b 
added in both
  our    100644 78981922613b2afb6025042ff6bd878ac1994e85 a
  their  100644 61780798228d17af2d34fce4cfbdf35556832472 a
@@ -1 +1,5 @@
+<<<<<<< .our
 a
+=======
+b
+>>>>>>> .their

Người dùng @dreftymac đưa ra một quan điểm tốt: điều này làm cho nó không phù hợp với kịch bản, bởi vì bạn không thể dễ dàng nắm bắt được điều đó từ mã trạng thái. Các điểm đánh dấu xung đột có thể khá khác nhau tùy thuộc vào hoàn cảnh (bị xóa so với sửa đổi, v.v.), điều này cũng gây khó khăn cho grep. Coi chừng.


1
@hraban Đây có vẻ là câu trả lời đúng, tuy nhiên rõ ràng vẫn còn một yếu tố còn thiếu. Cách tiếp cận này yêu cầu người dùng "nhãn cầu" đầu ra để xem liệu các dấu hiệu xung đột có mặt hay không. Bạn có cách tiếp cận nào đơn giản là trả về truenếu có xung đột và falsenếu không có xung đột (ví dụ: giá trị boolean không yêu cầu kiểm tra "nhãn cầu" hoặc bất kỳ sự can thiệp nào của con người).
dreftymac

1
@dreftymac không thể tìm thấy bất cứ điều gì cho hiệu ứng đó. bạn có thể sử dụng một cái gì đó như git merge-tree ... | grep -q '^[a-z].*in both$' && echo conflict || echo safe to mergenhưng nó rất khó; Có lẽ tôi đang quên một trường hợp. có lẽ bạn muốn kiểm tra các dấu hiệu xung đột, thay vào đó? ví dụ: điều này có thể không bắt được "xung đột kiểu của họ, chúng ta đã thay đổi". (Tôi vừa kiểm tra và thậm chí không hiển thị các dấu xung đột, vì vậy bạn cần có một biểu thức tỉ mỉ để được an toàn ở đây)
hraban

1
Sử dụng less -Rđể xử lý đầu ra màu mà không sửa đổi cấu hình của bạn.
Giacomo Alzetta

Cảm ơn @GiacomoAlzetta, tôi đã cập nhật nó.
hraban

6

Nếu bạn đã tìm nạp các thay đổi, yêu thích của tôi là:

git log ...@{u}

Điều đó cần git 1.7.x tôi tin rằng mặc dù. Các @{u}ký hiệu là "viết tắt" cho các chi nhánh thượng nguồn do đó, nó một chút linh hoạt hơn git log ...origin/master.

Lưu ý: Nếu bạn sử dụng zsh và điều ảm đạm mở rộng trên, bạn có thể phải làm một cái gì đó như:

git log ...@\{u\}

6

Thêm vào các câu trả lời hiện có, một bí danh có thể được tạo để hiển thị khác và / hoặc nhật ký trước khi hợp nhất. Nhiều câu trả lời bỏ qua fetchphải được thực hiện trước khi "xem trước" hợp nhất; đây là một bí danh kết hợp hai bước này thành một (mô phỏng một cái gì đó tương tự như của mercurial's hg incoming/ outgoing)

Vì vậy, dựa trên " git log ..otherbranch", bạn có thể thêm các mục sau vào ~/.gitconfig:

...
[alias]
    # fetch and show what would be merged (use option "-p" to see patch)
    incoming = "!git remote update -p; git log ..@{u}"

Đối với đối xứng, các bí danh sau có thể được sử dụng để hiển thị những gì đã cam kết và sẽ được đẩy, trước khi đẩy:

    # what would be pushed (currently committed)
    outgoing = log @{u}..

Và sau đó, bạn có thể chạy " git incoming" để hiển thị nhiều thay đổi hoặc " git incoming -p" để hiển thị bản vá (nghĩa là "diff"), " git incoming --pretty=oneline", để tóm tắt ngắn gọn, v.v. Sau đó, bạn có thể (tùy chọn) chạy " git pull" để thực sự hợp nhất. (Mặc dù, vì bạn đã tìm nạp, việc hợp nhất có thể được thực hiện trực tiếp.)

Tương tự như vậy, " git outgoing" hiển thị những gì sẽ được đẩy nếu bạn chạy " git push".


3

git log currentbranch..otherbranchsẽ cung cấp cho bạn danh sách các cam kết sẽ đi vào chi nhánh hiện tại nếu bạn thực hiện hợp nhất. Các đối số thông thường để đăng nhập cung cấp chi tiết về các cam kết sẽ cung cấp cho bạn thêm thông tin.

git diff currentbranch otherbranchsẽ cung cấp cho bạn sự khác biệt giữa hai cam kết sẽ trở thành một. Đây sẽ là một khác biệt cung cấp cho bạn mọi thứ sẽ được hợp nhất.

Những điều này sẽ giúp đỡ?


2
Thật ra, sai rồi. git log otherbranch..currentbranchđưa ra danh sách các cam kết trên currentbranch . Việc git diff otherbranch currentbranchcung cấp cho bạn khác biệt từ phiên bản sắp hợp nhất với mẹo hiện tại, điều này gần như vô dụng, bởi vì những gì bạn muốn khác với cơ sở hợp nhất với đầu hợp nhất.
Jan Hudec

Cảm ơn. Tôi đã chuyển tên của những cái cây.
Noufal Ibrahim

3

Yêu cầu kéo - Tôi đã sử dụng hầu hết các ý tưởng đã gửi nhưng một ý tưởng mà tôi cũng thường sử dụng là (đặc biệt là từ một nhà phát triển khác) thực hiện Yêu cầu kéo cung cấp một cách thuận tiện để xem xét tất cả các thay đổi trong hợp nhất trước khi thực hiện địa điểm. Tôi biết đó là GitHub không phải git nhưng nó chắc chắn là tiện dụng.


2

Nói ngắn gọn về việc thực hiện hợp nhất theo kiểu vứt đi (xem câu trả lời của Kasapo), dường như không có cách nào đáng tin cậy để thấy điều này.

Phải nói rằng, đây là một phương pháp rất gần:

git log TARGET_BRANCH...SOURCE_BRANCH --cherry

Điều này đưa ra một dấu hiệu công bằng về việc cam kết nào sẽ đưa nó vào hợp nhất. Để xem khác biệt, thêm -p. Để xem tên tập tin, thêm bất kỳ --raw, --stat, --name-only, --name-status.

Vấn đề với git diff TARGET_BRANCH...SOURCE_BRANCHcách tiếp cận (xem câu trả lời của Jan Hudec) là, bạn sẽ thấy các khác biệt cho các thay đổi đã có trong nhánh mục tiêu của mình nếu nhánh nguồn của bạn chứa các kết hợp chéo.


1

Có lẽ điều này có thể giúp bạn? git-diff-tree - So sánh nội dung và chế độ của các đốm được tìm thấy thông qua hai đối tượng cây


1

Tôi không muốn sử dụng lệnh git merge làm tiền thân để xem lại các tệp xung đột. Tôi không muốn thực hiện hợp nhất, tôi muốn xác định các vấn đề tiềm ẩn trước khi hợp nhất - các vấn đề tự động hợp nhất có thể ẩn khỏi tôi. Giải pháp tôi đã tìm kiếm là làm thế nào để git nhổ ra một danh sách các tệp đã được thay đổi trong cả hai nhánh sẽ được hợp nhất với nhau trong tương lai, liên quan đến một số tổ tiên chung. Khi tôi có danh sách đó, tôi có thể sử dụng các công cụ so sánh tệp khác để tìm hiểu thêm. Tôi đã tìm kiếm nhiều lần và tôi vẫn không tìm thấy những gì tôi muốn trong một lệnh git riêng.

Đây là cách giải quyết của tôi, trong trường hợp nó giúp được bất kỳ ai khác ngoài đó:

Trong kịch bản này, tôi có một chi nhánh gọi là QA có nhiều thay đổi trong đó kể từ lần phát hành sản xuất cuối cùng. Bản phát hành sản xuất cuối cùng của chúng tôi được gắn thẻ "15.20.1". Tôi có một nhánh phát triển khác gọi là new_ ware mà tôi muốn hợp nhất vào nhánh QA. Cả QA và new_ ware đều cam kết "theo dõi" (theo báo cáo của gitk) thẻ 15.20.1.

git checkout QA
git pull
git diff 15.20.1 --name-only > QA_files
git checkout new_stuff
git pull
git diff 15.20.1 --name-only > new_stuff_files
comm -12 QA_files new_stuff_files

Dưới đây là một số cuộc thảo luận về lý do tại sao tôi quan tâm đến việc nhắm mục tiêu các tệp cụ thể này:

Làm cách nào tôi có thể tin tưởng hợp nhất Git?

/software/199780/how-far-do-you-trust-automerge

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.