git rebase, отслеживая "локальный" и "удаленный"
Когда я делаю git rebase, мне часто трудно разобраться, что происходит с "локальным" и "удаленным" при разрешении конфликтов. У меня иногда создается впечатление, что они меняются сторонами от одного коммита к другому.
Это вероятно (определенно), потому что я все еще не понял должным образом.
При ребазинге кто "локальный", а кто "удаленный"?
(Я использую P4Merge для разрешения конфликтов)
3 ответа
TL;DR;
Подводя итог (как комментарии Benubird), когда:
git checkout A
git rebase B # rebase A on top of B
local
являетсяB
(перебазировать на),remote
являетсяA
А также:
git checkout A
git merge B # merge B into A
local
являетсяA
(слить в),remote
являетсяB
А перебазировка переключателей ours
(текущая ветвь перед началом ребазинга) и theirs
(ветка, поверх которой вы хотите сделать ребаз).
kutschkem указывает, что в контексте mergetool GUI:
- местные ссылки частично перебазированные коммиты: "
ours
" (ветвь вверх по течению) - удаленный относится к входящим изменениям: "
theirs
"- текущая ветка перед ребазой.
Смотрите иллюстрации в последней части этого ответа.
Инверсия при ребазе
Путаница может быть связана с инверсией ours
а также theirs
во время перебазирования.
(соответствующие выдержки)
git rebase
справочная страница:
Обратите внимание, что слияние rebase работает путем воспроизведения каждого коммита из рабочей ветви поверх
<upstream>
ветка.
Из-за этого, когда возникает конфликт слияния:
- сторона сообщается как
ours
это пока что перебазированная серия, начиная с<upstream>
, - а также '
theirs
это рабочая ветвь. Другими словами, стороны поменялись местами.
Инверсия проиллюстрирована
На слиянии
x--x--x--x--x(*) <- current branch B ('*'=HEAD)
\
\
\--y--y--y <- other branch to merge
мы не меняем текущую ветвь "B", поэтому то, что у нас есть, это то, над чем мы работали (и мы объединяемся из другой ветки)
x--x--x--x--x---------o(*) MERGE, still on branch B
\ ^ /
\ ours /
\ /
--y--y--y--/
^
their
На ребазе:
Но при ребазе мы переключаемся на сторону, потому что первое, что делает ребаз, это извлекает ветку upstream! (для воспроизведения текущих коммитов поверх него)
x--x--x--x--x(*) <- current branch B
\
\
\--y--y--y <- upstream branch
git rebase upstream
сначала изменится HEAD
от B до восходящей ветви HEAD
(следовательно, переключение "наших" и "их" по сравнению с предыдущей "текущей" рабочей ветвью.)
x--x--x--x--x <- former "current" branch, new "theirs"
\
\
\--y--y--y(*) <- upstream branch with B reset on it,
new "ours", to replay x's on it
, а затем rebase воспроизведет "их" коммиты в новой "нашей" ветке B:
x--x..x..x..x <- old "theirs" commits, now "ghosts", available through reflogs
\
\
\--y--y--y--x'--x'--x'(*) <- branch B with HEAD updated ("ours")
^
|
upstream branch
Примечание: понятие "восходящий поток" - это ссылочный набор данных (все репо или, как здесь, ветвь, которая может быть локальной ветвью), из которой данные считываются или в которые добавляются / создаются новые данные.
' local
' а также ' remote
"против" mine
' а также ' theirs
'
PandaWood добавляет в комментариях:
Для меня все еще остается вопрос, который является "локальным", а кто "удаленным" (поскольку термины "наши" и "их" не используются при перебазировании в git, обращение к ним просто делает ответ более запутанным),
GUI git mergetool
kutschkem добавляет, и это правильно
При разрешении конфликтов git скажет что-то вроде:
local: modified file and remote: modified file.
Я совершенно уверен, что вопрос нацелен на определение локального и удаленного на данный момент. В этот момент мне кажется, что из моего опыта:
- местные ссылки частично перебазированные коммиты: "
ours
" (ветвь вверх по течению) - удаленный относится к входящим изменениям: "
theirs
"- текущая ветка перед ребазой.
git mergetool
действительно упоминает "локальный" и "удаленный":
Merging:
f.txt
Normal merge conflict for 'f.txt':
{local}: modified file
{remote}: modified file
Hit return to start merge resolution tool (kdiff3):
Например, KDiff3 будет отображать разрешение слияния следующим образом:
И Мельд отобразил бы это тоже:
То же самое для VimDiff, который отображает:
Вызвать Vimdiff как mergetool с помощью git mergetool -t gvimdiff. Последние версии Git вызывают Vimdiff со следующей разметкой окна:
+--------------------------------+
| LOCAL | BASE | REMOTE |
+--------------------------------+
| MERGED |
+--------------------------------+
LOCAL
:
Временный файл, содержащий содержимое файла в текущей ветви.BASE
:
Временный файл, содержащий общую базу для слияния.REMOTE
:
Временный файл, содержащий содержимое файла для объединения.MERGED
:
Файл, содержащий маркеры конфликта.Git выполнил как можно больше автоматического разрешения конфликтов, и состояние этого файла является комбинацией обоих
LOCAL
а такжеREMOTE
с маркерами конфликта, окружающими все, что Git не мог разрешить сам.
mergetool
должен записать результат разрешения в этот файл.
Суть
мерзавец
- LOCAL = база, на которую вы перебираете
- REMOTE = коммиты, которые вы продвигаете на вершину
мерзавец слияния
- LOCAL = оригинальная ветвь, в которую вы сливаетесь
- REMOTE = другая ветвь, коммиты которой вы объединяете
Другими словами, LOCAL - это всегда оригинал, а REMOTE - это всегда парень, чьи коммиты не были раньше, потому что они были объединены или перебазированы сверху
Докажите это!
Конечно. Не верь мне на слово! Вот простой эксперимент, который вы можете сделать, чтобы убедиться в этом.
Во-первых, убедитесь, что у вас правильно настроен git mergetool. (Если вы этого не сделали, вы, вероятно, в любом случае не читали бы этот вопрос.) Затем найдите каталог для работы.
Настройте свой репозиторий:
md LocalRemoteTest
cd LocalRemoteTest
Создайте начальный коммит (с пустым файлом):
git init
notepad file.txt (use the text editor of your choice)
(save the file as an empty file)
git add -A
git commit -m "Initial commit."
Создайте коммит на ветке, которая не является основной:
git checkout -b notmaster
notepad file.txt
(add the text: notmaster)
(save and exit)
git commit -a -m "Add notmaster text."
Создайте коммит в основной ветке:
git checkout master
notepad file.txt
(add the text: master)
(save and exit)
git commit -a -m "Add master text."
gitk --all
На этом этапе ваш репозиторий должен выглядеть так:
Теперь для теста ребаз:
git checkout notmaster
git rebase master
(you'll get a conflict message)
git mergetool
LOCAL: master
REMOTE: notmaster
Теперь проверка слияния. Закройте ваш mergetool без сохранения каких-либо изменений, а затем отмените ребаз:
git rebase --abort
Затем:
git checkout master
git merge notmaster
git mergetool
LOCAL: master
REMOTE: notmaster
git reset --hard (cancels the merge)
Ваши результаты должны быть такими же, как показанные вверху.
Я не понял вашу проблему точно, но я думаю, что следующая диаграмма решает вашу проблему. (Rebase: Удаленный репозиторий ---> Рабочая область)
Источник: Мой рабочий процесс Git
Я тоже долго находился в замешательстве, часто принимал неверные решения и приходилось начинать заново.
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: я не эксперт по git, поэтому, если что-то не так, поправьте меня!
Думаю, я пришел к выводу, что мое замешательство было вызвано тем, что я изобразил перебазирование иначе, чем то, что многие рисуют. Вот два рисунка, которые обычно используются для описания перестановки:
--1--2--3--4--5 \ 6-7-8
а потом
-1-2-3-4-5-6-7-8
И, конечно, это один из способов нарисовать это, но мое ощущение того, что происходит с перебазированием, таково:
--1--2--3--4--5 \ 6-7-8
Что, конечно, точно так же. Но с "нашей / их" точки зрения все иначе. Во втором случае создается впечатление, что "мы" все еще "находимся" на ветке ("6-7-8") и хотим получить изменения от "мастера". Так что в этом мире "наш" по-прежнему "ветвь". И вот что меня смутило.
Но в первых "миросозерцаниях", который я полагаю, является вид Git, мы перейти к мастеру (коммит, мы хотим перебазироваться на), и оттуда мы выбираем каждый из фиксаций на ветке, в свою очередь, и применять их. Так что "наш" сначала становится "хозяином".
5
. После
6
успешно применяется, "наш" - это
6
, но на самом деле
6'
то есть "на" мастере:
--1--2--3--4--5--6' \ 6-7-8
И затем мы продолжаем то же самое с цифрой "7".
Итак, в слиянии вы "находитесь" на
8
и объедините их в новую фиксацию, но при перебазировании вы переходите к
5
и попробуйте применить различия в коммитах в ветке, когда новые коммиты там.
Итак, "истинная" картина конечного результата перебазирования должна быть такой:
-1-2-3-4-5-6 футов -7-8 футов \ 6-7-8
И после ребаза ты на
8'
. И ваша ветка тоже (я думаю!). И это можно представить (на мой взгляд) как:
--1--2--3--4--5 \ \ 6-7-8 6'-7'-8'