В чем разница между `git merge` и` git merge --no-ff`?


977

Используя gitk log, я не смог заметить разницу между ними. Как я могу наблюдать разницу (с помощью команды git или какого-либо инструмента)?


3
Возможно дублирование Git fast forward VS без слияния fast forward .


Возможная
— копия

Ответы:


1080

В --no-ffфлаг предотвращает git mergeот выполнения «голодание вперед» , если он обнаружит , что ваш текущий HEADявляется предком коммита вы пытаетесь объединить. Быстрая перемотка вперед - это когда вместо создания коммита слияния git просто перемещает указатель ветки, чтобы указать на входящий коммит. Это обычно происходит при выполнении git pullбез каких-либо локальных изменений.

Однако иногда вы хотите предотвратить такое поведение, как правило, потому что вы хотите поддерживать топологию конкретной ветви (например, вы объединяетесь в ветку темы и хотите, чтобы она выглядела так при чтении истории). Чтобы сделать это, вы можете передать --no-ffфлаг и всегдаgit merge создаст слияние вместо быстрой пересылки.

Точно так же, если вы хотите выполнить a 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от возможности разработки или разработки до освоения похоже на объединение запроса на извлечение?
— Мерлинпатт

9
@merlinpatt Конечно. Если вы объединяете запрос на удаление в GitHub, он делает эквивалент --no-ff.
— Лили Баллард

1
Это хорошее объяснение. Чувак, просто не хватает хороших объяснений git для людей, чтобы понять, почему чистая история git действительно, действительно важна (включая меня!)
— dudewad

1037

Графический ответ на этот вопрос

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

разница между git merge --no-ff и git merge

Пока я не увидел это, я был полностью потерян с мерзавцем. Использование --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 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) Я не следил за своим рабочим процессом! Я забыл про мерзавца, когда пытался заставить 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 невозможно увидеть, какие из объектов коммитов вместе реализовали функцию - вам придется вручную читать все сообщения журнала».
— Лорн Лалиберте

одно изображение всегда лучше тысячи слов!
— rupps

1
На рисунке не изображена ветвь функций на втором изображении, почему бы и нет? Это все еще существует, не так ли?
— ADJenks

270

Стратегии слияния

Явное слияние : Создает новый коммит слияния. (Это то, что вы получите, если использовали --no-ff.)

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

Fast Forward Merge: Быстрая перемотка вперед без создания нового коммита:

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

Rebase : установить новый базовый уровень:

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

Сквош: раздавить или сжать (что-то) с силой, чтобы он стал плоским:

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


11
Интересная графика, но она на самом деле не показывает случай --no-ff и, следовательно, не совсем отвечает на вопрос здесь
— Vib

22
Первый, "явное слияние", называемый здесь как "слияние", является слиянием без ff.
— bkribbs

3
эта графика мне очень помогла
— exexzian

2
не отвечает на вопрос, скажем так, но этот рисунок удивителен, UPVOTE!
— Советская граница

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
— Даниэль Смит

Кажется, в моей компании все запросы на включение объединяются с параметром --no-ff. В этих условиях имеет ли смысл еще раз выполнить перебазирование, прежде чем я создаю запрос на извлечение?
— Nickpick

37

Это старый вопрос, и он несколько тонко упоминается в других постах, но объяснение, которое сделало этот щелчок для меня, заключается в том, что для слияния без ускоренной перемотки потребуется отдельная фиксация .


не могли бы вы рассмотреть рабочий процесс в моем ответе выше: означает ли это, что мне нужны дополнительные коммиты сверх того, что я получил сейчас? Спасибо.
— Крис К

3
@ChrisK у git merge --no-ff eccвас просто будет дополнительный коммит слияния в git logветке for. Это технически не требуется в том случае, если master указывает на прямого предка коммита ecc, но указав опцию --no-ff, вы принудительно создаете этот коммит слияния. Это будет иметь название:Merge branch 'ecc'
— Анкур Агарвал

Отличное резюме! :)
— Эдуард

4

Флаг --no-ff заставляет слияние всегда создавать новый объект фиксации, даже если слияние может быть выполнено с ускоренной перемоткой вперед. Это позволяет избежать потери информации об историческом существовании ветви компонента и объединяет все коммиты, которые вместе добавляли функцию

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.