Чем результат перебазирования может отличаться от результата слияния?

В одной из статей GitHub я прочитал следующее:

Вы не можете автоматически перебазировать и объединить на GitHub, когда: Перебазирование коммитов считается "небезопасным", например, когда перебазирование возможно без конфликтов слияния, но приведет к отличному результату, чем слияние.

Мне не ясно, как перебазирование может привести к другому результату, чем слияние.

Кто-нибудь может объяснить, как это возможно?


Ссылка на оригинальную статью: https://help.github.com/articles/about-pull-request-merges/

1 ответ

Решение

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

Хитрость заключается в том, что поскольку rebase-копии фиксируют, но пропускают слияния, нам нужно отбросить слияние, разрешение которого не является простой композицией его предшественников. Чтобы у этого слияния не было конфликтов, я думаю, что это должно быть "злое слияние", так что это то, что я положил в сценарий.

График, который мы строим, выглядит так:

  B   <-- master
 /
A--C--E   <-- branch
 \   /
  \ /
   D   <-- br2

Если вы на master (ваш совет коммит B) и ты git merge branch это сочетает в себе изменения от A vs- B с теми, кто от A vs- E, Полученный график:

  B-----F   <-- master
 /     /
A--C--E   <-- branch
 \   /
  \ /
   D   <-- br2

и содержание коммита F определяются теми из A, B, а также E,

Если вы на branch (ваш совет коммит E) и ты git rebase master эта копия передает C а также D в каком-то порядке (не понятно, какой именно). Он полностью пропускает коммит E, Полученный график:

  B   <-- master
 / \
A   C'-D'   <-- branch
 \
  D   <-- br2

(оригинал C а также E доступны только через reflogs и ORIG_HEAD). перемещение master в ускоренном порядке, верхушка master становится совершенным D', Содержание коммита D' определяются путем добавления изменений, извлеченных из C а также D в B,

Поскольку мы использовали "злое слияние", чтобы внести изменения в E которые появляются ни в одном C ни D эти изменения исчезают.

Вот сценарий, который создает проблему (обратите внимание, это делает временный каталог tt что он уходит в текущий каталог).

#! /bin/sh

fatal() {
    echo fatal: "$@" 1>&2; exit 1
}

[ -e tt ] && fatal tt already exists

mkdir tt && cd tt && git init -q || fatal failed to create tt repo

echo README > README && git add README && git commit -q -m A || fatal A
git branch branch || fatal unable to make branch
echo for master > bfile && git add bfile && git commit -q -m B || fatal B

git checkout -q -b br2 branch || fatal checkout -b br2 branch
echo file for C > cfile && git add cfile && git commit -q -m C || fatal C
git checkout -q branch || fatal checkout branch
echo file for D > dfile && git add dfile && git commit -q -m D || fatal D
git merge -q --no-commit br2 && git rm -q -f cfile && git commit -q -m E ||
    fatal E
git branch -D br2
git checkout -q master || fatal checkout master

echo merging branch
git merge --no-edit branch || fatal merge failed
echo result is: *

echo removing merge, replacing with rebase of branch onto master
git reset -q --hard HEAD^ || fatal reset failed
git checkout -q branch || fatal switch back to master failed
git rebase master || fatal rebase failed
echo result is: *

echo removing rebase as well so you can poke around
git reset --hard ORIG_HEAD
Другие вопросы по тегам