Я недавно столкнулся с git сценарием, с которым я не знаю, как справиться. Сначала давайте установим сцену.
Идеальный рабочий процесс
Предположим, вы поддерживаете разветвление большого проекта с открытым исходным кодом, в котором апстрим разрабатывает с использованием запросов извлечения (PR). Поскольку upstream выполняет PR, их git история имеет множество коммитов слияния.
Периодически вам придется синхронизировать c ваше дерево с upstream. Обычно это выглядит так:
git checkout -b sync
git pull upstream master
- Исправить конфликты слияния до
git add
файлов конфликтов, затем git commit
.
На этом этапе у вас есть аккуратный небольшой коммит слияния на вершине дерева. Внутри находятся все коммиты и слияния апстрима. Вы запускаете свои тесты непрерывной интеграции (CI), они проходят, и ветка объединяется с главной веткой вашего форка. Замечательно.
Проблематично c Сценарий
git checkout -b sync
git pull upstream master
- Вы исправляете конфликты слияния,
git add
и git commit
им. - Вы запускаете свой CI и тесты не пройдены, потому что апстрим что-то сломал.
- Через два дня апстрим решает проблему.
git pull upstream master
- Снова исправьте конфликты слияния.
В этот момент ваша ветвь sync
содержит две созданные вами коммиты слияния. Каждый отдельный коммит слияния содержит различные коммиты и слияния восходящего потока.
Вы можете запустить CI и выполнить слияние сейчас, но этого не следует делать, поскольку ваш первый коммит слияния будет мешать будущему git bisects
. В идеале у вас должен быть один коммит слияния, который является суммой двух коммитов слияния в последовательности.
Как можно объединить эти два коммита слияния в один, но сохраняя git историю восходящего потока?
Примечания
git rebase --preserve-merges
- это а) устарело, и б) все или ничего. Вы не можете выборочно сохранить все слияния вверх по течению, но сгладьте ваши.
Я пытался использовать git rebase --rebase-merges -i origin/master
и пометить второе слияние f
для исправления, но это не дает желаемого эффекта. У меня есть коммиты слияния для файлов, которых я никогда не трогал.
Одним из решений было бы повторить все слияние с нуля, теперь, когда апстрим исправлен. Проблема в том, что даже с rerere
это будет много работы. В этих исходных синхронизациях вы в конечном итоге исправляете вещи, которые не являются конфликтом слияния, но являются (например) ошибкой компиляции или logi c. Поскольку эти исправления являются вторичными по отношению к конфликтам слияния (отдельным коммитам), rerere
не записывает автоматические c разрешения для них.