Cách tốt nhất (và an toàn nhất) để hợp nhất một nhánh Git thành chủ là gì?


2104

Một nhánh mới từ masterđược tạo ra, chúng tôi gọi nó test.

Có một số nhà phát triển cam kết masterhoặc tạo các nhánh khác và sau đó hợp nhất vào master.

Giả sử công việc testđang diễn ra trong vài ngày và bạn muốn liên tục testcập nhật các cam kết bên trong master.

Tôi sẽ làm git pull origin mastertừ test.

Câu hỏi 1: Đây có phải là phương pháp đúng đắn? Các nhà phát triển khác có thể dễ dàng làm việc trên các tệp giống như tôi đã làm việc btw.


Công việc của tôi đã testxong và tôi sẵn sàng hợp nhất lại master. Đây là hai cách tôi có thể nghĩ ra:

A:

git checkout test
git pull origin master
git push origin test
git checkout master
git pull origin test 

B:

git checkout test
git pull origin master
git checkout master
git merge test

Tôi không sử dụng --rebasevì theo hiểu biết của tôi, rebase sẽ nhận được các thay đổi từ mastervà xếp chồng tôi lên trên đó do đó nó có thể ghi đè lên những thay đổi mà người khác đã thực hiện.

Câu 2: Một trong hai phương pháp này là đúng? Sự khác biệt ở đó là gì?

Mục tiêu trong tất cả những điều này là để giữ cho testchi nhánh của tôi được cập nhật với những điều xảy ra mastervà sau này tôi có thể hợp nhất chúng lại với masterhy vọng giữ cho dòng thời gian càng tuyến tính càng tốt.


18
không .. rebase không bao giờ ghi đè, nó chỉ cố gắng để đạt được một lịch sử sạch hơn. bởi reattach (hoặc giả) lịch sử đến điểm cuối của bậc thầy
Junchen Liu

7
rebase không ghi đè lên cam kết của bạn. Nó hoàn tác các cam kết của bạn, áp dụng các cam kết trong nhánh chính cho nhánh thử nghiệm của bạn, sau đó áp dụng các cam kết của bạn trở lại để kiểm tra.
zundi

Câu trả lời:


2993

Làm thế nào tôi sẽ làm điều này

git checkout master
git pull origin master
git merge test
git push origin master

Nếu tôi có một chi nhánh địa phương từ một điều khiển từ xa, tôi không cảm thấy thoải mái với việc hợp nhất các chi nhánh khác với chi nhánh này với điều khiển từ xa. Ngoài ra tôi sẽ không thúc đẩy những thay đổi của mình, cho đến khi tôi hài lòng với những gì tôi muốn thúc đẩy và tôi cũng sẽ không thúc đẩy mọi thứ, điều đó chỉ dành cho tôi và kho lưu trữ địa phương của tôi. Trong mô tả của bạn có vẻ như, điều đó testchỉ dành cho bạn? Vì vậy, không có lý do để xuất bản nó.

git luôn cố gắng tôn trọng sự thay đổi của bạn và những người khác, và cũng vậy --rebase. Tôi không nghĩ rằng tôi có thể giải thích nó một cách thích hợp, vì vậy hãy xem cuốn sách Git - Rebasing hoặc git-ready: Giới thiệu về việc nổi loạn để mô tả một chút. Đây là một tính năng khá thú vị


2
git merge testmang lại cho tôi fatal: 'test' does not point to a commit. Tôi phải tìm kiếm git logđiểm cam kết trên nhánh thử nghiệm, chuyển trở lại nhánh chính rồi làm git merge 0f37d3154abbf52a4cbbbb5109f08af6a7567234.
Duncanmoo

17
@Duncanmoo Vâng, tất nhiên chi nhánh testphải tồn tại. Chắc chắn, bạn có thể sử dụng hàm băm cam kết thay thế, nhưng thường sử dụng tên chi nhánh thường dễ dàng hơn. Trong nội bộ, nó chỉ lấy ra băm của HEADchi nhánh.
KingCrunch

44
@shanyangqu Để có được những thay đổi mới nhất từ ​​xa. Nếu bạn làm việc một mình và chỉ với một hệ thống thì không có vấn đề gì. Nhưng khi có những thay đổi được đẩy từ một hệ thống khác (có thể từ một nhà phát triển khác), bạn sẽ thấy một cuộc xung đột ngay khi bạn cố gắng đẩy sự hợp nhất của mình trở lại (bước thứ 4). Giải pháp duy nhất bây giờ là hợp nhất chủ địa phương của bạn vào chủ từ xa, kết thúc bằng một cam kết hợp nhất "tổng thể thành chủ / gốc" khá xấu xí. Vì vậy, luôn luôn là một ý tưởng hay để thực hiện trước khi hợp nhất
KingCrunch

7
"Trong mô tả của bạn có vẻ như, bài kiểm tra đó chỉ dành cho bạn? Vì vậy, không có lý do để xuất bản nó." Bạn có thể muốn đẩy chi nhánh địa phương của mình lên một máy chủ nếu, ví dụ, máy chủ đó cung cấp một bản sao lưu chống lại ổ đĩa cục bộ của bạn hoặc nếu bạn không có một phương tiện khác để thực hiện sao lưu.
Eric

5
"... Ngoài ra tôi sẽ không thúc đẩy các thay đổi của mình, cho đến khi tôi hài lòng với những gì tôi muốn thúc đẩy ..." tại sao không cố gắng vì mã của bạn được sao lưu, trong trường hợp máy cục bộ của bạn chết và nhiều ngày nỗ lực đã biến mất?
Rich Stone

400

Đây là một câu hỏi rất thực tế, nhưng tất cả các câu trả lời ở trên là không thực tế.

Giống

git checkout master
git pull origin master
git merge test
git push origin master

Cách tiếp cận này có hai vấn đề :

  1. Điều đó không an toàn, vì chúng tôi không biết liệu có bất kỳ xung đột nào giữa nhánh thử nghiệm và nhánh chính hay không.

  2. Nó sẽ "ép" tất cả các cam kết kiểm tra thành một cam kết hợp nhất trên bản gốc; điều đó có nghĩa là trên nhánh chính, chúng ta không thể thấy tất cả các nhật ký thay đổi của nhánh thử nghiệm.

Vì vậy, khi chúng tôi nghi ngờ sẽ có một số xung đột, chúng tôi có thể có các hoạt động git sau:

git checkout test
git pull 
git checkout master
git pull
git merge --no-ff --no-commit test

Kiểm tra mergetrước commit, tránh cam kết chuyển tiếp nhanh bằng cách --no-ff,

Nếu gặp phải xung đột, chúng ta có thể chạy git statusđể kiểm tra chi tiết về các xung đột và cố gắng giải quyết

git status

Khi chúng tôi giải quyết được các xung đột hoặc nếu không có xung đột, chúng tôi commitpushhọ

git commit -m 'merge test branch'
git push

Nhưng cách này sẽ làm mất lịch sử thay đổi được đăng nhập trong nhánh thử nghiệm và nó sẽ khiến nhánh chính khó có thể hiểu được lịch sử của dự án.

Vì vậy, phương pháp tốt nhất là chúng ta phải sử dụng rebasethay vì merge(giả sử, trong thời điểm này, chúng ta đã giải quyết được các xung đột chi nhánh).

Sau đây là một mẫu đơn giản, đối với các hoạt động nâng cao, vui lòng tham khảo http://git-scm.com/book/en/v2/Git-Branching-Rebasing

git checkout master
git pull
git checkout test
git pull
git rebase -i master
git checkout master
git merge test

Đúng, khi bạn đã hoàn thành các uppers, tất cả các cam kết của nhánh Test sẽ được chuyển lên đầu của nhánh Master. Lợi ích chính của việc nổi loạn là bạn có được một lịch sử dự án tuyến tính và sạch sẽ hơn nhiều.

Điều duy nhất bạn cần tránh là: không bao giờ sử dụng rebasetrên nhánh công cộng, như nhánh chính.

Không bao giờ thực hiện các thao tác như sau:

git checkout master
git rebase -i test

Chi tiết cho https://www.atlassian.com/git/tutorials/merging-vs-rebasing/the-golden-rule-of-rebasing

ruột thừa:


4
Tôi đồng ý từ chối các nhánh thử nghiệm để sau này sáp nhập vào chủ là cách để đi. Ngay cả các câu trả lời khác cũng đúng, điều này sẽ giữ lịch sử thay đổi kiểm tra chi nhánh trong phần đầu của chủ nhân khi trình tự động đề cập "bạn có được một dự án lót và sạch hơn nhiều", đó là mục đích của hệ thống kiểm soát phiên bản.
le0diaz

16
Câu nói "đó không phải là một cách an toàn, vì chúng tôi không biết có bất kỳ mâu thuẫn nào giữa nhánh thử nghiệm và nhánh chính" không đúng: người ta luôn có thể hủy bỏ hợp nhất. Và ngay cả khi không có xung đột, bạn luôn có thể hoàn tác cam kết cục bộ cuối cùng miễn là nó không bị đẩy. Không có sự hiểu biết chính xác về git, một số điều có vẻ hơi đáng sợ hoặc không rõ ràng, nhưng "không an toàn" chỉ là không chính xác theo bất kỳ cách nào. Hãy cẩn thận đừng nhầm lẫn giữa những người khác với thông tin không chính xác.
Paul van Leeuwen

4
đồng ý với @PaulvanLeeuwen, khi bạn kết hợp nhánh thử nghiệm thành chủ, bạn sẽ được thông báo về xung đột và đó là nơi bạn sẽ bước vào và hợp nhất các thay đổi. Khi bạn đã hoàn tất, bạn sẽ cam kết hợp nhất và đẩy lùi. Nếu bạn hối tiếc hoặc không thể hợp nhất chính xác, bạn luôn có thể loại bỏ công việc của mình và kéo lại từ chủ. Vì vậy, nó chắc chắn không an toàn ..
Juan

3
Tại sao rebase -i?
MushyPeas

8
Rebasing vốn đã không an toàn hơn so với sáp nhập. Đề xuất rebasing như là một lựa chọn an toàn hơn để sáp nhập là sai. Rebasing là một chiến lược hợp lệ, nhưng đi kèm với nhiều cảnh báo hơn mà người dùng nên cẩn thận.
Ikke

90

Không phải là một cuộc nổi loạn hay hợp nhất sẽ ghi đè lên những thay đổi của bất kỳ ai (trừ khi bạn chọn làm như vậy khi giải quyết xung đột).

Cách tiếp cận thông thường trong khi phát triển là

git checkout master
git pull
git checkout test
git log master.. # if you're curious
git merge origin/test # to update your local test from the fetch in the pull earlier

Khi bạn đã sẵn sàng để hợp nhất trở lại thành chủ,

git checkout master
git log ..test # if you're curious
git merge test
git push

Nếu bạn lo lắng về việc phá vỡ một cái gì đó trên hợp nhất, git merge --abortcó sẵn cho bạn.

Sử dụng đẩy và sau đó kéo như một phương tiện hợp nhất là ngớ ngẩn. Tôi cũng không chắc tại sao bạn lại đẩy bài kiểm tra về nguồn gốc.


1
Quá trình này sẽ tăng số lượng cam kết, mỗi khi bạn chuyển đổi giữa các chi nhánh, bạn phải cam kết chi nhánh của mình.
iBug

2
Gì? Bạn đang nói rằng nó sẽ tăng số lượng cam kết mỗi khi bạn chuyển đổi chi nhánh? Hay bạn đang nói rằng mỗi khi bạn chuyển đổi chi nhánh, bạn phải "cam kết chi nhánh"? Đầu tiên là không đúng sự thật và tôi không chắc thứ hai có nghĩa là gì.
raylu

trước khi thanh toán, bạn phải cam kết chi nhánh. đó là những gì tôi đang nói
iBug

11
Bạn không: đó là (một trong những điều) git stashlà dành cho.
msanford

1
Hoặc bạn có thể tăng cường cam kết cuối cùng của mình (trong chi nhánh địa phương) và biến nó thành hoàn hảo trước khi đẩy.
whihathac

42

Trước tiên tôi sẽ làm cho chi nhánh được sáp nhập càng sạch càng tốt. Chạy thử nghiệm của bạn, đảm bảo trạng thái như bạn muốn. Làm sạch các cam kết mới bằng git squash .

Ngoài câu trả lời của KingCrunches , tôi đề nghị sử dụng

git checkout master
git pull origin master
git merge --squash test
git commit
git push origin master

Bạn có thể đã thực hiện nhiều cam kết trong nhánh khác, chỉ nên là một cam kết trong nhánh chính. Để giữ lịch sử cam kết sạch nhất có thể, bạn có thể muốn nén tất cả các cam kết của mình từ nhánh kiểm tra thành một cam kết trong nhánh chính (xem thêm: Git: Để đè bẹp hay không đè bẹp? ). Sau đó, bạn cũng có thể viết lại thông điệp cam kết thành một cái gì đó rất biểu cảm. Một cái gì đó dễ đọc và dễ hiểu, mà không cần đào sâu vào mã.

chỉnh sửa: Bạn có thể quan tâm đến

Vì vậy, trên GitHub, tôi kết thúc việc làm sau đây cho một nhánh tính năng mybranch:

Nhận thông tin mới nhất từ ​​nguồn gốc

$ git checkout master
$ git pull origin master

Tìm hàm băm hợp nhất:

$ git merge-base mybranch master
c193ea5e11f5699ae1f58b5b7029d1097395196f

$ git checkout mybranch
$ git rebase -i c193ea5e11f5699ae1f58b5b7029d1097395196f

Bây giờ hãy chắc chắn rằng đầu tiên là pick, phần còn lại là s:

pick 00f1e76 Add first draft of the Pflichtenheft
s d1c84b6 Update to two class problem
s 7486cd8 Explain steps better

Tiếp theo chọn một thông điệp cam kết rất tốt và đẩy đến GitHub. Thực hiện yêu cầu kéo sau đó.

Sau khi hợp nhất yêu cầu kéo, bạn có thể xóa nó cục bộ:

$ git branch -d mybranch

và trên GitHub

$ git push origin :mybranch

" chỉ nên là một cam kết trong nhánh chính ", cũng không nhất thiết phải như vậy; bạn có thể muốn giữ lịch sử
Cocowalla

Chắc chắn rồi. Nhưng sau đó, đơn giản là đừng
đè bẹp

Tôi nghĩ - cha mẹ đầu tiên dường như là giải pháp tốt nhất. davidchudzicki.com/posts/first-parent
bkribbs

7

Chủ đề cũ, nhưng tôi đã không tìm thấy cách làm của tôi. Nó có thể có giá trị đối với người làm việc với rebase và muốn hợp nhất tất cả các cam kết từ một nhánh (tính năng) trên đầu trang chính. Nếu có xung đột trên đường đi, bạn có thể giải quyết chúng cho mọi cam kết. Bạn giữ toàn quyền kiểm soát trong suốt quá trình và có thể hủy bỏ bất cứ lúc nào.

Nhận Master và Chi nhánh cập nhật:

git checkout master
git pull --rebase origin master
git checkout <branch_name>
git pull --rebase origin <branch_name>

Hợp nhất chi nhánh trên đỉnh của Master:

git checkout <branch_name>
git rebase master

Tùy chọn: Nếu bạn gặp phải Xung đột trong Cuộc nổi loạn:

Đầu tiên, giải quyết xung đột trong tập tin. Sau đó:

git add .
git rebase --continue

Đẩy chi nhánh nổi loạn của bạn:

git push origin <branch_name>

Bây giờ bạn đã có hai tùy chọn:

  • A) Tạo PR (ví dụ: trên GitHub) và hợp nhất nó ở đó thông qua UI
  • B) Quay trở lại dòng lệnh và hợp nhất nhánh thành chủ
git checkout master
git merge --no-ff <branch_name>
git push origin master

Làm xong.


6

Đây là quy trình làm việc mà tôi sử dụng trong công việc của mình với nhóm. Kịch bản là như bạn mô tả. Đầu tiên, khi tôi hoàn thành công việc, testtôi nổi loạn với chủ để lấy bất cứ thứ gì đã được thêm vào chủ trong thời gian tôi làm việc ở testchi nhánh.

git pull -r upstream master

Điều này sẽ kéo các thay đổi thành chủ kể từ khi bạn rẽ testnhánh và áp dụng chúng, sau đó áp dụng các thay đổi bạn đã thực hiện để kiểm tra "trên đầu trang" trạng thái hiện tại của chủ. Có thể có xung đột ở đây, nếu những người khác đã thực hiện thay đổi đối với cùng các tệp mà bạn đã chỉnh sửa trong thử nghiệm. Nếu có, bạn sẽ phải sửa chúng bằng tay và cam kết. Khi bạn đã thực hiện điều đó, bạn sẽ tốt để chuyển sang nhánh chính và hợp nhất testmà không gặp vấn đề gì.


3
git checkout master
git pull origin master
# Merge branch test into master
git merge test

Sau khi hợp nhất, nếu tệp được thay đổi, thì khi bạn hợp nhất, nó sẽ thông qua lỗi "Giải quyết xung đột"

Vì vậy, trước tiên bạn cần giải quyết tất cả các xung đột của mình sau đó, bạn phải một lần nữa cam kết tất cả các thay đổi của mình và sau đó đẩy

git push origin master

Điều này tốt hơn là những người đã thực hiện các thay đổi trong nhánh thử nghiệm, bởi vì anh ta biết những thay đổi mình đã làm.


3

Tôi sẽ sử dụng phương pháp rebase. Chủ yếu là vì nó phản ánh hoàn hảo trường hợp của bạn về mặt ngữ nghĩa, nghĩa là. những gì bạn muốn làm là làm mới trạng thái của chi nhánh hiện tại của bạn và "giả vờ" như thể nó dựa trên cơ sở mới nhất.

Vì vậy, thậm chí không cần kiểm tra master, tôi sẽ:

git fetch origin
git rebase -i origin/master
# ...solve possible conflicts here

Tất nhiên, chỉ tìm nạp từ nguồn gốc không làm mới trạng thái cục bộ của bạn master(vì nó không thực hiện hợp nhất), nhưng nó hoàn toàn ổn cho mục đích của chúng tôi - chúng tôi muốn tránh chuyển đổi, vì mục đích tiết kiệm thời gian.


2

Câu trả lời của @ KingCrunch nên hoạt động trong nhiều trường hợp. Một vấn đề có thể phát sinh là bạn có thể đang ở một máy khác cần rút bản mới nhất từ ​​bài kiểm tra. Vì vậy, tôi khuyên bạn nên thử nghiệm kéo đầu tiên. Bản sửa đổi trông như thế này:

git checkout test
git pull
git checkout master
git pull origin master
git merge test
git push origin master

0

Bạn phải kiểm tra chi nhánh để kéo, vì kéo có nghĩa là hợp nhất thành chủ và bạn cần một cây công việc để hợp nhất.

git checkout master
git pull

Không cần phải kiểm tra trước; rebase làm điều đúng với hai đối số

git rebase master test  

git checkout master
git merge test

git đẩy theo mặc định đẩy tất cả các nhánh tồn tại ở đây và trên điều khiển từ xa

git push
git checkout test

0

Như tiêu đề nói "Cách tốt nhất", tôi nghĩ rằng đó là một ý tưởng tốt để xem xét chiến lược hợp nhất kiên nhẫn .

Từ: https://git-scm.com/docs/merge-str Strategies

Với tùy chọn này, 'hợp nhất-đệ quy' dành thêm một chút thời gian để tránh sự không phù hợp đôi khi xảy ra do các đường khớp không quan trọng (ví dụ: dấu ngoặc từ các hàm riêng biệt). Sử dụng điều này khi các nhánh được sáp nhập đã chuyển hướng dữ dội. Xem thêm git-diff [1] - bệnh nhân.

Sử dụng:

git fetch
git merge -s recursive -X patience origin/master

Bí danh Git

Tôi luôn sử dụng bí danh cho việc này, ví dụ: chạy một lần:

 git config --global alias.pmerge 'merge -s recursive -X patience'

Bây giờ bạn có thể làm:

git fetch
git pmerge origin/master

0

Đây là từ GitLab: Chỉ cần làm theo hướng dẫn:

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


0

Tôi sẽ trả lời theo các nhánh phát triển và tính năng,

nếu bạn đang ở trong nhánh tính năng và cần cập nhật nó với phát triển, hãy sử dụng các lệnh bên dưới: git checkout phát triển git pull git tính năng / xyz git merge phát triển

Bây giờ tính năng của bạn được cập nhật với phát triển, bạn có thể đẩy các thay đổi của mình.

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.