Ответ 1
При слиянии (включая перезагрузку, что является частным случаем повторного "слияния" внутри), есть два "головы" (два конкретных ответвления). Назовите эти your-branch
и origin/their-branch
:
G - H -------- <-- HEAD=your-branch
/ \
... - E - F M <-- desired merge commit [requires manual merge]
\ /
I - J - K - L <-- origin/their-branch
Эта точка обычно (и неудивительно) запутывает, хотя, когда она помечена как это, достаточно ясно.
Ухудшись, однако, git использует --ours
и --theirs
для обозначения двух головных коммиттов во время слияния, причем "наш" является тем, на котором вы были (commit H
), когда вы запускали git merge
, а "их" - это, ну, их (commit L
). Но когда вы делаете переустановку, обе головы меняются на противоположные, так что "наш" - это голова, которую вы перегружаете, т.е. Их обновленный код и "их" - это фиксация, которую вы в настоящее время перезагружаете, т.е. собственный код.
Это связано с тем, что rebase фактически использует серию операций вишневого захвата. Вы начинаете с той же картины:
G - H <-- HEAD=your-branch
/
... - E - F
\
I - J - K - L <-- origin/their-branch
Что нужно сделать git здесь, чтобы скопировать эффект коммитов G
и H
, т.е. git cherry-pick
commit G
, а затем сделать это снова с commit H
. Но для этого git должен сначала переключиться на фиксацию L
, внутренне (используя режим "снятый HEAD" ):
G - H <-- your-branch
/
... - E - F
\
I - J - K - L <-- HEAD, origin/their-branch
Теперь он может запустить операцию перезаписи, сравнивая деревья для commits F
и G
(чтобы увидеть, что вы изменили), а затем сравните F
vs L
(чтобы убедиться, что часть вашей работы уже в L
) и вносите любые изменения, еще не находящиеся в L
, и добавьте их. Это операция "слияния" внутри.
G - H <-- your-branch
/
... - E - F G' <-- HEAD
\ /
I - J - K - L <-- origin/their-branch
Если слияние не идет хорошо, HEAD
остается в commit L
(поскольку commit G'
еще не существует). Таким образом, да, HEAD
является главой своей ветки развития - по крайней мере, сейчас.
Как только существует копия G
, HEAD
перемещается в G'
и git пытается скопировать изменения из H
таким же образом (diff G
vs H
, то diff F
vs G'
и объединить результаты):
G - H <-- your-branch
/
... - E - F G' - H' <-- HEAD
\ /
I - J - K - L <-- origin/their-branch
Опять же, если слияние не удалось и вам нужна помощь, вы останетесь с HEAD
, указывающим на G'
вместо H'
, поскольку H'
еще не существует.
Как только слияния всех преуспевают и совершают G'
и H'
существуют, git удаляет метку your-branch
из commit H
и вместо этого указывает на commit H'
:
G - H
/
... - E - F G' - H' <-- HEAD=your-branch
\ /
I - J - K - L <-- origin/their-branch
и вы теперь переустановлены, а HEAD
- это снова то, что вы ожидаете. Но во время rebase HEAD
- это либо их ответвление (commit L
), либо один из новых коммитов, скопированных и присоединенных к их ветки; и --ours
означает, что ветвь вырастает в конце L
, а --theirs
означает скопированную фиксацию - из (G
или H
выше).
(В основном это git, демонстрирующий необработанный механизм того, как он делает то, что он делает, что довольно часто происходит в git.)