Разрешить слияние несвязанных историй в git rebase

Когда вы хотите перебазировать ветку с сохранением коммитов, вы передаете --preserve-merges флаг. Когда вы объединяете несвязанную историю в git, вам нужно передать --allow-unrelated-histories флаг.

Если вы делаете git rebase --preserve-merges когда существующее слияние происходит из несвязанной истории, происходит сбой:

фатальный: отказ от слияния несвязанных историй

Если вы попытаетесь git rebase --preserve-merges --allow-unrelated-histories это терпит неудачу с:

ошибка: неизвестный параметр 'allow-unrelated-историй'

Есть ли другой способ сказать rebase, чтобы разрешить слияние?


Изменить: вот минимальное воспроизведение: https://github.com/vossad01/rebase-unrelated-merge-reproduction

Воспроизвести заказ master затем выполните:

git rebase --preserve-merges --onto origin/a-prime HEAD~2

3 ответа

Решение

Метод грубой силы состоит в том, чтобы форсировать общий корень - поскольку вы пытаетесь перебазировать корни без истории содержимого, сделайте одноразовый пустой коммит и скажите git, что он является родителем историй, которые вы объединяете:

git rev-list --all --max-parents=0 \
| awk '{print $0,empty}' empty=`:|git mktree|xargs git commit-tree` \
> .git/info/grafts
git rebase here
rm .git/info/grafts

Когда git rebase Сбой при слиянии не отменяет перебазирование, поэтому у вас есть возможность вмешаться вручную.

Если вы хотите решить эту проблему вручную, вы можете выполнить слияние следующим образом:

git merge --allow-unrelated ORIGINAL_BRANCH_THAT_WAS_MERGED --no-commit
git commit -C ORIGINAL_MERGE_COMMIT
git rebase --continue

В идеале Git мог бы справиться с этим без ручного вмешательства.

Чтобы воспроизвести мастер проверки, выполните:

git rebase --preserve-merges --onto origin/a-prime HEAD~2 -i

Документы git-rebase говорят не объединять -i а также --preserve-merges,

[--preserve-merges] использует механизм --interactive для внутреннего использования, но объединение его с опцией --interactive в явном виде, как правило, не очень хорошая идея, если вы не знаете, что делаете (см. ошибки ниже).

Но даже без -i это все еще терпит неудачу с fatal: refusing to merge unrelated histories,

Часть проблемы HEAD~2 является прямым предком origin/a-prime, Ваше тестовое репо выглядит так:

1 [master]
|
2
|\
| |  3 [origin/a-prime]
| |  |
| 4 / [origin/b]
|  /
| /
|/
5 [origin/a]

HEAD~2 из master это 5. origin/a-prime 3. Ваша команда эквивалентна:

git rebase -p --onto 3 5

5 является прямым предком 3, так что команда не имеет особого смысла. Если это вообще сработает, это сделает что-то странное.


случаи, с которыми я сталкивался несколько раз в последнее время, были связаны с перемещением документации проекта из GitHub Wiki на страницы GitHub (когда веб-сайт уже существует).

Это неуместное использование rebase. Rebase превращает параллельные истории в линейные истории, в основном притворяясь, что один набор изменений был сделан поверх другого набора все время. Это хорошо для таких вещей, как поддержание ветвей функций в актуальном состоянии, пока они работают, ведение бухгалтерии и рецензирование проще, если у вас нет группы промежуточных коммитов слияния, которые ничего не делают, кроме обновления ветки. Это просто шум для любого, кто читает код и фиксирует историю в будущем.

Но когда у вас есть две действительно расходящиеся истории, лучше оставить их как расходящиеся истории. Объединение их рассказывает правильную историю: веб-сайт и документы разрабатывались отдельно, но затем объединялись в одно целое.

1 - 3 - 5
         \
  2 - 4 - 6 - 7 - 8 [master]

Вы можете посмотреть их отдельно в топологическом порядке (8, 7, 6, 5, 3, 1, 4, 2), используя git log --topo-order или вы можете посмотреть на них с чередованием в порядке дат (8, 7, 6, 5, 4, 3, 2, 1), git log дефолт. Визуализатор истории как gitk или GitX покажет оба заказа одновременно.

Перебрасывание одного поверх другого говорит неправду: мы работали над сайтом, а затем мы работали над документацией, а затем в какой-то момент (момент, который вам нужно найти), и по какой-то причине мы работали над сайтом и документация вместе.

1 - 3 - 5 - 2 - 4 - 6 - 7 - 8 [master]

Это теряет жизненно важную информацию и делает загадкой, почему некоторые изменения были сделаны более трудными в будущем.

Сделайте слияние, это правильная вещь.

Единственный способ синхронизировать две расходящиеся ветки - это объединить их вместе, в результате чего получится дополнительный коммит слияния и два набора коммитов, содержащих одинаковые изменения (исходные и те, что из вашей перебазированной ветки). Излишне говорить, что это очень запутанная ситуация.

Итак, прежде чем бежать git rebase, всегда спрашивайте себя: "Кто-нибудь еще смотрит на эту ветку?" Если ответ положительный, уберите руки с клавиатуры и подумайте о неразрушающем способе внесения изменений (например, git revertкоманда). В противном случае вы можете переписывать историю сколько угодно раз.

Ссылка: https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing

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