Что делает опция --merge в Git rebase? - PullRequest
6 голосов
/ 29 апреля 2019

Страница man git-rebase (1) говорит:

-m
--merge
Используйте стратегии слияния для перебазирования.[...]

Но, конечно, можно также столкнуться с "конфликтами слияния" без использования опции --merge.Так что и в этом случае должна быть какая-то «стратегия слияния» для обработки этих конфликтов.

Какая разница делает опцию --merge для перебазирования.

Кажетсябыть довольно фундаментальным: для rebase --merge Git хранит свои рабочие файлы в папке с именем $GIT_DIR/rebase-merge (как это делается для интерактивных перебазирования).Если опция --merge не используется (а перебазирование не является интерактивным), эта папка называется $GIT_DIR/rebase-apply.

1 Ответ

8 голосов
/ 29 апреля 2019

В одном предложении то, что -m или --merge делает для git rebase, состоит в том, чтобы убедиться, что rebase использует git cherry-pick внутри.

Флаг -m для принудительного выбора вишни часто, но не всегда, излишним.В частности, любая интерактивная перебазировка всегда использует cherry-pick.* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *.Как и -k, как отмечено ниже.

Long (или, по крайней мере, более длинный)

Rebase имеет длинную историю в Git: первые операции rebase были выполнены путем форматирования каждого коммита набыть перебазирован в патч, затем применить патч к другому коммиту.То есть изначально git rebase был в основном просто:

branch=$(git symbolic-ref --short HEAD)
target=$(git rev-parse ${onto:-$upstream})
git format-patch $upstream..HEAD > $temp_file
git checkout $target
git am -3 $temp_file
git checkout -B $branch HEAD

(за исключением обработки аргументов, всей проверки ошибок и того факта, что git am может останавливаться с ошибкой, требующей ручного исправленияи git rebase --continue; кроме того, приведенный выше сценарий является моей версией с ограниченной читабельностью и, вероятно, не очень похож на исходный сценарий).

Этот вид перебазирования справляется с большинством случаев достаточно хорошо.Наиболее распространенный случай, когда он плохо обрабатывает , включает перебазирование некоторых переименований файлов.Он также не может скопировать «пустой» коммит - тот, чей патч пуст, т. Е. git format-patch не разрешено пропускать часть патча.

Эти пустые коммиты обычно опускаются git rebase, даже когдаиспользуя -m;Вы должны добавить -k, чтобы сохранить их.Чтобы сохранить их, git rebase должен переключиться на вариант выбора вишни, если это еще не сделано.

Чтобы передать -s или -X аргументов, rebase должен вызывать git cherry-pick вместо git am, поэтому для любого из этих флагов также требуется вариант cherry-pick.

Использование git format-patch никогда не приводит к обнаружению переименования.Следовательно, если поток копируемых вами коммитов должен иметь обнаружение переименования в отношении HEAD, флаг -m очень важен.В качестве конкретного примера рассмотрим следующую серию коммитов:

          B--C--D   <-- topic
         /
...--o--A--E--F--G   <-- mainline

Предположим, что разница от A до B, B до C и C до D равнавсе обрабатывается в файле с именем lib-foo.ext.Но в коммите F этот файл переименован в , вместо lib/foo.ext.git format-patch из A..D покажет изменения, которые должны быть внесены в файл lib-foo.ext, ни одно из которых не будет корректно применено для фиксации G, поскольку файла lib-foo.ext нет.Перебазирование в целом завершится неудачей.

A git cherry-pick commit B, когда HEAD идентифицирует commit G, однако найдет переименование и применит A -vs- B изменяет версию lib/foo.ext в коммите G:

          B--C--D   <-- topic
         /
...--o--A--E--F--G   <-- mainline
                  \
                   B'   <-- HEAD [detached]

Следующий вишневый пик, C, в то время как HEAD идентифицирует B', обнаружит, что B-to- C изменение на libfoo.ext должно применяться к переименованному lib/foo.ext, и последний вишневый пик D сделает то же самое, так что перебазировка будет успешной.

Код обнаружения переименования идет медленно, поэтому ребаз, который имеет no , переименовывает в «делать», и «пустые» коммиты не сохраняются, может работать намного быстрее при запуске через систему git format-patch | git am.Это единственный способ, с помощью которого оригинальный метод лучше, чем вариант «черешни»: он быстрее в ограниченных случаях.(Однако улучшение скорости происходит только тогда, когда имеется много переименованных кандидатов , но ни один из них не является действительным переименовывает , либо ни один из них не имеет значения.)

(Примечание: аргумент -3, или --3way, чтобы использовать более длинное написание, говорит git am передать этот флаг каждому git apply, где apply будет пытаться выполнить трехстороннее слияние, если необходимо,использование хэшей больших двоичных объектов в строке index в diff. В некоторых условиях кажется, что может быть достаточным для обработки переименованных файлов, в частности, если хэш больших двоичных объектов точно совпадает. Метод cherry-pick делаетполное обнаружение переименования, которое обрабатывает неточные совпадения; -3 не может этого сделать. См. также В чем разница между git cherry-pick и git format-patch | git am? , как отметил Юрген .)

...