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 fetch
theo 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 -X
tù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à resolve
chiến lược thay thế đều có -X ours
hoặ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
) và 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
để colour
trên dòng 17 và họ thay đổi fred
để barney
trê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
và -X theirs
tù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
.
-X
Tuy 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 i
là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-commit
vào git merge
lệ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/demo
và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/demo
nhưng sẽ tạo ra kết quả cuối cùng tương tự). Thứ hai là đưa origin/master
vàomaster
.
Tôi không rõ ai đang cập nhật demo
và / hoặc master
. Nếu bạn viết mã của riêng mình trên demo
nhánh của riêng bạn , và những người khác đang viết mã và đẩy nó đến demo
nhá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 rebase
thay 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 demo
chi 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/demo
demo
để 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 demo
hoà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 demo
hiệ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-only
tù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-only
có 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).
git push -f origin master