git rebase, відстежуючи "локальний" та "віддалений"


174

Роблячи git rebase, у мене часто виникають труднощі при розробці того, що відбувається з "локальним" та "віддаленим" під час вирішення конфліктів. Іноді у мене складається враження, що вони змінюють сторони від однієї комісії на іншу.

Це, мабуть, (безумовно), тому що я досі не правильно зрозумів.

Коли звільняєте, хто "локальний", а хто "віддалений"?

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


Чи можливо, що читання цього вам допоможе? Решта підручника також дуже корисна ....
ivans

Ще один чудовий ресурс git .
Невідомий

Чи допоможе stackoverflow.com/questions/2959443/… ? (не для ' git svn' частини, просто для ' git rebase' частини)
VonC

@VonC, так, саме так. Якщо ви хочете скопіювати відповідний фрагмент вашої відповіді сюди, я поставлю галочку (я дійсно цього разу, обіцяю!)
Benjol

гаразд ... Я кусаю;) Відповідні виписки розміщені.
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(гілка, зверху якої ви хочете перезавантажити).


kutschkem вказує, що в контексті графічного інтерфейсу GUI :

  • місцеві посилання на частково знижену комісію : " ours" (гілка вище)
  • віддалене посилається на вхідні зміни : " theirs" - поточна гілка перед ребатом.

Дивіться ілюстрації в останній частині цієї відповіді.


Інверсія при ребазі

Плутанина може бути пов’язана з інверсією oursта theirsпід час ребазування .
(відповідні витяги)

git rebaseсторінка man :

Зауважте, що злиття ребаза працює, відтворюючи кожну комісію з робочої гілки вгорі <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

На ребазі:

Але на ребазі ми переходимо на сторону, тому що перше, що потрібно робити, - це перевірити верхню гілку! (для відтворення поточних комісій поверх нього)

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

, і тоді ребаза повторно повторить "свої" нові відділення "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' vs. ' mine' і ' theirs'

Пандавуд додає в коментарях :

Для мене все ще залишається питання, що є "локальним" і хто "віддаленим" (оскільки терміни "наш" і "їхній" не використовуються при перезаписі в 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 також відобразив би це :

Meld diff

Те саме для VimDiff , який відображає :

Викликайте Vimdiff як mergetool з git mergetool -t gvimdiff. Останні версії Git викликають Vimdiff із наступним макетом вікна:

+--------------------------------+
| LOCAL  |     BASE     | REMOTE |
+--------------------------------+
|             MERGED             |
+--------------------------------+
  • LOCAL:
    Тимчасовий файл, що містить вміст файла в поточній гілці.
  • BASE:
    Тимчасовий файл, що містить загальну базу для злиття.
  • REMOTE:
    Тимчасовий файл, що містить вміст файлу, який потрібно об'єднати.
  • MERGED:
    Файл, що містить маркери конфлікту.

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


13
Для мене все ще залишається питання, що є "локальним" і хто "віддаленим" (оскільки терміни "наш" і "їхній" не використовуються при перезаписі в git, посилання на них просто здається, що відповідь стає більш заплутаною) . Питання "хто місцевий та хто віддалений" - тому відповідь, безумовно, вимагає згадування слів "місцевий" та "віддалений"
PandaWood

@PandaWood: "local" - це "поточна гілка" (яка стає "їхньою"), "remote" - "гілка вище за течією" (яка стає "нашою").
VonC

3
Отже, підводячи підсумок: коли ви git checkout A; git rebase Bлокальний B, віддалений - це А. Все, що мені потрібно було знати ...
Benubird

1
git - це такий clusterfk зручності використання. це не має ніякого сенсу: коли git checkout A; git rebase Bмісцевий житель B, віддалений є . Якщо я checkout Aтоді є в даний час , дивлячись на файли , як вони існують на A, як в тому , що яким - небудь чином віддаленого ? (Я не кажу, що Benubird помиляється; я кажу, що у git є дурна UX)
Рафа

1
@ VonC впевнений; моя (рентуюча) точка - це не слід приймати документацію для читання, перегляд діаграм та перегляд StackOverflow. Якби тільки команда давала чіткі, однозначні відгуки. Наприклад, замість локальних / віддалених / їхніх / наших / моїх / ваших, просто покажіть {branch A}і{branch B} чи подібне.
Рафа

45

Суть

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

На даний момент ваш сховище має виглядати так:

Сховище з базовою коміткою та двома гілками з одною комією

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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.