Sự khác biệt giữa `git merge` và` git merge --no-ff` là gì?


977

Sử dụng gitk log, tôi không thể nhận ra sự khác biệt giữa hai. Làm cách nào tôi có thể quan sát sự khác biệt (bằng lệnh git hoặc công cụ nào đó)?




Câu trả lời:


1080

Các --no-ffngăn chặn cờ git mergetừ thực hiện một "tua" nếu nó phát hiện rằng hiện tại của bạn HEADlà tổ tiên của các cam kết bạn đang cố gắng hợp nhất. Chuyển tiếp nhanh là khi, thay vì xây dựng một cam kết hợp nhất, git chỉ di chuyển con trỏ nhánh của bạn để trỏ đến cam kết đến. Điều này thường xảy ra khi làm git pullmà không có bất kỳ thay đổi cục bộ.

Tuy nhiên, đôi khi bạn muốn ngăn hành vi này xảy ra, thường là vì bạn muốn duy trì một cấu trúc liên kết chi nhánh cụ thể (ví dụ: bạn đang hợp nhất trong một nhánh chủ đề và bạn muốn đảm bảo nó sẽ như vậy khi đọc lịch sử). Để làm điều đó, bạn có thể vượt qua --no-ffcờ và git mergesẽ luôn xây dựng một sự hợp nhất thay vì chuyển tiếp nhanh.

Tương tự, nếu bạn muốn thực thi một git pullhoặc sử dụng git mergeđể chuyển tiếp nhanh chóng rõ ràng và bạn muốn bảo lãnh nếu nó không thể chuyển tiếp nhanh, thì bạn có thể sử dụng --ff-onlycờ. Bằng cách này, bạn có thể thường xuyên làm một cái gì đó như git pull --ff-onlykhông cần suy nghĩ, và sau đó nếu nó bị lỗi, bạn có thể quay lại và quyết định xem bạn muốn hợp nhất hoặc rebase.


87
Để trả lời trực tiếp hơn câu hỏi của OP: chúng không phải lúc nào cũng khác nhau, nhưng nếu có, thì rõ ràng gitkhoặc git log --graphviệc hợp nhất chuyển tiếp nhanh không tạo ra một cam kết hợp nhất, trong khi đó, không phải là chuyển tiếp nhanh.
Cascabel

11
Sẽ tốt hơn nếu mở rộng lý do để tránh ff: tác giả đã đề cập đến "cấu trúc liên kết nhánh cụ thể" có nghĩa là trong trường hợp - không-ff, một cam kết hợp nhất bổ sung đóng vai trò là điểm đánh dấu của hợp nhất. Ưu điểm là đánh dấu hợp nhất rõ ràng với tên của tác giả và sáp nhập. Nhược điểm là lịch sử phi tuyến tính trông giống như một tập hợp các tuyến đường sắt hội tụ. Một tác dụng phụ tâm lý có thể có của việc hợp nhất mặc dù là những người đóng góp mất hứng thú do quá trình xem xét lâu hơn: blog.spreedly.com/2014/06/24/ mẹo
Vlad

6
Sẽ công bằng khi nói rằng --no-fftừ một tính năng để phát triển hoặc phát triển thành chủ tương tự như hợp nhất một yêu cầu kéo?
merlinpatt

9
@merlinpatt Chắc chắn rồi. Nếu bạn hợp nhất một yêu cầu kéo trong GitHub thì nó sẽ tương đương với --no-ff.
Lily Ballard

1
Đây là một lời giải thích tốt. Man, không có đủ lời giải thích git tốt ngoài kia để mọi người hiểu tại sao lịch sử git sạch thực sự, thực sự quan trọng (bao gồm cả tôi!)
dudewad 13/03/2017

1037

Đồ họa trả lời cho câu hỏi này

Đây là một trang web với một lời giải thích rõ ràng và minh họa đồ họa của việc sử dụng git merge --no-ff:

sự khác biệt giữa hợp nhất git --no-ff và git merge

Cho đến khi tôi nhìn thấy điều này, tôi đã hoàn toàn bị mất với git. Sử dụng --no-ffcho phép ai đó xem lại lịch sử để thấychi nhánh bạn đã kiểm tra để làm việc. (liên kết đó trỏ đến công cụ trực quan "mạng" của github) Và đây là một tài liệu tham khảo tuyệt vời khác với hình minh họa. Tài liệu tham khảo này bổ sung cho phần đầu tiên độc đáo với sự tập trung nhiều hơn vào những người ít làm quen với git.


Thông tin cơ bản cho những người mới như tôi

Nếu bạn giống như tôi chứ không phải Git-guru, câu trả lời của tôi ở đây mô tả việc xử lý xóa các tệp khỏi theo dõi của git mà không xóa chúng khỏi hệ thống tệp cục bộ, có vẻ như được ghi lại kém nhưng thường xảy ra. Một tình huống newb khác là nhận mã hiện tại , mà vẫn tìm cách trốn tránh tôi.


Ví dụ quy trình làm việc

Tôi đã cập nhật một gói lên trang web của mình và phải quay lại ghi chú của mình để xem quy trình làm việc của mình; Tôi nghĩ rằng nó hữu ích để thêm một ví dụ cho câu trả lời này.

Quy trình làm việc của tôi về các lệnh git:

git checkout -b contact-form
(do your work on "contact-form")
git status
git commit -am  "updated form in contact module"
git checkout master
git merge --no-ff contact-form
git branch -d contact-form
git push origin master

Dưới đây: sử dụng thực tế, bao gồm giải thích.
Lưu ý: đầu ra bên dưới bị bắn tỉa; git khá dài dòng.

$ git status
# On branch master
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   ecc/Desktop.php
#       modified:   ecc/Mobile.php
#       deleted:    ecc/ecc-config.php
#       modified:   ecc/readme.txt
#       modified:   ecc/test.php
#       deleted:    passthru-adapter.igs
#       deleted:    shop/mickey/index.php
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       ecc/upgrade.php
#       ecc/webgility-config.php
#       ecc/webgility-config.php.bak
#       ecc/webgility-magento.php

Lưu ý 3 điều từ phía trên:
1) Trong đầu ra, bạn có thể thấy những thay đổi từ bản nâng cấp của gói ECC, bao gồm cả việc bổ sung các tệp mới.
2) Cũng lưu ý rằng có hai tệp (không có trong /eccthư mục) Tôi đã xóa độc lập với thay đổi này. Thay vì nhầm lẫn giữa việc xóa các tệp đó với ecc, tôi sẽ tạo một cleanupnhánh khác sau đó để phản ánh việc xóa các tệp đó.
3) Tôi đã không tuân theo quy trình làm việc của mình! Tôi đã quên git trong khi tôi đang cố gắng để ecc hoạt động trở lại.

Dưới đây: thay vì bao gồm tất cả những git commit -am "updated ecc package"gì tôi thường làm, tôi chỉ muốn thêm các tệp trong /eccthư mục. Những tệp bị xóa đó không phải là một phần cụ thể của tôi git add, nhưng vì chúng đã được theo dõi trong git, tôi cần xóa chúng khỏi cam kết của chi nhánh này:

$ git checkout -b ecc
$ git add ecc/*
$ git reset HEAD passthru-adapter.igs
$ git reset HEAD shop/mickey/index.php
Unstaged changes after reset:
M       passthru-adapter.igs
M       shop/mickey/index.php

$ git commit -m "Webgility ecc desktop connector files; integrates with Quickbooks"

$ git checkout master
D       passthru-adapter.igs
D       shop/mickey/index.php
Switched to branch 'master'
$ git merge --no-ff ecc
$ git branch -d ecc
Deleted branch ecc (was 98269a2).
$ git push origin master
Counting objects: 22, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (14/14), done.
Writing objects: 100% (14/14), 59.00 KiB, done.
Total 14 (delta 10), reused 0 (delta 0)
To git@github.com:me/mywebsite.git
   8a0d9ec..333eff5  master -> master



Script để tự động hóa ở trên

Đã sử dụng quy trình này hơn 10 lần trong một ngày, tôi đã thực hiện viết các tập lệnh bó để thực thi các lệnh, vì vậy tôi đã tạo một git_update.sh <branch> <"commit message">tập lệnh gần như phù hợp để thực hiện các bước trên. Đây là nguồn Gist cho kịch bản đó.

Thay vì git commit -amtôi đang chọn các tệp từ danh sách "đã sửa đổi" được tạo qua git statusvà sau đó dán những tệp trong tập lệnh này. Điều này xuất hiện bởi vì tôi đã thực hiện hàng tá chỉnh sửa nhưng muốn các tên nhánh khác nhau để giúp nhóm các thay đổi.


11
Bạn vẫn có thể xóa một chi nhánh một cách an toàn sau khi bạn hợp nhất với --no-fftùy chọn không?
Andy Fleming

17
@DesignerGuy có bạn có thể xóa chi nhánh cũ một cách an toàn. Hãy nghĩ về chi nhánh es như chỉ con trỏ đến một cam kết cụ thể.
Zyphrax

2
Tôi thấy văn bản này từ trang được liên kết hữu ích: không có --no-ff "không thể thấy từ lịch sử Git mà các đối tượng cam kết cùng thực hiện một tính năng - bạn sẽ phải đọc thủ công tất cả các thông điệp tường trình."
Lorne Laliberte

một hình ảnh luôn luôn tốt hơn một ngàn từ!
rupps

1
Đồ họa không hiển thị nhánh tính năng trong hình ảnh thứ hai, tại sao không? Nó vẫn tồn tại phải không?
ADJenks

269

Hợp nhất các chiến lược

Hợp nhất rõ ràng : Tạo một cam kết hợp nhất mới. (Đây là những gì bạn sẽ nhận được nếu bạn sử dụng --no-ff.)

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

Hợp nhất chuyển tiếp nhanh : Chuyển tiếp nhanh chóng, mà không tạo ra một cam kết mới:

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

Rebase : Thiết lập cấp độ cơ sở mới:

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

Squash: Nghiền hoặc bóp (một cái gì đó) với lực để nó trở nên phẳng:

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


11
Đồ họa thú vị nhưng nó không thực sự hiển thị trường hợp --no-ff và do đó không hoàn toàn trả lời câu hỏi ở đây
Vib

22
Cái đầu tiên, "hợp nhất rõ ràng", có tiêu đề ở đây là "hợp nhất", là hợp nhất không ff.
bkribbs

3
đồ họa đó thực sự đã giúp tôi rất nhiều
exexzian

2
không trả lời câu hỏi mỗi lần nói, nhưng đồ họa này thật tuyệt vời, UPVOTE!
SovietFrontier

3
Vì vậy, sự khác biệt giữa Rebase và hợp nhất chuyển tiếp nhanh là gì?
ThanosFisherman

217

Các --no-ffĐảm bảo lựa chọn mà một tiền đạo merge nhanh sẽ không xảy ra, và đó là một cam kết mới đối tượng sẽ luôn được tạo ra . Điều này có thể được mong muốn nếu bạn muốn git duy trì lịch sử của các nhánh tính năng.             hợp nhất git --no-ff vs git merge Trong hình trên, bên trái là một ví dụ về lịch sử git sau khi sử dụng git merge --no-ffvà bên phải là một ví dụ về việc sử dụng git mergenơi có thể hợp nhất ff.

EDIT : Phiên bản trước của hình ảnh này chỉ cho biết một phụ huynh duy nhất cho cam kết hợp nhất. Hợp nhất xác nhận có nhiều xác nhận gốc mà git sử dụng để duy trì lịch sử của "nhánh tính năng" và của nhánh ban đầu. Các liên kết nhiều phụ huynh được tô sáng màu xanh lá cây.


3
Mũi tên xanh chỉ ra gì so với mũi tên đen?
rtconner

11
mũi tên màu xanh lá cây biểu thị một liên kết giữa một cam kết và cha mẹ trong đó cam kết có nhiều hơn một cha mẹ. Cam kết bình thường (màu đen) chỉ có một cha mẹ.
Daniel Smith

9
@DanielSmith Làm thế nào để bạn vẽ biểu đồ thanh lịch này?
chancyWu

4
@chancyWu với Adobe Illustrator
Daniel Smith

Dường như trong công ty của tôi, tất cả các yêu cầu kéo được hợp nhất với tùy chọn --no-ff. Trong trường hợp đó, nó vẫn có ý nghĩa để bắt đầu lại trước khi tôi tạo một yêu cầu kéo?
Nickpick

37

Đây là một câu hỏi cũ và điều này được đề cập một cách tinh tế trong các bài đăng khác, nhưng lời giải thích tạo ra nhấp chuột này cho tôi là việc hợp nhất không chuyển tiếp nhanh sẽ yêu cầu một cam kết riêng .


bạn vui lòng xem lại quy trình làm việc trong câu trả lời của tôi ở trên: điều này có nghĩa là tôi cần các cam kết bổ sung ngoài những gì tôi có bây giờ? Cảm ơn.
Chris K

3
@ChrisK git merge --no-ff eccbạn chỉ cần có một cam kết hợp nhất bổ sung trong git logtổng thể chi nhánh. Điều đó là không cần thiết về mặt kỹ thuật trong trường hợp chủ nhân đang chỉ vào tổ tiên trực tiếp của ecc cam kết đang bật nhưng bằng cách chỉ định tùy chọn --no-ff, bạn đang buộc tạo ra cam kết hợp nhất đó. Nó sẽ có tiêu đề:Merge branch 'ecc'
Ankur Agarwal

Tóm tắt tuyệt vời! :)
Eduard

4

Cờ --no-ff làm cho hợp nhất luôn tạo một đối tượng cam kết mới, ngay cả khi việc hợp nhất có thể được thực hiện với chuyển tiếp nhanh. Điều này tránh mất thông tin về sự tồn tại lịch sử của một nhánh tính năng và các nhóm cùng nhau tất cả các cam kết cùng nhau thêm tính năng

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.