Git 2.18 (второй квартал 2018 г.) значительно улучшит параметр --preserve-merge
, добавив новый параметр.
«git rebase
» научился «--rebase-merges
» переносить всю топологию графа фиксации в другое место.
(Примечание: Git 2.22, второй квартал 2019 г., фактически не рекомендует --preserve-merge
и Git 2.25, Q1 2020, перестает рекламировать его в выводе "git rebase --help
")
Подобно режиму preserve
, просто передавая параметр --preserve-merges
команде rebase
, режим merges
просто передает параметр --rebase-merges
.
rebase --exec
: заставить работать с --rebase-merges
Это позволит пользователям удобно перемещать нетривиальные топологии коммитов при извлечении новых коммитов, не сглаживая их.
git rebase
на странице руководства теперь есть полный раздел история со слияниями.
Извлекать:
Есть законные причины, по которым разработчик может захотеть воссоздать коммиты слиянием: чтобы сохранить структуру ветвей (или «топологию фиксации») при работе с несколькими взаимосвязанными ветвями.
В следующем примере разработчик работает над тематической веткой, которая реорганизует способ определения кнопок, и над другой тематической веткой, которая использует этот рефакторинг для реализации кнопки «Сообщить об ошибке».
Результат git log --graph --format=%s -5
может выглядеть следующим образом :
Разработчик может захотеть перенастроить эти коммиты на более новую master
, сохранив топологию веток, например, когда ожидается, что первая ветка темы будет интегрирована в master
намного раньше, чем вторая, скажем, для разрешения конфликтов слияния с изменениями в DownloadButton
класс, который превратился в master
.
* Merge branch 'report-a-bug'
|\
| * Add the feedback button
* | Merge branch 'refactor-button'
|\ \
| |/
| * Use the Button class for all buttons
| * Extract a generic Button class from the DownloadButton one
Эту перебазировку можно выполнить с помощью параметра --rebase-merges
.
См. Небольшой пример commit 1644c73:
Секвенсор только что изучил новые команды, предназначенные для воссоздания структуры ветвей (по духу похожую на --preserve-merges
, но с существенно менее нарушенным дизайном).
Убедитесь, что refs / rewritten / относится к рабочему дереву
Позвольте rebase--helper
генерировать списки задач с использованием этих команд, запускаемых новой опцией --rebase-merges
.
Для такой топологии фиксации (где HEAD указывает на C):
сгенерированный список дел будет выглядеть так:
- A - B - C (HEAD)
\ /
D
В чем разница с --preserve-merge
?
Commit 8f6aed7 объясняет:
# branch D
pick 0123 A
label branch-point
pick 1234 D
label D
reset branch-point
pick 2345 B
merge -C 3456 D # C
Давным-давно этот здесь разработчик подумал: было бы неплохо, если бы, скажем, патчи Git для Windows поверх основного Git можно было представить в виде чащи веток и переустановить поверх основного Git, чтобы поддерживать набор серий патчей, который можно выбрать только из вишенки?
Первоначальная попытка ответить на этот вопрос была такой: git rebase --preserve-merges
.
Однако этот эксперимент никогда не задумывался как интерактивный вариант, и он использовался только для git rebase --interactive
, потому что реализация этой команды выглядела уже очень, очень знакомой: она была разработана тем же человеком, который разработал --preserve-merges
: ваш покорный слуга.
Под словом «ваш покорный слуга» автор называет себя: Йоханнес Шинделин (dscho
) , кто является основной причиной (с несколькими другими героями - Ханнесом, Штеффеном, Себастьяном и т. д.), что у нас есть Git для Windows (хотя в те времена - 2009 год - это было непросто).
Он работает в Microsoft с сентября 2015 г., что имеет смысл, учитывая, что Microsoft сейчас активно использует Git и нуждается в его услугах.
Это тенденция фактически началась в 2013 году с TFS. С тех пор Microsoft управляет самый большой репозиторий Git на планете! И, с октября 2018 г., Microsoft приобрела GitHub а>.
Вы можете увидеть, как Йоханнес выступает в этом видео для Git Merge 2018 в апреле 2018 года.
Некоторое время спустя какой-то другой разработчик (я смотрю на тебя, Андреас! ;-)) решил, что было бы неплохо разрешить сочетание --preserve-merges
с --interactive
(с оговорками!) И сопровождающим Git (ну, временный Сопровождающий Git во время отсутствия Джунио согласился, и именно тогда очарование дизайна --preserve-merges
начало распадаться довольно быстро и неприглядно.
Здесь Джонатан говорит об Андреасе Швабе из Suse.
Вы можете увидеть некоторые из обсуждений в 2012 году.
Причина? В режиме --preserve-merges
родители коммита слияния (или, если на то пошло, любого коммита) не были указаны явно, но были подразумеваются переданным именем коммита. к команде pick
.
Это сделало невозможным, например, переупорядочивание коммитов.
Не говоря уже о перемещении коммитов между ветвями или, не дай бог, разделении тематических веток на две.
Увы, эти недостатки также помешали этому режиму (изначально предназначавшемуся для удовлетворения потребностей Git для Windows с дополнительной надеждой, что он может быть полезен и для других) удовлетворить потребности Git для Windows.
Пять лет спустя, когда стало действительно неприемлемо иметь одну громоздкую, большую сборную серию патчей частично связанных, частично несвязанных патчей в Git для Windows, которые время от времени переустанавливались на основные теги Git (что вызвало незаслуженный гнев разработчика из злополучной серии git-remote-hg
, в которой впервые был исключен конкурирующий подход Git для Windows, который позже был оставлен без сопровождающего) был действительно несостоятельным, "Садовые ножницы Git" родились: сценарий, подкрепленный поверх интерактивной перебазировки, который сначала определит топологию ветвей патчей, которые будут перебазированы, создаст список псевдо-задач для дальнейшего редактирования преобразуйте результат в настоящий список задач (интенсивно используя команду exec
для «реализации» отсутствующих команд списка задач) и fina Я воссоздайте серию патчей поверх нового базового коммита.
(Скрипт садовых ножниц Git упоминается в этом патче в commit 9055e40)
Это было в 2013 году.
И потребовалось около трех недель, чтобы придумать дизайн и реализовать его в виде нестандартного скрипта. Излишне говорить, что на стабилизацию реализации потребовалось довольно много лет, при этом сама конструкция зарекомендовала себя добротной.
С этим патчем все преимущества садовых ножниц Git проявляются непосредственно в git
rebase -i
.
При передаче параметра --rebase-merges
создается список задач, который можно легко понять и где очевидно, как чтобы изменить порядок коммитов.
Новые ветки могут быть введены путем вставки label
команд и вызова merge <label>
.
И как только этот режим станет стабильным и общепринятым, мы сможем отказаться от ошибки дизайна, которая была --preserve-merges
.
Git 2.19 (3 квартал 2018 г.) улучшает новую опцию --rebase-merges
, заставляя ее работать с --exec
.
Параметр "--exec
" для "git rebase --rebase-merges
" помещал команды exec в неправильные места, что было исправлено.
См. commit 1ace63b (09 августа 2018 г.) и commit f0880f7 (06 августа 2018 г.) от Йоханнес Шинделин (dscho
).
(Объединено Junio C Hamano - gitster
- < / a> в commit 750eb11, 20 августа 2018 г.)
Идея --exec
- добавлять вызов exec
после каждого pick
.
path.c
: не вызывайте функцию match
без значения в trie_find()
С момента появления fixup!
/ squash!
коммитов эта идея была расширена, чтобы применить ее к «выбору, за которым, возможно, следует цепочка исправлений / сквоша», т.е. exec не будет вставляться между pick
и любой из соответствующих строк fixup
или squash
.
Текущая реализация использует грязный трюк для достижения этого: она предполагает, что есть только команды pick / fixup / squash, а затем вставляет строки exec
перед любыми pick
, кроме первой, и добавляет последнюю.
Со списками задач, сгенерированными git rebase --rebase-merges
, эта простая реализация показывает свои проблемы: она выдает совершенно неправильную вещь, когда есть команды label
, reset
и merge
.
Давайте изменим реализацию, чтобы сделать именно то, что мы хотим: ищем pick
строки, пропускаем все исправления / цепочки сквоша, а затем вставляем exec
строку. Вспенить, промыть, повторить.
Примечание: мы стараемся вставлять перед строками комментариев, когда это возможно, поскольку пустые коммиты представлены закомментированными строками выбора (и мы хотим вставить строку exec предыдущего выбора перед такую строчку, а не потом).
При этом также добавьте exec
строки после merge
команд, потому что они похожи по духу на команды pick
: они добавляют новые коммиты.
Git 2.22 (второй квартал 2019 г.) исправляет использование refs / rewritten / hierarchy для хранения промежуточных состояний перебазирования, что по своей сути создает иерархию для каждого рабочего дерева.
См. commit b9317d5, совершить 90d31ff, a> (7 марта 2019 г.) Нгуен Тхай Нгок Дуй (pclouds
).
(Объединено Junio C Hamano - gitster
- в commit 917f2cd, 09 апреля 2019 г.)
a9be29c (секвенсор: создание ссылок, сгенерированных командой label
worktree-local, 2018-04- 25, Git 2.19) добавляет refs/rewritten/
в качестве ссылочного пространства для каждого рабочего дерева.
К сожалению (моя неудача), есть пара мест, которые необходимо обновить, чтобы убедиться, что оно действительно для каждого рабочего дерева.
common_list[]
обновляется, поэтому git_path()
возвращает правильное местоположение. Это включает "rev-parse --git-path
".
- add_per_worktree_entries_to_dir()
обновлен, чтобы убедиться, что в списке ссылок учитывается refs/rewritten/
для каждого рабочего дерева, а не для каждого репо.
Этот беспорядок создан мной.
Я начал пытаться исправить это с введением refs/worktree,
, где все ссылки будут привязаны к каждому рабочему дереву без специальных обработок.
К сожалению, refs / rewritten были перед refs / worktree, так что это все, что мы сможет сделать.
- Предупреждение: начиная с Git 2.18 (второй квартал 2018 г., 5 лет спустя)
--preserve-merge
в конечном итоге заменит старый git rebase
. См. мой ответ ниже
В Git 2.24 (4 квартал 2019 г.) «git rebase --rebase-merges
» научился управлять различными стратегиями слияния и передавать им параметры, специфичные для стратегии.
В Git 2.25 (Q1 2020) логика, используемая для разделения локальных ссылок рабочего дерева и глобальных ссылок репозитория, является фиксированной, чтобы упростить сохранение-слияние.
См. commit f45f88b, зафиксировать c72fc40, , совершить 7cb8c92, commit e536b1f (21 октября 2019 г.) от (SZEDER Gá szeder
).
(Объединено Junio C Hamano - gitster
- в commit db806d7, 10 ноября 2019 г.)
Подписано: SZEDER Gábor
'logs / refs' не является рабочим путем для конкретного дерева, но поскольку commit b9317d55a3 ( Убедитесь, что refs / rewritten / относится к рабочему дереву, 2019-03-07, v2.22.0-rc0) 'git rev-parse --git-path
' возвращал фиктивный путь, если присутствует конечный '/
':
"logs/refs/worktree
" рядом с уже существующим "logs/refs/bisect
".
В результате получился узел trie
с путем "logs/refs/
", которого раньше не было и к которому не было прикреплено значение.
A запрос для 'logs/refs/
' находит этот узел, а затем обращается к тому сайту вызова функции match
, которая не проверяет наличие значения, и, таким образом, вызывает функцию match
с NULL
в качестве значения.
Мы используем структуру данных trie
, чтобы эффективно решить, принадлежит ли путь к общему каталогу или работает на основе дерева.
Как оказалось, b9317d55a3 вызвал ошибку, которая устарела, как и сама реализация trie
, добавленная в 4e09cf2acf ("path
: оптимизировать общую проверку каталога", 31.08.2015, Git v2 .7.0-rc0 - слияние, перечисленное в пакет № 2).
$ git -C WT/ rev-parse --git-path logs/refs --git-path logs/refs/
/home/szeder/src/git/.git/logs/refs
/home/szeder/src/git/.git/worktrees/WT/logs/refs/
Согласно комментарию, описывающему trie_find()
, он должен вызывать указанную функцию сопоставления 'fn' только для префикса с завершением / -или- \ 0 ключа, для которого дерево содержит значение.
Это неверно: есть три места, где trie_find () вызывает функцию сопоставления, но в одном из них отсутствует проверка существования значения.
b9317d55a3 добавил два новых ключа в trie
:
Когда функция match
check_common()
вызывается со значением NULL
, она возвращает 0, что указывает на то, что запрошенный путь не принадлежит общему каталогу, что в конечном итоге приводит к фиктивному пути, показанному выше.
Добавьте отсутствующее условие в trie_find()
, чтобы оно никогда не вызывало функцию сопоставления с несуществующим значением.
- '
logs/refs/rewritten
', and
- Я заметил, что
--preserve-merge
намного медленнее, чем git rebase
без --rebase-merges
. Это побочный эффект поиска правильных коммитов? Есть ли что-нибудь, что можно сделать, чтобы это ускорить? (Кстати… спасибо за очень подробный ответ!)
check_common()
больше не нужно будет проверять, получено ли значение, отличное от NULL, поэтому удалите это условие.
Я считаю, что нет других путей, которые могли бы вызвать подобный ложный вывод.
AFAICT единственный другой ключ, приводящий к вызову функции сопоставления со значением NULL
, - это 'co
' (из-за ключей 'common
' и 'config
').
Однако, поскольку они не находятся в каталоге, который принадлежит к общему каталогу, ожидается, что результирующий рабочий путь зависит от дерева.
pull
: принять --rebase-merges
, чтобы воссоздать топологию ветки
rebase-helper
--make-script
: введите флаг для перебазирования слияний
person
VonC
schedule
27.05.2018