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

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

Ответы

Ответ 1

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

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

Аналогичным образом, если вы хотите выполнить git pull или использовать git merge для явной перемотки вперед, и вы хотите выручить, если он не может выполнить перемотку вперед, тогда вы можете использовать --ff-only флаг. Таким образом, вы можете регулярно делать что-то вроде git pull --ff-only, не думая, а затем, если он ошибается, вы можете вернуться и решить, хотите ли вы объединиться или переустановить.

Ответ 2

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

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

difference between git merge --no-ff and git merge

Пока я не увидел это, я был полностью потерян с помощью git. Использование --no-ff позволяет кому-то отчетливо просмотреть историю видеть ветку, на которую вы проверили, для работы. (эта ссылка указывает на инструмент визуализации github "network" ). А вот еще одна отличная ссылка с иллюстрациями. Эта ссылка дополняет первую из них красиво, с большим вниманием к тем, кто менее знаком с git.


Основная информация для newbs like me

Если вы похожи на меня, а не Git -guru, мой ответ здесь описывает обработку удаления файлов из 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 [email protected]:me/mywebsite.git
   8a0d9ec..333eff5  master -> master



Script для автоматизации вышеприведенных

Используя этот процесс 10 раз в день, я начал писать командные скрипты для выполнения команд, поэтому я сделал почти правильный git_update.sh <branch> <"commit message"> script для выполнения вышеуказанных шагов. Вот источник Gist для этого script.

Вместо git commit -am Я выбираю файлы из "измененного" списка, созданного с помощью git status, а затем вставляя их в этот script. Это произошло потому, что я сделал десятки изменений, но хотел иметь разные названия ветвей, чтобы помочь сгруппировать изменения.

Ответ 3

Параметр --no-ff гарантирует, что быстрого слияния вперед не произойдет и что всегда будет создан новый объект фиксации. Это может быть желательно, если вы хотите, чтобы git поддерживал историю ветвей функций.             git merge --no-ff vs git merge В приведенном выше изображении левая сторона является примером истории git после использования git merge --no-ff, а правая сторона является примером использования git merge, где возможно слияние ff.

EDIT: предыдущая версия этого изображения указала только один родительский элемент для фиксации слияния. Слияния коммитов имеют несколько родительских коммитов, которые git использует для сохранения истории "ветки функции" и исходной ветки. Несколько родительских ссылок выделены зеленым цветом.

Ответ 4

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

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

enter image description here

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

enter image description here

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

enter image description here

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

enter image description here

Ответ 5

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

Ответ 6

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