Раздавление старых коммитов 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 (хотя вам придется немного подправить пример, чтобы справиться со слиянием). Это может сработать, потому что вы хотите, чтобы у результата было неизменное дерево.

Другие вопросы по тегам