git rebase, śledzenie „lokalnego” i „zdalnego”

174

Podczas wykonywania rebase git często mam trudności z ustaleniem, co dzieje się z „lokalnym” i „zdalnym” podczas rozwiązywania konfliktów. Czasami mam wrażenie, że zamieniają się stronami od jednego zatwierdzenia do drugiego.

Dzieje się tak prawdopodobnie (zdecydowanie) dlatego, że nadal nie rozumiem.

W przypadku zmiany bazy, kto jest „lokalny”, a kto „zdalny”?

(Używam P4Merge do rozwiązywania konfliktów)

Benjol
źródło
Czy to możliwe, że przeczytanie tego pomogłoby? Reszta samouczka również jest bardzo pomocna ...
ivans
Kolejny doskonały zasób git .
Nieznany
Czy stackoverflow.com/questions/2959443/… pomoże? (nie dla części „ git svn”, tylko dla części „ git rebase”)
VonC
@VonC, tak, to jest dokładnie to. Jeśli chcesz tutaj skopiować odpowiedni fragment swojej odpowiedzi,
zaznaczę
w porządku ... ugryzę;) Odpowiednie fragmenty opublikowane.
VonC,

Odpowiedzi:

244

TL; DR;

Podsumowując (jak komentuje Benubird ), kiedy:

git checkout A
git rebase   B    # rebase A on top of B
  • localsię B(przebazować na )
  • remote jest A

I:

git checkout A
git merge    B    # merge B into A
  • localjest A(scal w ),
  • remote jest B

Przełącza rebase ours(bieżąca gałąź przed rozpoczęciem rebase) i theirs(gałąź, na której ma zostać dokonana rebase).


kutschkem wskazuje, że w kontekście narzędzia scalającego GUI :

  • lokalnie odwołuje się do zatwierdzonych częściowo zmian : " ours" (gałąź upstream)
  • remote odnosi się do nadchodzących zmian : " theirs" - bieżąca gałąź przed rebase.

Zobacz ilustracje w ostatniej części tej odpowiedzi.


Inwersja podczas rebase

Zamieszanie może być związane z inwersją oursi theirspodczas rebase .
(odpowiednie fragmenty)

git rebasestrona podręcznika :

Zauważ, że scalanie rebase działa poprzez ponowne odtworzenie każdego zatwierdzenia z gałęzi roboczej na wierzchu <upstream>gałęzi.

Z tego powodu, gdy dochodzi do konfliktu scalania:

  • strona zgłaszana jako „ ours” jest dotychczas zmienionym szeregiem zaczynającym się od <upstream>,
  • a „ theirs” to gałąź robocza. Innymi słowy, strony są zamieniane.

Zilustrowana inwersja

Na fuzji

x--x--x--x--x(*) <- current branch B ('*'=HEAD)
    \
     \
      \--y--y--y <- other branch to merge

, nie zmieniamy bieżącej gałęzi 'B', więc to, co mamy, to wciąż to, nad czym pracowaliśmy (i łączymy się z inną gałęzią)

x--x--x--x--x---------o(*)  MERGE, still on branch B
    \       ^        /
     \     ours     /
      \            /
       --y--y--y--/  
               ^
              their

Na rebase:

Ale w przypadku rebase zmieniamy stronę, ponieważ pierwszą rzeczą, którą robi rebase, jest pobranie gałęzi upstream! (aby odtworzyć aktualne zatwierdzenia na górze)

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

A git rebase upstreamnajpierw zmieni HEADB na gałąź upstream HEAD(stąd zmiana „naszego” i „ich” w porównaniu do poprzedniej „bieżącej” gałęzi roboczej).

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

, a następnie rebase odtworzy „swoje” zatwierdzenia w nowej „naszej” gałęzi 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

Uwaga: pojęcie „upstream” to referencyjny zbiór danych (all repo lub, jak tutaj, oddział, który może być oddziałem lokalnym ), z którego odczytywane są dane lub do których są dodawane / tworzone nowe dane.


local” i „ remote” kontra „ mine” i „ theirs

Pandawood dodaje w komentarzach :

Dla mnie nadal pozostaje pytanie, które jest „lokalne”, a kto jest „zdalny” (ponieważ terminy „nasz” i „ich” nie są używane podczas ponownego bazowania w git, odnoszenie się do nich po prostu wydaje się bardziej zagmatwać odpowiedź) .

GUI git connectetool

Kutschkem dodaje i słusznie:

Podczas rozwiązywania konfliktów git powie coś takiego:

local: modified file and remote: modified file. 

Jestem całkiem pewien, że w tym momencie pytanie dotyczy definicji lokalnego i odległego. W tym momencie z mojego doświadczenia wynika, że:

  • lokalnie odwołuje się do zatwierdzonych częściowo zmian : " ours" (gałąź upstream)
  • remote odnosi się do nadchodzących zmian : " theirs" - bieżąca gałąź przed rebase.

git mergetoolrzeczywiście wspomina o „lokalnym” i „zdalnym” :

Merging:
f.txt

Normal merge conflict for 'f.txt':
  {local}: modified file
  {remote}: modified file
Hit return to start merge resolution tool (kdiff3):

Na przykład, KDiff3 by wyświetlać rozdzielczość scalania podobnie jak :

kdiff3

I meld też to wyświetli :

Meld diff

To samo dotyczy VimDiff , który wyświetla :

Wywołaj Vimdiff jako narzędzie do łączenia za pomocą git connectetool -t gvimdiff. Najnowsze wersje Gita wywołują Vimdiff z następującym układem okien:

+--------------------------------+
| LOCAL  |     BASE     | REMOTE |
+--------------------------------+
|             MERGED             |
+--------------------------------+
  • LOCAL:
    Plik tymczasowy zawierający zawartość pliku w bieżącej gałęzi.
  • BASE:
    Plik tymczasowy zawierający wspólną podstawę dla scalenia.
  • REMOTE:
    Plik tymczasowy zawierający zawartość pliku do scalenia.
  • MERGED:
    Plik zawierający znaczniki konfliktu.

Git wykonał tyle automatycznego rozwiązywania konfliktów, ile to możliwe, a stan tego pliku jest połączeniem obu LOCALi REMOTEznaczników konfliktów otaczających wszystko, czego Git nie mógł rozwiązać samodzielnie. Powinien zapisać wynik uchwały do tego pliku.
mergetool

VonC
źródło
13
Dla mnie nadal pozostaje pytanie, które jest „lokalne”, a kto jest „zdalny” (ponieważ terminy „nasz” i „ich” nie są używane podczas ponownego bazowania w git, odnoszenie się do nich po prostu wydaje się bardziej zagmatwać odpowiedź) . Pytanie brzmi „kto jest lokalny, a kto zdalny” - odpowiedź z pewnością wymaga użycia słów „lokalny” i „zdalny”
PandaWood
@PandaWood: „lokalny” to „bieżąca gałąź” (która staje się „ich”), „zdalna” to „gałąź nadrzędna” (która staje się „naszą”).
VonC,
3
Podsumowując: kiedy git checkout A; git rebase Blokalny jest B, zdalny jest A. Wszystko, co musiałem wiedzieć ...
Benubird
1
git jest takim klastrem użyteczności. to nie ma sensu: jeśli git checkout A; git rebase Blokalny jest B, zdalny jest . Gdybym checkout Ato ja jestem obecnie patrząc na plikach, ponieważ istnieje na A, jak to jest w żaden sposób zdalny ? (Nie mówię, że Benubird się myli; mówię, że git ma głupi UX)
Rafa
1
@VonC pewnie; moim (rantem) jest to, że nie powinno się czytać dokumentacji, przeglądać diagramów i przeglądać StackOverflow. Gdyby tylko polecenie dało jasne, jednoznaczne informacje zwrotne. Na przykład zamiast lokalnego / zdalnego / ich / naszego / mojego / twojego, po prostu pokaż {branch A}i {branch B}lub podobne.
Rafa
45

Najważniejsze

git rebase

  • LOCAL = podstawa jesteś przebazowania na
  • REMOTE = zatwierdzenia, na które przenosisz się na górze

git merge

  • LOCAL = oryginalna gałąź, do której się scalasz
  • REMOTE = inna gałąź, w której dokonujesz łączenia

Innymi słowy, LOCAL jest zawsze oryginalnym, a REMOTE jest zawsze facetem, którego commity nie istniały wcześniej, ponieważ są scalane lub zmieniane na górze

Udowodnij to!

Na pewno. Nie wierz mi na słowo! Oto prosty eksperyment, który możesz wykonać, aby samemu się przekonać.

Po pierwsze, upewnij się, że masz poprawnie skonfigurowane narzędzie git Mergetool. (Jeśli tego nie zrobiłeś, prawdopodobnie i tak nie czytałbyś tego pytania). Następnie znajdź katalog do pracy.

Skonfiguruj swoje repozytorium:

md LocalRemoteTest
cd LocalRemoteTest

Utwórz wstępne zatwierdzenie (z pustym plikiem):

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."

Utwórz zmianę na gałęzi, która nie jest master:

git checkout -b notmaster
notepad file.txt
  (add the text: notmaster)
  (save and exit)
git commit -a -m "Add notmaster text."

Utwórz zmianę w gałęzi głównej:

git checkout master
notepad file.txt
  (add the text: master)
  (save and exit)
git commit -a -m "Add master text."

gitk --all

W tym momencie Twoje repozytorium powinno wyglądać tak:

Repozytorium z podstawowym zatwierdzeniem i dwoma gałęziami z jednym zatwierdzeniem

Teraz do testu rebase:

git checkout notmaster
git rebase master
  (you'll get a conflict message)
git mergetool
  LOCAL: master
  REMOTE: notmaster

Teraz test scalania. Zamknij narzędzie Mergetool bez zapisywania zmian, a następnie anuluj rebase:

git rebase --abort

Następnie:

git checkout master
git merge notmaster
git mergetool
  LOCAL: master
  REMOTE: notmaster
git reset --hard  (cancels the merge)

Twoje wyniki powinny być takie same jak u góry.

Ryan Lundy
źródło
1
+1. To wyjaśnia local/ remoteaspekty, z którymi się zmagałem w mojej własnej odpowiedzi powyżej (która jest bardziej o inwersji oursvs theirstak czy inaczej)
VonC
3

Nie dostałem dokładnie Twojego problemu, ale myślę, że poniższy diagram rozwiązuje Twój problem. (Rebase: Zdalne repozytorium ---> Obszar roboczy)

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

Źródło: My Git Workflow

Chathuranga Chandrasekara
źródło