git rebase, отслеживая «локальный» и «удаленный» - PullRequest
155 голосов
/ 16 июня 2010

При выполнении git rebase мне часто бывает трудно понять, что происходит с «локальным» и «удаленным» при разрешении конфликтов. У меня иногда создается впечатление, что они меняются сторонами от одного коммита к другому.

Это, вероятно (определенно), потому что я до сих пор не понял правильно.

При перебазировании кто является «локальным», а кто «удаленным»?

(я использую P4Merge для разрешения конфликтов)

Ответы [ 3 ]

213 голосов
/ 16 июня 2010

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 is B

A rebase переключает ours (текущая ветвь перед началом rebase) и theirs (ветвь, поверх которой вы хотите перебазировать).


kutschkem указывает, что в контексте слияния GUI :

  • локальные ссылки на частично перебазированные коммиты : "ours" (ветка upstream)
  • Удаленный относится к входящим изменениям : «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

На ребаз:

Но на rebase , мы переключаем сторону, потому что первое, что делает rebase, это извлекает ветку upstream! (чтобы воспроизвести текущие коммиты поверх него)

x--x--x--x--x(*) <- current branch B
    \
     \
      \--y--y--y <- upstream branch

A 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

, а затем ребаз будет воспроизводить «свои» коммиты в новой «нашей» ветке 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

Примечание: понятие "upstream" является ссылочным набором данных (все репо или, как здесь, ветвь, которая может быть локальной ветвью), из которой данные или какие новые данные добавляются / создаются.


'local' и 'remote' против 'mine' и 'theirs'

Pandawood добавляет комментарии :

Для меня все еще остается вопрос, который является «локальным», а кто «удаленным» (поскольку термины «наш» и «их» не используются при перебазировании в git, ссылка на них просто кажется ответом) больше сбивает с толку).

GUI git mergetool

kutschkem добавляет, и это правильно:

При разрешении конфликтов git скажет что-то вроде:

local: modified file and remote: modified file. 

Я вполне уверен, что этот вопрос направлен на определение локального и удаленного на данном этапе. В этот момент мне кажется, что из моего опыта:

  • локальные ссылки на частично перебазированные коммиты : "ours" (ветка upstream)
  • remote относится к входящим изменениям : "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 будет отображать его тоже :

Meld diff

То же самое для VimDiff , , который отображает :

Вызовите Vimdiff как mergetool с помощью git mergetool -t gvimdiff. Последние версии Git вызывают Vimdiff со следующим расположением окна:

+--------------------------------+
| LOCAL  |     BASE     | REMOTE |
+--------------------------------+
|             MERGED             |
+--------------------------------+
  • LOCAL
    Временный файл, содержащий содержимое файла в текущей ветви.
  • BASE
    Временный файл, содержащий общую базу для слияния.
  • REMOTE
    Временный файл, содержащий содержимое файла для объединения.
  • MERGED
    Файл, содержащий маркеры конфликта.

Git выполнил максимально возможное автоматическое разрешение конфликтов, и состояние этого файла представляет собой комбинацию LOCAL и REMOTE с маркерами конфликта, окружающими все, что Git не мог разрешить сам.
mergetool должен записать результат разрешения в этот файл.

40 голосов
/ 02 мая 2014

Нижняя строка

git rebase

  • LOCAL = база, на которую вы перебираете на
  • REMOTE = коммиты, на которые вы двигаетесь вверх

git merge

  • 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

На этом этапе ваш репозиторий должен выглядеть следующим образом:

Repository with a base commit and two one-commit branches

Теперь для теста ребаз:

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)

Ваши результаты должны совпадать с показанными вверху.

3 голосов
/ 16 июня 2010

Я не получил вашу проблему точно, но я думаю, что следующая диаграмма решает вашу проблему. (Rebase: Удаленное хранилище ---> Рабочая область)

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

Источник: Мой рабочий процесс Git

...