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 года)
pull
: принять --rebase-merges
для воссоздания топологии ветки
Подобно preserve
режиму, просто передающему --preserve-merges
параметр rebase
команде, merges
режим просто передает
--rebase-merges
параметр.
Это позволит пользователям удобно перебазировать нетривиальные топологии фиксации при извлечении новых коммитов, не выравнивая их.
git rebase
На странице man теперь есть полный раздел, посвященный перебазированию истории слияниями .
Выдержка:
Существуют законные причины, по которым разработчик может захотеть воссоздать коммиты слияния: сохранить структуру ветвей (или «топологию коммитов») при работе с несколькими взаимосвязанными ветвями.
В следующем примере разработчик работает над веткой тем, которая изменяет способ определения кнопок, и над другой веткой тем, которая использует этот рефакторинг для реализации кнопки «Сообщить об ошибке».
Вывод git log --graph --format=%s -5
может выглядеть так:
* 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
Разработчик может захотеть переназначить эти коммиты на более новую master
, сохранив топологию веток, например, когда ожидается, что первая ветвь темы будет интегрирована master
гораздо раньше, чем вторая, например, для разрешения конфликтов слияния с изменениями в
DownloadButton
классе, который сделал это в master
.
Эта перебазировка может быть выполнена с помощью --rebase-merges
опции.
Смотрите коммит 1644c73 для небольшого примера:
rebase-helper
--make-script
: ввести флаг, чтобы перебазировать слияния
Секвенсор только что выучил новые команды, предназначенные для воссоздания структуры ветвей ( схожи по духу --preserve-merges
, но с существенно менее разрушенным дизайном ).
Давайте позволим rebase--helper
генерировать списки задач, используя эти команды, запускаемые новой --rebase-merges
опцией.
Для топологии фиксации, подобной этой (где HEAD указывает на C):
- A - B - C (HEAD)
\ /
D
сгенерированный список задач будет выглядеть так:
# branch D
pick 0123 A
label branch-point
pick 1234 D
label D
reset branch-point
pick 2345 B
merge -C 3456 D # C
В чем разница --preserve-merge
?
Commit 8f6aed7 объясняет:
Давным-давно этот разработчик подумал: не было бы неплохо, если бы, скажем, патчи Git для Windows поверх ядра Git можно было представить в виде зарослей ветвей и переместить их поверх ядра Git, чтобы поддерживать набор из нескольких патчей?
Оригинальная попытка ответить на это: git rebase --preserve-merges
.
Тем не менее, этот эксперимент никогда не задумывался как интерактивный вариант, и он только поддерживал себя, git rebase --interactive
потому что реализация этой команды выглядела уже очень, очень знакомо: она была разработана тем же человеком, который разработал --preserve-merges
: действительно ваш.
И под «вашим по-настоящему» автором подразумевается сам Йоханнес Шинделин ( dscho
) , который является главной причиной (вместе с несколькими другими героями - Ханнесом, Штеффеном, Себастьяном, ...), что у нас есть Git For Windows (хотя назад в тот день - 2009 - это было нелегко ).
Он работает в Microsoft с сентября 2015 года , что имеет смысл, учитывая, что Microsoft сейчас активно использует Git и нуждается в его услугах.
Эта тенденция началась в 2013 году, на самом деле, с TFS . С тех пор Microsoft управляет крупнейшим Git-репозиторием на планете ! И с октября 2018 года Microsoft приобрела GitHub .
Вы можете видеть, как Йоханнес говорит в этом видео для Git Merge 2018 в апреле 2018 года.
Некоторое время спустя другой разработчик (я смотрю на тебя, Андреас! ;-)) решил, что было бы неплохо разрешить --preserve-merges
объединение с --interactive
(с оговорками!) И сопровождающим Git (ну, временным сопровождающим Git). во время отсутствия Хунио, то есть) согласился, и именно тогда гламур --preserve-merges
дизайна начал распадаться довольно быстро и непривлекательно.
Здесь Джонатан говорит об Андреасе Швабе из Сьюз.
Вы можете увидеть некоторые из их обсуждений еще в 2012 году .
Причина? В --preserve-merges
режиме, родители коммитов слияния (или, в этом отношении, любого коммита) не были указаны явно, но
подразумевались именем коммита, переданным pick
команде .
Это сделало невозможным, например, изменить порядок коммитов .
Не говоря уже о том, чтобы перемещать коммиты между ветками или, не дай бог, разделить тематические ветки на две.
Увы, эти недостатки также помешали этому режиму (первоначальная цель которого состояла в том, чтобы обслуживать Git для нужд Windows, с дополнительной надеждой, что он может быть полезен и для других), чтобы обслуживать Git для нужд Windows.
Пять лет спустя, когда стало действительно невыносимо иметь одну громоздкую, большую серию патчей с мешаниной, частично связанных, частично не связанных патчей в Git для Windows, которые время от времени перекладывались на основные теги Git (вызывая незаслуженный гнев разработчика из злополучной
git-remote-hg
серии, которая в первую очередь отменила конкурирующий подход Git для Windows, оставленный без сопровождения позже), была действительно несостоятельной, команда « Садовые ножницы Git » была рождена : скрипт, поросенок-поддержку на верхней части интерактивной перебазироваться, который сначала определит топологию ветвлений патчей, которые будут перебазированы, создаст псевдо-список задач для дальнейшего редактирования, преобразует результат в реальный список задач (интенсивно используяexec
для «реализации» отсутствующих команд списка задач) и, наконец, воссоздания серия патчей поверх новой базовой фиксации.
(В этом патче упоминается скрипт садовых ножниц Git в коммите 9055e40 )
Это было в 2013 году.
И потребовалось около трех недель, чтобы придумать дизайн и реализовать его в виде сценария «из дерева». Излишне говорить, что для стабилизации реализации потребовалось несколько лет, и в то же время сам дизайн доказал свою надежность.
С этим патчем совершенство садовых ножниц Git приходит в git
rebase -i
себя .
Передача --rebase-merges
опции создаст список задач, который можно легко понять, и где очевидно, как изменить порядок коммитов .
Новые ветки можно вводить, вставляя label
команды и вызывая merge <label>
.
И как только этот режим станет стабильным и общепринятым, мы можем осудить ошибку проектирования, которая была--preserve-merges
.
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)
rebase --exec
: заставить его работать с --rebase-merges
Идея --exec
состоит в том, чтобы добавить exec
вызов после каждого pick
.
С момента введения fixup!
/ s quash!
коммитов эта идея была расширена для применения к «выбору, возможно, сопровождаемому цепочкой исправлений / сквоша», т.е. exec не будет вставлен между a pick
и любой из его соответствующих
строк fixup
или squash
строк.
Текущая реализация использует пакость для достижения этой цели: она предполагает , что только выбрать / Fixup / сквош команды, а затем
вставляет в exec
линию перед любым , pick
но первым, и присоединяет окончательную.
С списком дел , порожденных git rebase --rebase-merges
, эта простая реализация показывает свои проблемы: она производит точную неправильную вещь , когда есть label
, reset
и merge
команды.
Давайте изменим реализацию, чтобы сделать именно то, что мы хотим: искать
pick
строки, пропускать любые цепочки исправлений / сквошей, а затем вставлять exec
строки . Вспенить, промыть, повторить.
Примечание: мы стараемся вставлять перед комментариями строки, когда это возможно, так как пустые коммиты представлены закомментированными строками выбора (и мы хотим вставить строку exec предыдущего выбора перед такой строкой, а не после).
При этом также добавляйте exec
строки после merge
команд, потому что они по духу похожи на pick
команды: они добавляют новые коммиты.
В 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)
Убедитесь, что refs / rewritten / per-worktree
a9be29c (секвенсор: сделать ссылки, сгенерированные label
командой worktree-local, 2018-04-25, Git 2.19) добавляет refs/rewritten/
в качестве ссылочного пространства для каждого рабочего дерева.
К сожалению (мой плохой) есть пара мест, которые нуждаются в обновлении, чтобы убедиться, что это действительно для каждого рабочего дерева.
- add_per_worktree_entries_to_dir()
обновлен, чтобы удостовериться, что список ссылок просматривается для каждого рабочего дерева refs/rewritten/
вместо одного для репо.
common_list[]
обновляется, так что git_path()
возвращает правильное местоположение. Это включает в себя " rev-parse --git-path
".
Этот беспорядок создан мной.
Я начал пытаться исправить это с введением того, refs/worktree,
где все рефери будут на дерево без специальной обработки.
Неудачные рефери / переписанные были раньше рефери / рабочего дерева, так что это все, что мы можем сделать.
С 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)
path.c
: не вызывать match
функцию без значения вtrie_find()
Подписано: SZEDER Gábor
'logs / refs' - это не рабочий путь, зависящий от дерева, но поскольку commit b9317d55a3 (убедитесь, что refs / rewritten / is per-worktree, 2019-03-07, v2.22.0-rc0) ' git rev-parse --git-path
' возвращает поддельный путь если присутствует трейлинг ' /
':
$ 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
структуру данных, чтобы эффективно решить, принадлежит ли путь к общему каталогу или работает для дерева.
Так случилось, что b9317d55a3 вызвал ошибку, которая столь же стара, как и trie
сама реализация, добавленная в 4e09cf2acf (« path
: оптимизировать общую проверку dir», 2015-08-31, Git v2.7.0-rc0 - слияние, перечисленное в пакете № 2 ).
Согласно описанию комментария trie_find()
, он должен вызывать только данную функцию сопоставления 'fn' для "/ -or- \ 0-прекращенного префикса ключа, для которого три содержит значение".
Это не так: есть три места, где trie_find () вызывает функцию match, но в одном из них отсутствует проверка на наличие значения.
b9317d55a3 добавил два новых ключа к trie
:
- '
logs/refs/rewritten
' и
- '
logs/refs/worktree
', рядом с уже существующим ' logs/refs/bisect
'.
В результате появился trie
узел с путем ' logs/refs/
', которого раньше не было, и к которому не было прикреплено значение.
Запрос для ' logs/refs/
' находит этот узел, а затем обращается к этому одному месту вызова match
функции, который не проверяет существование значения, и, таким образом, вызывает match
функцию со NULL
значением.
Когда match
функция check_common()
вызывается со NULL
значением, она возвращает 0, что указывает на то, что запрашиваемый путь не принадлежит общему каталогу, что в итоге приводит к фиктивному пути, показанному выше.
Добавьте отсутствующее условие, trie_find()
чтобы оно никогда не вызывало функцию сопоставления с несуществующим значением.
check_common()
тогда больше не нужно будет проверять, что он получил ненулевое значение, поэтому удалите это условие.
Я полагаю, что нет других путей, которые могли бы вызвать подобный поддельный вывод.
AFAICT, единственная другая клавиша, приводящая к вызову функции соответствия со NULL
значением, это ' co
' (из-за клавиш ' common
' и ' config
').
Однако, поскольку они не находятся в каталоге, принадлежащем общему каталогу, ожидается, что в результате будет получен путь к конкретному рабочему дереву.
git --rebase-merges
конечном итоге заменит старыйgit --preserve-merges
. Смотрите мой ответ ниже