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 будет отображать разрешение слияния следующим образом:

kdiff3

И Мельд отобразил бы это тоже:

Meld diff

То же самое для 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: Удаленный репозиторий ---> Рабочая область)

http://assets.osteele.com/images/2008/git-transport.png

Источник: Мой рабочий процесс 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'
Другие вопросы по тегам