Раздавление старых коммитов git, которые были до слияния
Я убираю git-репо, чтобы его было легче понять. До сих пор это было приватно, так что я в порядке, меняя историю.
В основном, я сводил коммиты в осмысленные сеты.
Проблема в том, что проект, в начале своей истории, был слиянием двух других проектов. У меня возникают проблемы со сдавливанием коммитов, которые были до слияния.
У меня вопрос: как мне это сделать?
Чтобы быть конкретным: у меня есть
xxxxxx * master: Latest commit
xxxxxx * another commit
xxxxxx * Merge projectA and projectB
xxxxxx |\
0000A6 | * a minor commit in project A
0000A5 | * another minor commit
И я хотел бы раздавить 0000A5 и 0000A6 вместе.
Когда я пытаюсь интерактивно выполнить перебазирование, magit (интерфейс emacs для git, который я использую) предупреждает меня: "Продолжить, несмотря на слияние в диапазоне перебаз?" и когда я продолжаю, это терпит неудачу в следующем (взятом из моей фактической работы, а не упрощенного примера выше). Я не уверен, есть ли проблема с перебазированием коммитов до слияния или с чем-то еще (строка "неотслеживаемые файлы" подозрительна, так как слияние состояло из перемещения клиентского проекта в подкаталог "client/" большего размера). проект.
Last commands done (5 commands done):
pick fb5de84 Simplified schema:
squash 96ac7ac Revert schema to full complexity
Next commands to do (29 remaining commands):
pick 4ad389a Just indentation, for readability
pick 4241835 First pass at schema
You are currently editing a commit while rebasing branch 'master' on 'ad91ab4'.
Untracked files:
client/
No changes
You asked to amend the most recent commit, but doing so would make
it empty. You can repeat your command with --allow-empty, or you can
remove the commit entirely with "git reset HEAD^".
Could not apply 96ac7ac7753c03e83b8c1296d892ce9c5fea44c7... Revert schema to full complexity
1 ответ
Кажется, здесь происходит пара вещей. Я не знаком с интерфейсом, который вы используете, но похоже, что он пытается автоматизировать перебазирование и выручку, если есть пауза, которая обычно требует ручного вмешательства, но не знает, как ее исправить.
Хотя перебазирование через слияние может быть сложным, я не думаю, что это имеет какое-либо отношение к текущей проблеме. Мне кажется, что 96ac7ac - это просто возврат fb5de84, поэтому, когда вы их сдавливаете, вы получаете пустой коммит. Это допустимо, но требует ручного вмешательства. (Перебаз остановился бы, вы бы сказали что-то вроде git commit --allow-empty
а потом продолжай.)
Вы можете подтвердить, действительно ли 96ac7ac - идеальный возврат, выполнив
git diff 96ac7ac fb5de84^
Если это так, и если ваш пользовательский интерфейс не может приспособиться к необходимому вмешательству для ребазинга, вы можете отбросить эти два коммита вместо того, чтобы раздавить их.
Следующее, с чем вы можете столкнуться, это то, что rebase попытается сделать историю линейной, если вы не предоставите --preserve-merges
вариант. Я думаю, что это то, о чем вас предупреждает ваш интерфейс, и как только вы скажете, чтобы он продолжал, я не знаю, пропускает ли этот вариант или нет.
Даже при правильных параметрах проблема с перебазированием через слияние заключается в том, что любая работа от исходного слияния за пределами автоматического разрешения по умолчанию может быть потеряна. Если необходимо ручное разрешение конфликта, то git снова остановится и будет ожидать, что вы выполните разрешение (с которым ваш интерфейс может не сотрудничать). Кроме того, в случаях, когда автоматическое разрешение будет успешным, и, тем не менее, объединение содержит изменения, внесенные вручную (к счастью, редко, но не невозможно), изменения могут быть незаметно потеряны.
Другой вариант - это "обходные" слияния (если их не так много). Если у вас есть
X --- A --- B --- M --- C <--(master)
\ /
D --- E --- F
и ты хочешь раздавить E
а также F
тогда вы могли бы сначала
git checkout F
git checkout -b temp_branch
git rebase -i D
и настроить сквош, давая вам
X --- A --- B --- M --- C <--(master)
\ /
D --- E --- F
\
EF <--(temp_branch)
Затем повторите слияние
git checkout B
git merge temp_branch
Во время этого слияния вам нужно будет воспроизвести любую работу, которая была сделана в исходном слиянии. M
, Если M
просто автоматически разрешается, затем сливаются мяу (M'
) должен также. Вы можете подтвердить, что это хорошо с
git diff M M`
Если это показывает различия, вам придется применить их вручную (что, вероятно, произошло с M
также). Вы можете заставить дерево работы выглядеть правильно и зафиксировать с помощью --amend
Я верю.
Конечно, если сигналы слияния конфликтуют, вам придется их разрешать; снова против M
должен обеспечить хорошее руководство.
Когда это будет сделано, у вас есть
<*>- M --- C <--(master)
/
X --- A --- B --- M' <--((HEAD))
\ /
D --------- EF <--(temp_branch)
\
E --- F -<*>
(Извините за странные обозначения, график сошел с ума от меня; <*>
s должен быть одной строкой из F
в M
, Но не волнуйтесь, мы собираемся распутать это.)
Очистите и сделайте окончательную перезагрузку коммитов после слияния:
git branch --delete temp_branch
git rebase --onto M` M master
получая
X --- A --- B --- M' --- C` <--(master)
\ /
D --------- EF
Вы можете видеть, что это может быть довольно утомительным, особенно если есть много слияний и / или слияний, содержащих ручные разрешения конфликтов или другие неавтоматические изменения. Проверка окончательного состояния является ключевым моментом. (Вы можете использовать reflog, чтобы помочь с этим, или пометить оригинальный главный HEAD перед началом всего этого. Например, используя reflog:
git diff master master@{1}
Эта запись может стать грязной, если вы также хотите проверить каждый исторический коммит...)
Еще одним вариантом будет вместо того, чтобы переделать слияние и перебазировать работу после слияния на него, вы можете раздавить E
а также F
а затем настроить git filter-branch
с --parent-filter
переучить M
от B , F
в B , EF
, Увидеть git filter-branch
документация для деталей о том, как использовать --parent-filter
(хотя вам придется немного подправить пример, чтобы справиться со слиянием). Это может сработать, потому что вы хотите, чтобы у результата было неизменное дерево.