Яка різниця між `git merge` та` git merge --no-ff`?


977

Використовуючи gitk log, я не міг помітити різниці між ними. Як я можу спостерігати різницю (за допомогою команди git чи якогось інструмента)?




Відповіді:


1080

В --no-ffпрапор запобігає git mergeвід виконання «голодування вперед» , якщо він виявить , що ваш поточний HEADє предком коммітов ви намагаєтеся об'єднати. Швидкий перемотка вперед - це, замість того, щоб створювати комісію злиття, git просто переміщує ваш вказівник гілки, щоб вказати на вхідний коміт. Це зазвичай трапляється, коли не робиться git pullлокальних змін.

Однак час від часу ви хочете не допустити подібної поведінки, як правило, тому, що ви хочете підтримувати конкретну топологію гілки (наприклад, ви об’єднуєтесь у тематичну галузь і хочете переконатися, що вона виглядає таким чином під час читання історії). Для того , щоб зробити це, ви можете передати --no-ffпрапор і git mergeбуде завжди будувати злиття замість швидкого перемотування вперед.

Аналогічно, якщо ви хочете виконати git pullабо використовувати git mergeдля того, щоб явно перемотати вперед, і ви хочете скористатися, якщо він не може перемотати вперед, тоді ви можете використовувати --ff-onlyпрапор. Таким чином, ви можете регулярно робити щось на кшталт, git pull --ff-onlyне замислюючись, а потім, якщо це помилки, ви можете повернутися назад і вирішити, чи хочете ви об'єднати або відновити.


87
Для більш прямої відповіді на питання OP ще: вони не завжди відрізняються, але якщо вони є, це зрозуміло з gitkабо git log --graphщо швидко вперед злиття не створити злиття зробити, а не швидкого перемотування вперед один зробив.
Каскабель

11
Було б непогано розкрити причину уникнення ff: автор згадав "специфічну топологію гілки" означає, що в --no-ff випадку додаткова комісія злиття служить маркером злиття. Плюси - це явний маркер злиття з іменами автора та злиття. Мінуси - це нелінійна історія, схожа на набір збіжних залізничних колій. Можливий психологічні побічний ефект злиття , хоча це вкладники втрати інтересу з - за більш тривалим процес огляду: blog.spreedly.com/2014/06/24 / ...
Влад

6
Чи було б справедливо сказати, що --no-ffвід функції, яка розробляється або розвивається до майстра, схоже на об'єднання запиту на тягнення?
merlinpatt

9
@merlinpatt Звичайно. Якщо ви об'єднаєте запит на тягу в GitHub, він робить еквівалент --no-ff.
Лілі Баллард

1
Це хороше пояснення. Людина, просто не вистачає хороших пояснень з git, щоб люди зрозуміли, чому чиста історія git насправді, дуже важлива (я
включаю

1037

Графічна відповідь на це питання

Ось сайт із чітким поясненням та графічною ілюстрацією використання git merge --no-ff:

різниця між git merge - no-ff та git merge

Поки я цього не побачив, я повністю загубився від git. Використання --no-ffдозволяє комусь, хто переглядає історію, чітко бачити гілку, над якою ви перевірили роботу. (це посилання вказує на інструмент візуалізації "мережі" github) І ось ще одна чудова посилання з ілюстраціями. Ця довідка добре доповнює першу з більшою увагою на тих, хто менш знайомий з git.


Основна інформація для новичок, як я

Якщо ви схожі на мене, а не на Git-гуру, моя відповідь тут описує обробку видалення файлів із відстеження git без їх видалення з локальної файлової системи, що здається погано задокументованим, але часто зустрічається. Ще одна нова ситуація - це отримання поточного коду , який все ще вдається мені уникати.


Приклад робочого процесу

Я оновив пакет на своєму веб-сайті, і мені довелося повернутися до своїх нотаток, щоб побачити мій робочий процес; Я вважав корисним додати приклад до цієї відповіді.

Мій робочий процес команд 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

Нижче: фактичне використання, включаючи пояснення.
Примітка: вихідний результат прорізаний; git досить багатослівний.

$ 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

Зверніть увагу на 3 речі зверху:
1) На виході ви бачите зміни від оновлення пакету ECC, включаючи додавання нових файлів.
2) Також зауважте, що два файли (не в /eccпапці), які я видалив незалежно від цієї зміни. Замість того, щоб плутати ці видалення файлів ecc, я зроблю іншу cleanupгілку пізніше, щоб відобразити видалення цих файлів.
3) Я не стежив за своїм робочим процесом! Я забув про git, коли я намагався знову працювати з ecc.

Нижче: замість того, щоб робити все включене, git commit -am "updated ecc package"як правило, я хотів лише додати файли в /eccпапку. Ці видалені файли не були частиною могоgit add , але, оскільки вони вже відслідковувалися в git, мені потрібно видалити їх з цієї гілки:

$ 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



Сценарій автоматизації описаного вище

Використовуючи цей процес 10 і більше разів на день, я взявся писати пакетні сценарії для виконання команд, тому я зробив майже належне git_update.sh <branch> <"commit message"> сценарій для виконання вищезазначених кроків. Ось джерело Gist для цього сценарію.

Замість цього git commit -amя вибираю файли зі "модифікованого" списку, створеного за допомогою, git statusа потім вставляю їх у цей сценарій. Це сталося тому, що я вніс десятки змін, але хотів, щоб різноманітні назви гілок допомогли згрупувати зміни.


11
Чи можете ви все-таки безпечно видалити гілку після об'єднання з --no-ffопцією?
Енді Флемінг

17
@DesignerGuy так, ви можете сміливо видалити стару гілку. Подумайте, що гілки є просто вказівниками на певний комітет.
Zyphrax

2
Цей текст із пов’язаної сторінки мені здається корисним: без --no-ff "з історії Git неможливо побачити, хто з об'єктів комітету разом реалізував функцію - вам доведеться вручну читати всі повідомлення журналу".
Lorne Laliberte

одне зображення завжди найкраще тисячі слів!
рвап

1
Графіка не відображає гілки функцій на другому зображенні, чому б ні? Він все ще існує, чи не так?
ADJenks

269

Стратегії злиття

Явне злиття : створює нову комісію злиття. (Це те, що ви отримаєте, якщо використали --no-ff.)

введіть тут опис зображення

Швидке злиття вперед: швидко вперед, не створюючи нового зобов’язання:

введіть тут опис зображення

База даних : Встановлення нового базового рівня:

введіть тут опис зображення

Кабачок: розчавити або стиснути (щось) силою, щоб воно стало плоским:

введіть тут опис зображення


11
Цікава графіка, але вона насправді не показує випадку --no-ff, а значить, не зовсім відповідає на питання тут
Vib

22
Перший, "явне злиття", названий тут як "злиття", - це не-ff злиття.
bkribbs

3
що графіка мені дуже допомогла
exexzian

2
не відповідає на запитання за словом, але ця графіка дивовижна!
Радянський кордон

3
То в чому ж тоді різниця між Rebase і швидким злиттям вперед?
ThanosFisherman

217

Цей --no-ffпараметр гарантує, що швидкого злиття вперед не відбудеться і що завжди буде створений новий об'єкт фіксації . Це може бути бажано, якщо ви хочете, щоб git підтримував історію галузей функцій.             git merge - no-ff vs git merge На наведеному вище зображенні ліва сторона є прикладом історії git після використання, git merge --no-ffа права сторона - приклад використання git mergeтам, де було можливо злиття ff.

РЕДАКТУВАННЯ : Попередня версія цього зображення вказувала лише одного батька для об'єднання об'єднань. Об'єднання комітетів мають кілька батьківських комітетів, які git використовує для підтримки історії "функції гілки" та початкової гілки. Кілька батьківських посилань виділені зеленим кольором.


3
Що означає зелена стрілка проти чорної стрілки?
rtconner

11
зелена стрілка вказує на зв'язок між командою та батьком, де у коміті є більше одного з батьків. Звичайні комісії (чорні) мають лише один з батьків.
Даніель Сміт

9
@DanielSmith Як ви малюєте цей елегантний графік?
chancyWu

4
@chancyWu з Adobe Illustrator
Daniel Smith

Здається, у моїй компанії всі запити на витяг об’єднуються з опцією --no-ff. За таких обставин, чи все ж є сенс перезавантажитись, перш ніж створити запит на виклик?
Нікпік

37

Це давнє запитання, і це дещо тонко згадується в інших публікаціях, але пояснення, яке зробило цей клік для мене, полягає в тому, що не швидкі злиття вперед вимагають окремої фіксації .


Чи можете ви, будь ласка, переглянути робочий процес у моїй відповіді вище: чи це означає, що мені потрібні додаткові комісії поза тим, що я отримав зараз? Дякую.
Кріс К

3
@ChrisK у git merge --no-ff eccвас буде просто додаткова комісія злиття в git logмагістралі для філії. Це технічно не потрібно в тому випадку, якщо майстер вказує на прямого предка виконуваної комісії, але вказуючи параметр --no-ff, ви змушуєте створювати цей об'єкт об'єднання. Він матиме назву:Merge branch 'ecc'
Ankur Agarwal

Чудовий підсумок! :)
Едуард

4

Прапор --no-ff викликає злиття, щоб завжди створювати новий об'єкт фіксації, навіть якщо злиття може бути виконане за допомогою швидкого перемотування вперед. Це дозволяє уникнути втрати інформації про історичне існування відгалуження та об'єднує всі комісії, які разом додали функцію

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.