Проблема в том, что означает конфликт слияния, а комментарий Чепнера является ключом к пониманию причины.Что ж, и граф коммитов , плюс тот факт, что git rebase
состоит из повторяющихся git cherry-pick
операций.Интерактивная перебазировка позволяет вам добавлять свои собственные команды между git cherry-pick
или даже менять черри-пики на что-то еще.(Первоначальный лист команд начинается с всех команд pick
, каждая из которых означает выбор вишни .)
Ваша история коммитов является сводкой вашего графа коммитов.по сути, результат посещения каждого коммита в графе коммитов, начиная с некоторой конкретной конечной точки (кончик вашей текущей ветви) и работая в обратном направлении.Если вы используете git log --graph
, вы получите потенциально важную информацию, которая не указана без --graph
, хотя в этом конкретном случае легко увидеть, что график является линейным.Итак, у вас есть всего три коммита:
A <-B <-C <-- master (HEAD)
, где A
на самом деле 4a5244b
, B
означает 7bdb5ef
, а C
означает 80384aa
(если я переписализображения правильно).Каждый коммит имеет полную, полную копию файла names.txt
.Копия, конечно, отличается в коммитах A
, B
и C
, в том, что в A
она пуста;в B
это чтение одной строки Mary
;и в C
это две строки, читающие Mary
, а затем John
Сам график возникает из-за того, что commit C
, или 80384aa
, содержит идентификатор хеша commit B
или 7bdb5ef
, внутри C
самой .Вот почему я нарисовал стрелку из C
, указывающую на B
.Git вызывает этот C
родительский коммит.Git записывает хэш-идентификатор C
в имя master
, а затем присоединяет специальное имя HEAD
к имени master
, чтобы он знал, что именно здесь git log
следуетstart, и этот коммит C
тот, который у вас есть, для работы прямо сейчас.
Когда вы запускаете git rebase -i 4a5244b
- выбираете коммит A
в качестве новой базы - Git выясняет, чтоэто означает copy commit B
и C
, поэтому он помещает их хэш-идентификаторы в список pick
команд.Затем он открывает ваш редактор на листе команд.Вы изменяете pick
на edit
, что говорит Git: Сделайте выбор вишни, а затем выйдите из перебазирования, в середине операции.
Вы не заставить выполнить перебазирование, чтобы сделать истинную копию.(Чтобы сделать это, используйте -f
или --no-ff
или --force-rebase
- все это означает одно и то же. Это не имеет значения здесь, ни в большинстве случаев.) Так что Git увидел, что была инструкция, Скопируйте B
, чтобы он шел после A
, и понял: Эй, подождите, B
уже после A
.Я просто оставлю это там. Git сделал это и остановился, оставив вас в этом состоянии:
A--B <-- HEAD
\
C <-- master
Обратите внимание, что HEAD
больше не привязан к master
: теперь он указывает напрямуюсовершить B
.Коммит C
остается, а master
по-прежнему указывает на него, но Git остановился в режиме «detached HEAD», чтобы позволить вам выполнить редактирование.
Вы вносите изменения в файл, git add
и git commit --amend
.Это делает новый коммит - мы могли бы назвать его B'
или D
, и обычно я использую B'
, поскольку обычно он очень похож на B
, но на этот раз он достаточно отличается, поэтомудавайте использовать D
.Новый коммит имеет A
в качестве родителя - это то, что делает --amend
.Git обновляет HEAD
, чтобы указать на новый коммит.Существующий коммит B
остается без изменений.Итак, теперь у вас есть:
D <-- HEAD
/
A--B
\
C <-- master
Файл names.txt
в D
имеет новое однострочное чтение Mary Shelly
.
Теперь вы запускаете git rebase --continue
, поэтому Git продолжает счто осталось в инструкцииОн состоит из pick <hash-of-C>
, что заставляет Git запускать git cherry-pick
для копирования C
.Эта копия должна идти после текущей фиксации, D
.Существующий коммит C
этого не делает, поэтому Git действительно должен выполнить эту работу на этот раз.
Вишня - это слияние - слияние как глагол, по крайней мере
To perform операция слияния - для слияния , действие - Git требуется три входа.Эти три входа: слияние, , текущий или --ours
(также иногда называемый локальный , в частности, git mergetool
) и другой или --theirs
(иногда называется remote ).Для регулярных слияний база часто немного удалена: именно там две линии коммитов расходятся.Для вишни - и для возврата, в этом отношении - база находится прямо рядом с коммитом.Основой слияния этой операции является родительский коммит C
B
!
Фактическая операция слияния состоит в запуске двух команд git diff
для всех коммитов:
git diff --find-renames <em>hash-of-base</em> <em>hash-of-ours</em>
: что мы изменили? git diff --find-renames <em>hash-of-base</em> <em>hash-of-theirs</em>
: что они изменили?
Так что теперь Git делает diffs commit B
, base, vs commit D
, ваш текущий / наш коммит.Этот diff влияет на файл names.txt
и говорит: измените одну строку, в которой написано Мэри, на две строки: одну, читающую Мэри Шелли, и одну, читающую Джона. Затем Git diff * B
vs C
, чтобы увидетьчто "они" (вы, ранее) сделали.Разница влияет на файл names.txt
и говорит: добавьте строку, читающую John в конце файла, после строки, читающей Mary.
Вот что Git показывает вам в конфликте слиянияраздел: в одном файле написано замените Мэри на Мэри Шелли , в другом - оставьте Мэри и добавьте Джона .Если хотите, вы можете сказать Git оставить в разделе конфликта слияния больше информации.Для этого установите diff.conflictStyle
на diff3
.(По умолчанию, если он не установлен, merge
.)
С настройкой diff3
вы увидите, что содержимое base - помечено |||||||
-одна строка Mary
, и что два файла из конфликтующих коммитов заменили эту базу соответственно Mary Shelly
или Mary
+ новой строкой John
.Я нахожу этот тип конфликта слияния более понятным и более простым для слияния вручную.
В любом случае, ваша задача на данный момент состоит в том, чтобы найти правильный результат - что бы это ни было - и записать его и скопировать виндексный слот ноль.Обычно вы просто редактируете грязный names.txt
, оставленный Git в вашем рабочем дереве, помещаете в него нужное содержимое и затем запускаете git add names.txt
.
Возобновление
Исправивконфликта, запустите git <em>whatever</em> --continue
, чтобы возобновить любую остановленную операцию - в этом случае, перебазировать, но это также происходит с cherry-pick и слиянием.Git будет использовать содержимое индекса, которое вы обновили с помощью git add
, чтобы сделать новый коммит, который является копией C
:
D--C' <-- HEAD
/
A--B
\
C <-- master
Достигнув конца листа команд, git rebase
сейчасВ завершение вынимаете имя master
off commit C
и вставляете его в C'
, который является последней сделанной копией, а затем снова присоединяете HEAD
:
D--C' <-- master (HEAD)
/
A--B
\
C [abandoned]