Warum ist die Bedeutung von "uns" und "ihnen" mit git-svn umgekehrt?

90

Ich benutze git-svn und habe festgestellt, dass, wenn ich nach dem Ausführen von a einen Zusammenführungskonflikt beheben muss git svn rebase, die Bedeutung von --oursund --theirsOptionen für z git checkout. B. umgekehrt ist. Das heißt, wenn es einen Konflikt gibt und ich die vom SVN-Server stammende Version behalten und die lokal vorgenommenen Änderungen wegwerfen oursmöchte , muss ich sie verwenden , wenn ich dies erwarten würde theirs.

Warum ist das so?

Beispiel:

mkdir test
cd test
svnadmin create svnrepo
svn co file://$PWD/svnrepo svnwc
cd svnwc
echo foo > test.txt
svn add test.txt
svn ci -m 'svn commit 1'
cd ..
git svn clone file://$PWD/svnrepo gitwc
cd svnwc
echo bar > test.txt 
svn ci -m 'svn commit 2'
cd ..
cd gitwc
echo baz > test.txt 
git commit -a -m 'git commit 1'
git svn rebase

git checkout --ours test.txt
cat test.txt 
# shows "bar" but I expect "baz"

git checkout --theirs test.txt
cat test.txt 
# shows "baz" but I expect "bar"
Marc Liyanage
quelle
Jut hat meine Antwort mit vielen Diagrammen aktualisiert, um die "unsere" und "ihre" Seite besser zu veranschaulichen.
VonC
1
Siehe auch github.com/git/git/commit/…
VonC

Antworten:

230

Das scheint im Einklang mit dem zu stehen, was eine Rebase bewirkt.

  • git svn rebase holt Revisionen vom SVN-Elternteil des aktuellen HEAD und ruft die aktuelle (nicht an SVN gebundene) Arbeit dagegen zurück.

  • git rebaseerwähnt:
    Beachten Sie, dass eine Rebase-Zusammenführung funktioniert, indem jedes Commit aus dem Arbeitszweig über dem <upstream>Zweig wiedergegeben wird.
    Aus diesem Grund, wenn ein Zusammenführungskonflikt auftritt:

    • Die Seite, die als unsere gemeldet wurde, ist die bisher überarbeitete Serie, beginnend mit<upstream> :
    • und ihnen gehört der Arbeitszweig .
      Mit anderen Worten, die Seiten werden getauscht .

git rebase wiederholt jedes Commit aus dem Arbeitszweig über dem <upstream>Zweig.

Wenn Sie beide Definitionen in Einklang bringen:

  • Die von SVN kommenden Commits sind diejenigen, auf denen lokale Git-Commits wiedergegeben werden. Sie sind Teil der "bisher neu basierten Serie" und werden als "unsere" bezeichnet (in Ihrem Fall die test.txtDatei mit dem barInhalt).
  • Der Arbeitszweig (der Git-Commits enthält, die SVN nicht bekannt sind, in Ihrem Fall die test.txtDatei mit dem bazInhalt) ist "ihr", und jeder dieser lokalen Git-Commits wird wiedergegeben.

Mit anderen Worten, SVN oder nicht:

  • Der <upstream>Zweig " " (auf dem alles wiedergegeben wird und der Teil der bisher neu festgelegten Commits ist) ist " unser ".
  • Was wiederholt wird (der Arbeitszweig), ist " ihnen ".

Guter Mnemonik-Tipp von CommaToast :

was auch immer HEAD zeigt, ist "unser"

(und das erste, was a git rebase upstreamtut, um den upstreamZweig auszuchecken, auf dem Sie die Basis neu erstellen möchten: HEAD bezieht sich auf upstream- oursjetzt.)


Die Verwirrung kommt wahrscheinlich von der Rolle der Arbeitsbranche in einem Klassiker git merge.
Wenn Sie zusammenführen:

  • Der "Arbeitszweig" ist derjenige, der das enthält, was "bisher zusammengeführt" wurde, und wird als "unser" betrachtet.
  • während das andere Commit das darstellt, was - nicht wiederholt, sondern - über dem Arbeitszweig zusammengeführt und als "ihr" betrachtet wird.

Wie in der git rebaseManpage erwähnt, bedeutet eine Zusammenführung während einer Rebase, dass die Seite getauscht wird.


Eine andere Möglichkeit, dasselbe zu sagen, besteht darin, Folgendes zu berücksichtigen:

  • Was wir in der ausgecheckten Filiale haben, ist ' unsere ',
  • Was wir hatten (und zusammengeführt oder wiederholt werden), gehört ihnen .

Bei einer Fusion :

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

Wir ändern den aktuellen Zweig 'B' nicht. Wir haben also immer noch das, woran wir gearbeitet haben (und wir verschmelzen aus einem anderen Zweig).

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

Bei einer Rebase wechseln wir jedoch die Seite, da das erste, was eine Rebase bewirkt, das Auschecken des Upstream-Zweigs ist! (um die aktuellen Commits darüber abzuspielen)

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

A wechselt git rebase upstreamzuerst HEADvon B in den vorgelagerten Zweig HEAD(daher der Wechsel von "unserem" und "ihrem" im Vergleich zum vorherigen "aktuellen" Arbeitszweig).

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

, und dann wird die Rebase "ihre" Commits für den neuen "unser" B-Zweig wiedergeben:

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

Der einzige zusätzliche Schritt git svn rebasebesteht darin, dass zuerst ein SVN-Abruf für den Git-Remote-Zweig ausgeführt wird, der SVN-Commits darstellt.
Sie haben zunächst:

x--x--x--x--x(*) <- current branch B, "ours" for now.
    \                                   
     \
      \--y--y--y <- SVN tracking branch, "theirs for now"

Sie aktualisieren zuerst den SVN-Verfolgungszweig mit neuen Commits, die von SVN stammen

x--x--x--x--x(*) <- current branch B, still "ours", not for long
    \                                   
     \
      \--y--y--y--y'--y' <- SVN tracking branch updated

, dann schalten Sie den aktuellen Zweig auf die SVN-Seite (die zu "unserer" wird)

x--x--x--x--x <- for "B", now "their" during the rebase
    \                                   
     \
      \--y--y--y--y'--y'(*) <- SVN tracking branch updated, and branch B: 
                               now "ours" (this is "what we now have")

, bevor Sie die Commits erneut abspielen, an denen Sie gearbeitet haben (die aber jetzt während dieser Rebase "ihnen" gehören)

x--x..x..x..x <- old "theirs" commits, now "ghosts", available through reflogs
    \
     \
      \--y--y--y--y'--y'--x'--x'--x'(*) <-  branch B with HEAD updated ("ours")
                      ^
                      |
        upstream SVN tracking branch
VonC
quelle
9
Wow, was für eine großartige Antwort, danke! Ich muss diese Bemerkung in der git rebaseManpage völlig übersehen haben ...
Marc Liyanage
@epologee: Gern geschehen. Es ist auch nützlich, wenn Sie nur Git verwenden, um zu verstehen, was während einer Rebase oder einer Zusammenführung vor sich geht. Und es ergänzt die Upstream-Definition: stackoverflow.com/questions/2739376/…
VonC
5
Mein Gott!!! Welche Art von Drogen nahm Torvalds? Das ist viel zu kompliziert! Git ist ein sehr gefährliches Werkzeug. Sie können Ihre gesamte Arbeit leicht zerstören, wenn Sie versuchen, externes Wissen oder Ihre Intuition zu nutzen. Die Entwicklung von Software ist ins Wurmloch geraten!
ATL_DEV
@ user148298 An dieser Funktion ist nichts auszusetzen. Sie müssen all diese Dinge nicht wissen, es sei denn, Sie sind ein Git-Experte. Und wenn Sie erweiterte Funktionen benötigen, müssen Sie diese zuerst lernen.
Earth Engine