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. Смотрите мой ответ ниже