git rebase, отслеживая «локальный» и «удаленный»

174

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

Это вероятно (определенно), потому что я все еще не понял должным образом.

При ребазинге кто «локальный», а кто «удаленный»?

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

Benjol
источник
Возможно ли, что чтение этого поможет вам? Остальная часть урока также очень полезна ...
ivans
Еще один отличный ресурс Git .
Неизвестно
Поможет ли stackoverflow.com/questions/2959443/… ? (не для части ' git svn', только для части ' git rebase')
VonC
@VonC, да, это именно так. Если вы хотите скопировать соответствующий фрагмент вашего ответа здесь, я отмечу его (я действительно буду на этот раз обещаю!)
Бенджол
все хорошо ... я укушу;) Соответствующие выдержки выложены.
VonC

Ответы:

244

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(ветка, поверх которой вы хотите перебазировать).


Кучкем указывает, что в контексте mergetool с графическим интерфейсом :

  • локальные ссылки на частично перебазированные коммиты : " 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

На ребазе:

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

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

A git rebase upstreamсначала изменит HEADB на восходящую ветвь 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'

Пандавуд добавляет в комментариях :

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

GUI git mergetool

кучкем добавляет, и справедливо так

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

local: modified file and remote: modified file. 

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

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

VonC
источник
13
Для меня все еще остается вопрос, который является «локальным», а кто «удаленным» (поскольку термины «наш» и «их» не используются при перебазировании в git, обращение к ним просто делает ответ более запутанным) , Вопрос в том, кто является локальным, а кто удаленным, поэтому для ответа, безусловно, необходимо упомянуть слова «локальный» и «удаленный»
PandaWood
@PandaWood: «local» - это «текущая ветвь» (которая становится «их»), «remote» - «восходящая ветка» (которая становится «нашей»).
VonC
3
Итак, git checkout A; git rebase B
подведем
1
Git такой кластер FK из удобства использования. это не имеет никакого смысла: когда git checkout A; git rebase Bместный житель B, удаленный является . Если я , checkout Aто я имею в настоящее время , глядя на файлы , как они существуют на A, как в том , что каким - либо образом удаленного ? (Я не говорю, что Benubird не прав; я говорю, что у git тупой UX)
Рафа
1
@VonC уверен; Моя (напыщенная) мысль о том, что не нужно читать документацию, просматривать диаграммы и просматривать StackOverflow. Если бы только команда давала четкие, однозначные отзывы. Например, вместо локальных / удаленных / их / наших / моих / ваших, просто покажите {branch A}и / {branch B}или подобное.
Рафа
45

Суть

мерзавец

  • 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)

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

Райан Ланди
источник
1
+1. Это проясняет local/ remoteаспекты, с которыми я боролся в моем собственном ответе выше (который больше касается инверсии oursvs в theirsлюбом случае)
VonC
3

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

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

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

Чатуранга Чандрасекара
источник