2008-12-01 31 views
60

Giả sử rằng tôi muốn hợp nhất từ ​​một nhánh phát hành vào nhánh chính và có một số cam kết trong nhánh phát hành mà tôi không muốn đưa vào nhánh chính. Có cách nào để thực hiện hợp nhất để một hoặc nhiều cam kết đó không được hợp nhất không?Có thể loại trừ các cam kết cụ thể khi thực hiện hợp nhất git không?

Chiến lược của tôi cho đến nay là phải làm như sau (trong tổng thể):

git merge --no-commit release-branch 
# Resolve conflicts and apply reverse patch of the commits that I don't want included 
git commit # Edit commit message so that it lists the commits that have been reverse-patched 

Có cách nào tốt hơn để làm điều này?

+0

Có thể trùng lặp [git - bỏ qua các cam kết cụ thể khi hợp nhất] (https://stackoverflow.com/questions/727994/git-skipping-specific-commits-when-merging) - Tôi biết đó là trẻ hơn, nhưng [ câu trả lời được chấp nhận] (https://stackoverflow.com/a/729723/321973) là IMHO tốt hơn –

Trả lời

41

Tạo chi nhánh mới, xóa lại nhánh tương tác và xóa các cam kết mà bạn không muốn, sau đó hợp nhất.

Bạn không thể thực hiện thay đổi ở giữa nhánh mà không cần phục hồi, nhưng điều đúng sẽ xảy ra khi thấy cùng các thay đổi trong lần hợp nhất sau này (ví dụ: từ việc hái dâu và những gì không phải).

+2

Nhưng điều gì xảy ra khi bạn cố gắng hợp nhất nhánh đó lại? – Evgeny

+4

Với lệnh chính xác nào cần thực hiện? Tôi thấy không có cách nào tôi có thể "thả" các cam kết không mong muốn – Henning

+8

@Henning khi bạn 'git rebase -i other-branch' nó cung cấp cho bạn một trình soạn thảo văn bản với một loạt các cam kết trong đó. Xóa các dòng bạn không muốn. – Dustin

4

Lý do tại sao điều này không thể được thực hiện trực tiếp là mọi cam kết chứa liên kết đến các cam kết gốc (thường chỉ là một nhưng một số để hợp nhất). Bằng cách đó, nếu bạn có một cam kết (bằng tổng số SHA1 của nó) toàn bộ lịch sử cũng được cố định khi cha mẹ cũng chứa liên kết đến cha mẹ của họ và như vậy. Vì vậy, cách duy nhất để loại bỏ các bản vá lỗi trong lịch sử là viết một bản mới. git rebase -i trên nhánh mới được tạo ra có lẽ là cách dễ nhất để đạt được điều đó.

101

Tôi đã tìm thấy giải pháp phù hợp với mình in the Pro Git book.

Giả sử bạn muốn loại trừ tệp config.php.

Mở chi nhánh A:

  1. Tạo một file có tên .gitattributes trong cùng một thư mục, với dòng này: config.php merge=ours. Điều này cho git biết nên sử dụng chiến lược nào khi hợp nhất tệp. Trong trường hợp này, nó luôn giữ phiên bản của bạn, tức là. phiên bản trên nhánh bạn đang hợp nhất.

  2. Thêm tập tin .gitattributes và cam kết

Mở chi nhánh B: lặp lại bước 1-2

Hãy thử sáp nhập ngay bây giờ. Tập tin của bạn nên được giữ nguyên.

+1

Đối với người đọc trong tương lai, công trình này tuyệt vời cho rõ ràng * không * bao gồm các tệp cụ thể. (Trong trường hợp của tôi, tôi đang triển khai các chi nhánh khác nhau cho các máy chủ khác nhau và muốn duy trì kịch bản Capistrano triển khai duy nhất trên từng chi nhánh.) – charliepark

+13

Điều này không có tác dụng đối với tôi vì một số lý do. Tôi đã tạo một nhánh mới với cam kết thay đổi tệp và thêm tệp .gitattributes vào cả hai nhánh. Khi tôi hợp nhất trở lại nhánh ban đầu, dường như nó hoàn toàn bỏ qua dòng trong .gitattributes và kéo vào tệp đã thay đổi bất kể. Có một số thiết lập tôi đang thiếu? – robbles

+6

@robbles bạn có thể bị thiếu: http://stackoverflow.com/a/14099431/6309 – VonC

1

Nếu bạn chỉ muốn loại trừ một số cam kết có lúc kết thúc, bạn chỉ có thể cam kết một cụ thể cam kết số:

git checkout partlyMergedFrom 
git whatchanged 
--> find the commit hash up to where you want to merge 
git checkout partlyMergedInto 
git merge e40a0e384f58409fe3c864c655a8d252b6422bfc 
git whatchanged 
--> check that you really got all the changes you want to have 
2

Nó cũng có thể sửa đổi .git/info/thuộc tính tập tin và giữ nó bên trong thư mục .git thay vì thêm các tệp .gitattribute trên đó sẽ yêu cầu thêm chúng vào kiểm soát nguồn cuối cùng.

12

Nếu bạn có chi nhánh hỗ trợ nơi bạn sửa lỗi và tạo phiên bản mới. Về chủ, bạn có phiên bản tiếp theo, nơi bạn cũng xây dựng các phiên bản mới thường xuyên.

Mỗi khi bạn tạo phiên bản mới, bạn thay đổi phiên bản trong một số tệp, hãy cam kết tệp mới đó, tạo thẻ và đẩy. Giờ đây, việc hợp nhất từ ​​hỗ trợ thành master sẽ luôn có xung đột trong tệp chứa thông tin phiên bản.

Nếu tệp chứa thông tin phiên bản chỉ chứa thông tin phiên bản, bạn có thể đi với câu trả lời của fcurella. Nhưng nếu nó thực sự cũng có thể chứa thông tin hợp nhất (pom.xml, gradle.properties, MANIFEST.MF, ...), bạn phải thực hiện thêm một số hành động.

Cho phép sử dụng các ví dụ sau

 C---D*---E---F* support 
    /
A---B---G---H*---I master 

nơi cam kết với các ngôi sao chỉ chứa các thay đổi do sự thay đổi phiên bản đó nên bỏ qua trong quá trình hợp nhất.

Để nhập hỗ trợ vào chủ mà không merge-mâu thuẫn do phiên bản xây dựng, bạn có thể làm một trong hai điều sau đây:

Nhiều merge cam

git checkout master 
git merge C 
git merge D -s ours 
git merge E 
git merge F -s ours 

Với lập luận -s ours chúng tôi đang nói git chỉ ghi lại một hợp nhất mà không thay đổi không gian làm việc. Điều này có thể so sánh được to the --record-only option of svn.

trên sẽ dẫn đến việc bố trí sau

 -------------C---D*---E---F* support 
    /   \ \ \ \ 
A---B---G---H*---I---J---K----L---M master 

Một hợp nhất cam kết sử dụng cherry-chọn

git checkout master 
git merge support -s ours --no-commit 
git cherry-pick C E --no-commit 
git commit -m 'merged support into master' 

đầu tiên chúng tôi đang bắt đầu một hợp nhất nhưng chỉ ghi lại rằng chúng ta đang sáp nhập, mà không thay đổi không gian làm việc và không thực hiện cam kết hợp nhất. Sau đó, chúng tôi sẽ chọn các cam kết hợp nhất, một lần nữa mà không cần cam kết. Cuối cùng, chúng tôi cam kết hợp nhất.

trên sẽ dẫn đến việc bố trí sau

 C---D*---E---F* support 
    /   \ 
A---B---G---H*---I---J master 

Một thậm chí có thể tự động hóa việc cherry-hái.

git checkout master 
git merge support -s ours --no-commit 
for id in `git log support --reverse --not HEAD --format="%H [%an] %s" | 
    grep -v "bump version" | 
    sed "s/\(\w*\)\s.*/\1/g"` 
do 
    git cherry-pick --no-commit $id 
done 
git commit -m 'merged support into master' 
+0

Bất kỳ ví dụ nào để tự động hóa nhiều cam kết hợp nhất? – Santos

2

Câu hỏi chính là: bạn muốn thể hiện cam kết bạn muốn bỏ qua như thế nào?

  1. lén lút ẩn chúng (không phải tôi yêu thích)
  2. dứt khoát bỏ qua chúng
  3. rõ ràng đánh bại được họ

Đáng tiếc là không có. 2 là không thể diễn tả trong biểu đồ lịch sử.

Số 1 là có thể, nhưng tôi sẽ không bao giờ làm điều đó: cam kết hợp nhất có thể chứa thay đổi. - Thông thường, một cam kết hợp nhất chỉ vào kết quả của việc hợp nhất hai chi nhánh nữa: tất cả mọi thứ được phát triển trong các nhánh đó phải ở trong mã sau khi hợp nhất (tức là trong mã được chỉ định bởi cam kết hợp nhất). Và không có gì khác nên được trong cam kết này.

Nhưng ngạc nhiên, ngạc nhiên, bạn có thể thay đổi toàn bộ cơ sở mã và biểu thị nó dưới dạng hợp nhất.Hiệu ứng của quá trình hợp nhất là hai lần: nó hợp nhất cây lịch sử nên hợp nhất hai cơ sở mã. Trước đây nó chắc chắn (nếu không có ai gọi nó là một hợp nhất), sau này nó có thể thất bại, ví dụ: khi xung đột hợp nhất phát sinh và nó đã được giải quyết sai (sau đó các cơ sở mã không được hợp nhất đúng cách).

Một số câu trả lời khác đề xuất ẩn này. Tôi đề nghị cách rõ ràng: hợp nhất cộng với các cam kết hoàn nguyên.

+0

Đây là một chiến lược tuyệt vời cho các nhánh ngắn ngủi. Vấn đề với chiến lược này là khi bạn hợp nhất nhánh được hợp nhất chính xác của bạn (nhánh có hoàn nguyên) trở lại nhánh đang hoạt động, nhánh đang hoạt động cũng sẽ nhận được hoàn nguyên vì đó là cam kết thông thường, chính hãng. Nếu bạn có trường hợp nhánh làm việc thực sự không có cam kết, bạn sẽ phải hoàn nguyên việc hoàn nguyên. Điều này sẽ tiếp tục miễn là chi nhánh làm việc cụ thể đang được sử dụng. –

+0

@RonWertlen Bạn có quyền với tuyên bố rằng chủ không thể được sáp nhập lại vào nhánh "nhánh làm việc"/chi nhánh phát hành đó mà không giới thiệu hiệu ứng của các reverts. - Nhưng điều này không đúng đối với chiến lược được đề xuất 3 của tôi về câu trả lời của tôi, mà còn cho chiến lược 1. - Đây cũng là một lý do tại sao cá nhân tôi không theo đuổi quy trình làm việc từ câu hỏi của OP. –

+0

Tôi đồng ý với bạn. 1 và 2 là luồng công việc chống. Nếu bạn có các chi nhánh lâu đời và muốn giữ vĩnh viễn các cam kết trong một và ở bên kia, đã đến lúc bắt đầu suy nghĩ về việc tái cơ cấu dự án của bạn và sử dụng các mô-đun con (với node.js, bạn cũng có nút_modules như một cơ chế song song để đạt được điều tương tự). –

Các vấn đề liên quan