Git hợp nhất với lực ghi đè


101

Tôi có một nhánh được gọi là nhánh demomà tôi cần hợp nhất với masternhánh. Tôi có thể nhận được kết quả mong muốn bằng các lệnh sau:

git pull origin demo
git checkout master
git pull origin master
git merge demo
git push origin master

Mối quan tâm duy nhất của tôi là, nếu có bất kỳ vấn đề hợp nhất nào , tôi muốn yêu gitcầu ghi đè các thay đổi trong masternhánh mà không đưa ra lời nhắc hợp nhất. Vì vậy, về cơ bản các thay đổi trong demonhánh sẽ tự động ghi đè các thay đổi trong masternhánh.

Tôi đã xem xét xung quanh có nhiều lựa chọn nhưng tôi không muốn mất cơ hội với việc hợp nhất.


git push -f origin master
MD XF

4
@MDXF: Có thể tôi sai nhưng tôi không nên sử dụng -ftùy chọn với mergelệnh chứ không phải với pushlệnh
OpenStack

Bạn có thể thử cả hai và xem những gì làm việc cho bạn
MD XF

Xem dưới đây liên kết cho một giải pháp vũ lực đè: stackoverflow.com/a/42454737/984471
Manohar Reddy Poreddy

Câu trả lời:


102

Không thực sự liên quan đến câu trả lời này, nhưng tôi muốn bỏ qua git pull, chỉ chạy git fetchtheo sau git merge. Bạn đang thực hiện ba hợp nhất, điều này sẽ làm cho Git của bạn chạy ba hoạt động tìm nạp, khi một lần tìm nạp là tất cả những gì bạn cần. Vì thế:

git fetch origin   # update all our origin/* remote-tracking branches

git checkout demo         # if needed -- your example assumes you're on it
git merge origin/demo     # if needed -- see below

git checkout master
git merge origin/master

git merge -X theirs demo   # but see below

git push origin master     # again, see below

Kiểm soát việc hợp nhất khó nhất

Phần thú vị nhất ở đây là git merge -X theirs. Như root545 đã lưu ý , các -Xtùy chọn được chuyển cho chiến lược hợp nhất và cả hai tùy chọn mặc địnhrecursive chiến lược và resolvechiến lược thay thế đều có -X ourshoặc -X theirs(một hoặc khác, nhưng không phải cả hai). Tuy nhiên, để hiểu những gì họ làm, bạn cần biết cách Git tìm và xử lý, hợp nhất các xung đột .

Xung đột hợp nhất có thể xảy ra trong một số tệp 1 khi phiên bản cơ sở khác với cả phiên bản hiện tại (còn gọi là cục bộ, HEAD hoặc --ours) phiên bản khác (còn được gọi là từ xa hoặc --theirs) của cùng một tệp đó. Có nghĩa là, hợp nhất đã xác định ba bản sửa đổi (ba cam kết): cơ sở, của chúng tôi và của họ. Phiên bản "cơ sở" là từ cơ sở hợp nhất giữa cam kết của chúng tôi và cam kết của họ, như được tìm thấy trong biểu đồ cam kết (để biết thêm về điều này, hãy xem các bài đăng khác của StackOverflow). Git sau đó đã tìm thấy hai tập hợp thay đổi: "những gì chúng tôi đã làm" và "những gì họ đã làm". Những thay đổi này (nói chung) được tìm thấy trên từng dòng, hoàn toàn là văn bảnnền tảng. Git không có hiểu biết thực sự về nội dung tệp; nó chỉ đơn thuần là so sánh từng dòng văn bản.

Những thay đổi này là những gì bạn thấy trong git diffđầu ra và như mọi khi, chúng cũng có ngữ cảnh . Có thể những thứ chúng tôi đã thay đổi nằm trên những dòng khác với những thứ chúng đã thay đổi, vì vậy những thay đổi có vẻ như chúng sẽ không xảy ra xung đột, nhưng bối cảnh cũng đã thay đổi (ví dụ: do thay đổi của chúng tôi ở gần đầu hoặc cuối tệp, để tệp hết trong phiên bản của chúng tôi, nhưng trong phiên bản của họ, họ cũng đã thêm nhiều văn bản hơn ở đầu hoặc cuối).

Nếu những thay đổi xảy ra trên khác nhau dòng-ví dụ, chúng ta thay đổi colorđể colourtrên dòng 17 và họ thay đổi fredđể barneytrên đường dây 71 thì không có mâu thuẫn: Git chỉ đơn giản là mất cả hai thay đổi. Nếu những thay đổi xảy ra trên cùng một dòng, nhưng là những thay đổi giống hệt nhau , Git sẽ lấy một bản sao của thay đổi. Chỉ khi các thay đổi nằm trên cùng một dòng, nhưng là các thay đổi khác nhau hoặc trường hợp đặc biệt của ngữ cảnh gây nhiễu, bạn mới nhận được xung đột sửa đổi / sửa đổi.

Các tùy chọn -X ours-X theirstùy chọn cho Git biết cách giải quyết xung đột này, chỉ bằng cách chọn một trong hai thay đổi: của chúng tôi hoặc của chúng. Vì bạn đã nói rằng bạn đang hợp nhất demo(của họ) vàomaster (của chúng tôi) và muốn các thay đổi từ đó demo, bạn sẽ muốn -X theirs.

-XTuy nhiên, áp dụng một cách mù quáng rất nguy hiểm. Chỉ vì những thay đổi của chúng tôi không xung đột trên cơ sở từng dòng một không có nghĩa là những thay đổi của chúng tôi không thực sự xung đột! Một ví dụ cổ điển xảy ra trong các ngôn ngữ có khai báo biến. Phiên bản cơ sở có thể khai báo một biến không sử dụng:

int i;

Trong phiên bản của chúng tôi, chúng tôi xóa biến không sử dụng để biến cảnh báo trình biên dịch biến mất — và trong phiên bản của chúng , chúng thêm một vòng lặp vào một số dòng sau đó, sử dụng ilàm bộ đếm vòng lặp. Nếu chúng tôi kết hợp hai thay đổi, mã kết quả không còn được biên dịch nữa. Các-X tùy chọn là không có sự giúp đỡ ở đây từ những thay đổi về dòng khác nhau .

Nếu bạn có một bộ thử nghiệm tự động, điều quan trọng nhất cần làm là chạy các thử nghiệm sau khi hợp nhất. Bạn có thể thực hiện việc này sau khi cam kết và sửa chữa mọi thứ sau nếu cần; hoặc bạn có thể làm điều đó trước khi cam kết, bằng cách thêm --no-commitvào git mergelệnh. Chúng tôi sẽ để lại chi tiết cho tất cả những điều này cho các bài đăng khác.


1 Bạn cũng có thể gặp xung đột liên quan đến các hoạt động "trên toàn tệp", ví dụ: có lẽ chúng tôi sửa lỗi chính tả của một từ trong tệp (để chúng tôi có sự thay đổi) và chúng sẽ xóa toàn bộ tệp (để chúng có xóa bỏ). Git sẽ không tự giải quyết những xung đột này, bất kể các -Xđối số.


Thực hiện ít hợp nhất hơn và / hoặc hợp nhất thông minh hơn và / hoặc sử dụng rebase

Có ba hợp nhất trong cả hai chuỗi lệnh của chúng tôi. Đầu tiên là đưa origin/demovào local demo(việc sử dụng của bạn git pull, nếu Git của bạn rất cũ, sẽ không cập nhật được origin/demonhưng sẽ tạo ra kết quả cuối cùng tương tự). Thứ hai là đưa origin/mastervàomaster .

Tôi không rõ ai đang cập nhật demovà / hoặc master. Nếu bạn viết mã của riêng mình trên demonhánh của riêng bạn , những người khác đang viết mã và đẩy nó đến demonhánh trên origin, thì quá trình hợp nhất bước đầu tiên này có thể có xung đột hoặc tạo ra sự hợp nhất thực sự. Thường xuyên hơn không, tốt hơn là sử dụng rebase, thay vì hợp nhất, để kết hợp công việc (phải thừa nhận rằng đây là vấn đề của sở thích và quan điểm). Nếu vậy, bạn có thể muốn sử dụng git rebasethay thế. Mặt khác, nếu bạn không bao giờ thực hiện bất kỳ cam kết nào của riêng mình demo, bạn thậm chí không thực hiện : điều này sẽ chuyển tiếp nhanh nếu có thể và hoàn toàn thất bại nếu không (tại thời điểm đó, bạn có thể kiểm tra hai tập hợp thay đổi, và chọn một hợp nhất thực hoặc một cơ sở lại nếu thích hợp). cần một demochi nhánh. Ngoài ra, nếu bạn muốn tự động hóa nhiều việc này, nhưng có thể kiểm tra cẩn thận khi có cam kết mà cả bạn và những người khác, thực hiện, bạn có thể muốn sử dụnggit merge --ff-only origin/demodemo để khớp với cập nhậtorigin/demo

Logic này cũng áp dụng master, mặc dù bạn đang làm việc hợp nhất trên master , vì vậy bạn chắc chắn cần một master. Tuy nhiên, thậm chí còn có khả năng bạn muốn hợp nhất không thành công nếu không thể thực hiện được dưới dạng không hợp nhất tua nhanh, vì vậy điều này có lẽ cũng nên xảy ra git merge --ff-only origin/master.

Hãy nói rằng bạn không bao giờ thực hiện các cam kết của riêng mình demo. Trong trường hợp này, chúng ta có thể bỏ tên demohoàn toàn:

git fetch origin   # update origin/*

git checkout master
git merge --ff-only origin/master || die "cannot fast-forward our master"

git merge -X theirs origin/demo || die "complex merge conflict"

git push origin master

Nếu bạn đang thực demohiện cam kết chi nhánh của riêng mình , điều này không hữu ích; bạn cũng có thể giữ hợp nhất hiện có (nhưng có thể thêm --ff-onlytùy thuộc vào hành vi bạn muốn) hoặc chuyển nó sang thực hiện một cơ sở lại. Lưu ý rằng cả ba phương pháp đều có thể không thành công: hợp nhất có thể không thành công khi có xung đột, hợp nhất với --ff-onlycó thể không tua đi nhanh và rebase có thể thất bại khi có xung đột (về bản chất, rebase hoạt động bằng các cam kết chọn cherry , sử dụng hợp nhất máy móc và do đó có thể xảy ra xung đột hợp nhất).


21

Tôi đã gặp sự cố tương tự, nơi tôi cần thay thế hiệu quả bất kỳ tệp nào có thay đổi / xung đột với một nhánh khác.

Giải pháp tôi tìm thấy là sử dụng git merge -s ours branch.

Lưu ý rằng tùy chọn có -svà không -X. -sbiểu thị việc sử dụng ourslàm chiến lược hợp nhất cấp cao nhất, -Xsẽ áp dụng ourstùy chọn cho recursivechiến lược hợp nhất, đây không phải là điều tôi (hoặc chúng tôi) muốn trong trường hợp này.

Các bước, đâu oldbranchlà nhánh bạn muốn ghi đè newbranch.

  • git checkout newbranch kiểm tra chi nhánh bạn muốn giữ lại
  • git merge -s ours oldbranch hợp nhất trong nhánh cũ, nhưng vẫn giữ tất cả các tệp của chúng tôi.
  • git checkout oldbranch kiểm tra nhánh mà bạn muốn ghi đè
  • get merge newbranch hợp nhất trong nhánh mới, ghi đè lên nhánh cũ

Lưu ý: không có giải pháp nào khác ở đây phù hợp với tôi, do đó tôi đăng câu trả lời của mình.
Niall Mccormack, 09/07/19

1
Nó không hiệu quả với tôi. Nó đã giải quyết được xung đột (đã giải quyết các tệp bị xung đột) nhưng tệp không được hợp nhất. Và không thể hợp nhất cả hai.
c-an

Nếu có ai đó gặp khó khăn khi bạn được nhắc "Vui lòng nhập thông báo cam kết để giải thích lý do tại sao việc hợp nhất này là cần thiết": Nhập thông báo của bạn, sau đó nhấn phím ESC trên bàn phím của bạn, nhập: wq và nhấn ENTER để thoát khỏi lời nhắc.
topherPedersen

19

Cách tiếp cận hợp nhất này sẽ thêm một cam kết lên trên mastermà dán bất kỳ thứ gì có trong đó feature, mà không phàn nàn về các xung đột hoặc những thứ tào lao khác.

nhập mô tả hình ảnh ở đây

Trước khi bạn chạm vào bất cứ thứ gì

git stash
git status # if anything shows up here, move it to your desktop

Bây giờ chuẩn bị chủ

git checkout master
git pull # if there is a problem in this step, it is outside the scope of this answer

Mặc featurequần áo

git checkout feature
git merge --strategy=ours master

Đi giết người

git checkout master
git merge --no-ff feature

1
git push để kết thúc
Kochchy

git-scm.com/docs/git-merge#Documentation/git-merge.txt-ours. Nó hoạt động khi các cam kết không được hợp nhất một cách rõ ràng. Nhưng cách tiếp cận này sẽ không hoạt động luôn luôn, phải trích dẫn nguồn Changes from the other tree that do not conflict with our side are reflected in the merge result. Nó không hoạt động với tôi, vì tôi đã hợp nhất sạch sẽ các cam kết trong nhánh của mình đang bị ghi đè. Còn cách nào khác không?
NiharGht

11

Bạn có thể thử tùy chọn "của chúng tôi" trong hợp nhất git,

git hợp nhất chi nhánh -X của chúng tôi

Tùy chọn này buộc các nhóm xung đột phải được tự động giải quyết rõ ràng bằng cách ưu tiên phiên bản của chúng tôi. Những thay đổi từ cây khác không xung đột với phía chúng tôi được phản ánh vào kết quả hợp nhất. Đối với tệp nhị phân, toàn bộ nội dung được lấy từ phía chúng tôi.


3
Điều này sẽ ngược lại, vì OP đã nói rằng ông ấy muốn demophiên bản này được ưa thích hơn mặc dù ông ấy đang sáp nhập vào master. Cũng có -X theirs, nhưng không rõ ràng rằng đây là những gì OP thực sự muốn.

Bạn đã không đọc toàn bộ cách. Ghi chú của bạn mô tả những gì ourssẽ làm khi sử dụng trên phụ trợ với -stùy chọn. Khi sử dụng oursvới -X: Nó loại bỏ mọi thứ mà cây khác đã làm, khai báo lịch sử của chúng ta chứa tất cả những gì đã xảy ra trong đó. nguồn
jimasun

2

Khi tôi thử sử dụng -X theirsvà các công tắc lệnh liên quan khác, tôi vẫn nhận được một cam kết hợp nhất. Tôi có lẽ đã không hiểu nó một cách chính xác. Một cách thay thế dễ hiểu là chỉ cần xóa nhánh sau đó theo dõi lại.

git branch -D <branch-name>
git branch --track <branch-name> origin/<branch-name>

Đây không chính xác là một "hợp nhất", nhưng đây là những gì tôi đang tìm kiếm khi tôi bắt gặp câu hỏi này. Trong trường hợp của tôi, tôi muốn kéo các thay đổi từ một nhánh từ xa được đẩy.

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.