Документацияrebase
Git для команды довольно краткая:
--preserve-merges
Instead of ignoring merges, try to recreate them.
This uses the --interactive machinery internally, but combining it
with the --interactive option explicitly is generally not a good idea
unless you know what you are doing (see BUGS below).
Так что же на самом деле происходит, когда вы используете --preserve-merges
? Чем он отличается от поведения по умолчанию (без этого флага)? Что значит «воссоздать» слияние и т. Д.
git
git-rebase
Крис
источник
источник
git --rebase-merges
конечном итоге заменит старыйgit --preserve-merges
. Смотрите мой ответ нижеОтветы:
Как и при обычном git rebase, git with
--preserve-merges
сначала идентифицирует список коммитов, сделанных в одной части графа коммитов, а затем воспроизводит эти коммиты поверх другой части. Различия в отношении того,--preserve-merges
какие коммиты выбираются для воспроизведения и как это воспроизведение работает для коммитов слияния.Чтобы быть более ясным об основных различиях между обычным и сохраняющим слияние ребазом:
git checkout <desired first parent>
), тогда как при обычном ребазе об этом не нужно беспокоиться.Сначала я попытаюсь описать "достаточно точно", что перебазировать
--preserve-merges
делает , а затем будет несколько примеров. Конечно, можно начать с примеров, если это кажется более полезным.Алгоритм "Бриф"
Если вы действительно хотите попасть в сорняки, загрузите исходный код git и изучите файл.
git-rebase--interactive.sh
. (Rebase не является частью ядра C в Git, а написан на bash. За кулисами он делится кодом с «интерактивной перебазкой».)Но здесь я обрисую то, что я думаю в этом суть. Чтобы уменьшить количество вещей, о которых нужно подумать, я взял несколько свобод. (Например, я не пытаюсь уловить со 100% точностью точный порядок, в котором происходят вычисления, и игнорирую некоторые менее централизованные темы, например, что делать с коммитами, которые уже были выбраны между ветвями).
Во-первых, обратите внимание, что ребаз, не сохраняющий слияния, довольно прост. Это более или менее:
Ребаз
--preserve-merges
сравнительно сложен. Вот так просто, как я смог сделать это без потери вещей, которые кажутся довольно важными:Ребаз с
--onto C
аргументом должен быть очень похожим. Вместо того, чтобы начинать коммитное воспроизведение в HEAD of B, вы вместо этого начинаете коммитное воспроизведение в HEAD of C. (И используйте C_new вместо B_new.)Пример 1
Например, взять граф фиксации
m - это слияние с родителями E и G.
Предположим, что мы перебазировали тему (H) поверх главной (C), используя обычную, не сохраняющую слияния перебазу. (Например, тема оформления заказа; rebase master .) В этом случае git выберет следующие коммиты для воспроизведения:
а затем обновите граф фиксации следующим образом:
(D '- это переигранный эквивалент D и т. Д.)
Обратите внимание, что коммит слияния m не выбран для воспроизведения.
Если бы мы вместо этого сделали
--preserve-merges
ребазирование H поверх C. (Например, тема оформления заказа; rebase --preserve-merges master .) В этом новом случае git выберет следующие коммиты для воспроизведения:Теперь м был выбран для воспроизведения. Также обратите внимание, что родители слияния E и G были выбраны для включения перед коммитом m.
Вот итоговый граф коммитов:
Опять же, D '- это выбранная (то есть воссозданная) версия D. То же самое для E' и т. Д. Каждый коммит не на мастере был воспроизведен. И E, и G (родители слияния m) были воссозданы как E 'и G', чтобы служить родителями m '(после перебазирования история дерева остается прежней).
Пример 2
В отличие от обычной перебазировки, перебазирование, сохраняющее слияние, может создать несколько дочерних элементов восходящей головки.
Например, рассмотрим:
Если мы перебазируем H (тема) поверх C (master), то коммиты, выбранные для перебазировки:
И результат выглядит так:
Пример 3
В приведенных выше примерах как коммит слияния, так и два его родителя являются коммитами воспроизведения, а не исходными родителями, которые есть у исходного коммита слияния. Тем не менее, в других откатах воспроизведенный коммит слияния может закончиться с родителями, которые уже были в графе коммитов до слияния.
Например, рассмотрим:
Если мы переназначим тему на master (сохраняя слияния), то коммиты для воспроизведения будут
Переписанный граф коммитов будет выглядеть так:
Здесь воспроизводимый коммит слияния m 'получает родителей, которые ранее существовали в графе коммитов, а именно D (ГОЛОВКА хозяина) и E (один из родителей исходного коммита слияния m).
Пример 4
Сохраняющий слияние ребаз может быть запутан в некоторых случаях «пустого коммита». По крайней мере, это верно только для некоторых старых версий git (например, 1.7.8.)
Возьмите этот граф коммитов:
Обратите внимание, что оба коммита m1 и m2 должны были включать все изменения из B и F.
Если мы попытаемся сделать
git rebase --preserve-merges
H (топик) на D (мастер), то для воспроизведения будут выбраны следующие коммиты:Обратите внимание, что изменения (B, F), объединенные в m1, уже должны быть включены в D. (Эти изменения уже должны быть включены в m2, потому что m2 объединяет дочерние элементы B и F.) Следовательно, концептуально, воспроизведение m1 поверх Вероятно, D должен быть либо неактивным, либо создать пустой коммит (т. Е. Тот, в котором разница между последовательными ревизиями пуста).
Однако вместо этого git может отклонить попытку воспроизведения m1 поверх D. Вы можете получить ошибку, например, такую:
Похоже, кто-то забыл передать флаг git, но основная проблема в том, что git не нравится создавать пустые коммиты.
источник
git rebase --preserve-merges
это намного медленнее, чемrebase
без--preserve-merges
. Является ли это побочным эффектом поиска правильных коммитов? Есть ли что-нибудь, что можно сделать, чтобы ускорить это? (Кстати ... спасибо за очень подробный ответ!)Git 2.18 (Q2 2018) значительно улучшит
--preserve-merge
опцию, добавив новую опцию.«
git rebase
» Научились «--rebase-merges
» , чтобы трансплантировать всю топологию графа фиксации в других местах .(Примечание: Git 2.22, Q2 2019, фактически устарел
--preserve-merge
, а Git 2.25, Q1 2020, перестает рекламировать его вgit rebase --help
выводе " " )См совершают 25cff9f , совершают 7543f6f , совершают 1131ec9 , совершают 7ccdf65 , совершают 537e7d6 , совершают a9be29c , совершают 8f6aed7 , совершают 1644c73 , совершают d1e8b01 , совершают 4c68e7d , совершают 9055e40 , совершают cb5206e , совершают a01c2a5 , совершают 2f6b1d1 , совершают bf5c057 (25 апр 2018) от Johannes Schindelin (
dscho
) .Смотрите коммит f431d73 (25 апреля 2018 года) Стефана Беллера (
stefanbeller
) .См. Фиксацию 2429335 (25 апреля 2018) Филиппа Вуда (
phillipwood
) .(Слиты Junio C Hamano -
gitster
- в фиксации 2c18e6a , 23 мая 2018 года)git rebase
На странице man теперь есть полный раздел, посвященный перебазированию истории слияниями .Выдержка:
Смотрите коммит 1644c73 для небольшого примера:
В чем разница
--preserve-merge
?Commit 8f6aed7 объясняет:
И под «вашим по-настоящему» автором подразумевается сам Йоханнес Шинделин (
dscho
) , который является главной причиной (вместе с несколькими другими героями - Ханнесом, Штеффеном, Себастьяном, ...), что у нас есть Git For Windows (хотя назад в тот день - 2009 - это было нелегко ).Он работает в Microsoft с сентября 2015 года , что имеет смысл, учитывая, что Microsoft сейчас активно использует Git и нуждается в его услугах.
Эта тенденция началась в 2013 году, на самом деле, с TFS . С тех пор Microsoft управляет крупнейшим Git-репозиторием на планете ! И с октября 2018 года Microsoft приобрела GitHub .
Вы можете видеть, как Йоханнес говорит в этом видео для Git Merge 2018 в апреле 2018 года.
Здесь Джонатан говорит об Андреасе Швабе из Сьюз.
Вы можете увидеть некоторые из их обсуждений еще в 2012 году .
(В этом патче упоминается скрипт садовых ножниц Git в коммите 9055e40 )
Git 2.19 (Q3 2018) улучшает новую
--rebase-merges
опцию, заставляя ее работать--exec
.Параметр «
--exec
» для «git rebase --rebase-merges
» поместил команды exec в неправильные места, что было исправлено.Смотрите коммит 1ace63b (09 августа 2018 г.) и коммит f0880f7 (06 августа 2018 г.) от Johannes Schindelin (
dscho
) .(Слиты Junio C Hamano -
gitster
- в фиксации 750eb11 , 20 Aug 2018)В Git 2.22 (Q2 2019) исправлено использование refs / rewritten / иерархии для хранения промежуточных состояний перебазирования, что по сути создает иерархию для каждого рабочего дерева.
См. Коммит b9317d5 , коммит 90d31ff , коммит 09e6564 (07 марта 2019 г.) от Nguyễn Thái Ngọc Duy (
pclouds
) .(Слиты Junio C Hamano -
gitster
- в фиксации 917f2cd , 09 Apr 2019)a9be29c (секвенсор: сделать ссылки, сгенерированные
label
командой worktree-local, 2018-04-25, Git 2.19) добавляетrefs/rewritten/
в качестве ссылочного пространства для каждого рабочего дерева.К сожалению (мой плохой) есть пара мест, которые нуждаются в обновлении, чтобы убедиться, что это действительно для каждого рабочего дерева.
С Git 2.24 (Q4 2019), "
git rebase --rebase-merges
" научился управлять различными стратегиями слияния и передавать им специфические для стратегии опции.См. Сообщение 476998d (04 сентября 2019 г.) Элайджи Ньюрена (
newren
) .См. Коммит e1fac53 , коммит a63f990 , коммит 5dcdd74 , коммит e145d99 , коммит 4e6023b , коммит f67336d , коммит a9c7107 , коммит b8c6f24 , коммит d51b771 , коммит c248d32 , коммит 8c1e240 , коммит 5efed0e , коммит 68b547bac , коммит 2b547bac , совершает 6180b20 , совершают d5b581f (31 Июль 2019)Йоханнес Шинделин (
dscho
),(Слиты Junio C Hamano -
gitster
- в фиксации 917a319 , 18 Sep 2019)В Git 2.25 (Q1 2020) логика, используемая для разделения локальных ссылок и глобальных ссылок репозитория на рабочих местах, исправлена, чтобы облегчить сохранение-слияние.
См. Коммит f45f88b , коммит c72fc40 , коммит 8a64881 , коммит 7cb8c92 , коммит e536b1f (21 октября 2019 г.) от SZEDER Gábor (
szeder
) .(Слиты Junio C Hamano -
gitster
- в фиксации db806d7 , 10 ноября 2019)источник
--preserve-merges
самом деле не «сохраняет» слияния так, как вы хотите, это очень наивно. Это позволяет вам сохранить коммиты слияния и их родительские коммиты, одновременно предоставляя вам гибкость интерактивного перебазирования. Эта новая функция удивительна, и если бы не этот хорошо написанный SO ответ, я бы не знал!