'Git Pull Origin Mybranch' lässt lokale Mybranch N-Commits vor Origin. Warum?

92

Ich habe gerade etwas Seltsames beobachtet git pull, das ich nicht verstehe.

Am Freitag habe ich in einer lokalen Niederlassung gearbeitet. Nennen wir es mybranch. Bevor ich das Büro verließ, schob ich es zum Ursprung (das ist mein Github-Repo) : git push origin mybranch.

Gestern zu Hause habe ich pullmybranch auf meinen Laptop übertragen, etwas mehr programmiert und dann meine Änderungen wieder auf github (origin) verschoben.

Jetzt bin ich wieder bei der Arbeit und habe versucht, die Änderungen von gestern auf meine Arbeitsmaschine zu übertragen (ich habe am Wochenende nichts am lokalen Repo meines Arbeitsplatzes geändert):

git pull origin mybranch

das führte zu einem schnellen Vorlauf, was in Ordnung ist. Ich habe dann ein gemacht git status, und es sagte:

# On branch mybranch
# Your branch is ahead of 'origin/mybranch' by 6 commits.
#
nothing to commit (working directory clean)

Huh? Wie kann es sein, dass ich 6 Commits voraus bin, wenn ich es am Wochenende nicht einmal angefasst habe UND nur vom Ursprung abgezogen habe? Also habe ich a ausgeführt git diff origin/mybranchund die Unterschiede waren genau die 6 Änderungen, die ich gerade von der Fernbedienung gezogen habe.

Ich konnte dies nur durch Ausführen "beheben" git fetch origin:

From [email protected]:me/project
af8be00..88b0738  mybranch -> origin/mybranch

Anscheinend fehlten meinem lokalen Repo einige Referenzobjekte, aber wie kann das sein? Ich meine, ein Pull holt schon und ich habe an nichts anderem als an diesem Zweig gearbeitet, also sollte a git fetch originund git fetch origin mybranchdas gleiche Ergebnis haben?

Soll ich immer git pull originstatt verwenden git pull origin branchname?

Ich bin verwirrt.

Matthias
quelle
Ich habe das auch bemerkt; a git pushscheint es auch zu lösen (Berichterstattung "alles auf dem neuesten Stand").
Ben James
4
git config --get-regexp br.*kann Ihnen sagen, ob Ihre Konfiguration einen lokalen Zweig hat, der einen anderen Zweig verfolgt
VonC
3
Können Sie git config branch.master.remote yourGitHubRepo.gitIhr workRepo eingeben und (beim nächsten Mal git pull origin) überprüfen, ob der Status mit einer Vorauswarnung erhalten bleibt?
VonC
es ist nicht gesetzt (leere Ausgabe). aber git remote show originzeigt mir, dass origin auf mein GitHub-Repository verweist, also sollte das okay sein, denke ich?
Matthias
1
Git Remote allein (Anzeige der richtigen Adresse für GitHub Repo) reicht nicht aus . Um zu vermeiden, dass nach a eine Your branch is aheadWarnmeldung angezeigt wird git pull, müssen Sie zunächst auch den Remote-Namen für einen Zweig definieren . Daher mein Vorschlag: git config branch.master.remote yourGitHubRepo.gitGeben Sie a git pullund a ein git statusund prüfen Sie, ob das Problem weiterhin besteht.
VonC

Antworten:

115

git pullRuft git fetchmit den entsprechenden Parametern auf, bevor die explizit abgerufenen Köpfe (oder, falls keine vorhanden sind, der für das Zusammenführen konfigurierte Remote-Zweig) mit dem aktuellen Zweig zusammengeführt werden.

Die Syntax: git fetch <repository> <ref>Wo <ref>nur ein Zweigname ohne Doppelpunkt steht, ist ein One-Shot-Abruf, bei dem nicht alle verfolgten Zweige der angegebenen Fernbedienung standardmäßig abgerufen werden, sondern nur der benannte Zweig abgerufen wirdFETCH_HEAD .

Aktualisieren: Wenn es für Git-Versionen seit 1.8.4 einen Remote-Tracking-Zweig gibt, der den Ref verfolgt, den Sie abrufen möchten, wird der Tracking-Zweig jetzt von aktualisiert fetch. Diese Änderung wurde speziell vorgenommen, um die Verwirrung zu vermeiden, die das vorherige Verhalten verursacht hat.

Wenn Sie ausführen git pull <repository> <ref>, FETCH_HEADwird es wie oben aktualisiert und dann in Ihr HEADausgechecktes System zusammengeführt , aber keiner der Standard-Tracking-Zweige für das Remote-Repository wird aktualisiert (Git <1.8.4). Dies bedeutet, dass es lokal sieht aus wie Sie sind vor der entfernten Zweig, während in der Tat sind Sie mit ihm auf dem Laufenden.

Persönlich git fetchfolge ich immer, git merge <remote>/<branch>weil ich vor dem Zusammenführen Warnungen vor erzwungenen Aktualisierungen sehe und eine Vorschau meiner Zusammenführung anzeigen kann. Wenn ich git pulletwas mehr als ich verwenden würde, würde ich eine Ebene git pullohne die meisten Parameter erstellen der Zeit, sich auf das Richtige zu verlassen branch.<branch>.remoteund es branch.<branch>.mergezu tun.

CB Bailey
quelle
4
+1 Das ist wirklich eine gute Erklärung! Ich wusste, dass sich die Erklärung irgendwo in 'git help fetch' versteckte, konnte sie aber nicht
herausholen
1
+1. Guter Beitrag mit einem ähnlichen Ansatz wie gitster.livejournal.com/28309.html
VonC
1
Würde also git fetchnach einer git pull <repository> <ref>Behebung das Problem behoben werden, da der Abruf die Standard-Tracking-Zweige aktualisieren würde? Auch danke für diese Antwort, die
langsam
1
Ich bin auch auf dieses Problem gestoßen, und Sie müssten es tun, git fetchgefolgt von git merge origin/master master.
user1027169
3

Was gibt es git remote -v showzurück, wenn es um die Herkunft geht?

Wenn origin auf github zeigt, sollte der Status aktuell sein und nicht vor einem Remote-Repo. Zumindest mit dem Git1.6.5 verwende ich für einen schnellen Test.

Um dies zu vermeiden, definieren Sie das Remote-Repo des Hauptzweigs explizit:

$ git config branch.master.remote yourGitHubRepo.git

dann sollte a git pull origin master, gefolgt von a git status, einen sauberen Status zurückgeben (kein Voraus).
Warum? weil der get fetch origin master (im git pull origin master enthalten) nicht nur aktualisiert würde FETCH_HEAD(wie Charles Bailey in seiner Antwort erklärt ), sondern auch den "remote master branch" in Ihrem lokalen Git-Repository.
In diesem Fall scheint Ihr lokaler Master dem Remote-Master nicht mehr "voraus" zu sein.


Ich kann dies mit einem git1.6.5 testen:

Zuerst erstelle ich ein Workrepo:

PS D:\git\tests> cd pullahead
PS D:\git\tests\pullahead> git init workrepo
Initialized empty Git repository in D:/git/tests/pullahead/workrepo/.git/
PS D:\git\tests\pullahead> cd workrepo
PS D:\git\tests\pullahead\workrepo> echo firstContent > afile.txt
PS D:\git\tests\pullahead\workrepo> git add -A 
PS D:\git\tests\pullahead\workrepo> git commit -m "first commit"

Ich simuliere ein GitHub-Repo, indem ich ein nacktes Repo erstelle (eines, das von überall Push erhalten kann).

PS D:\git\tests\pullahead\workrepo> cd ..
PS D:\git\tests\pullahead> git clone --bare workrepo github

Ich füge meinem Arbeits-Repo ein Modif hinzu, das ich zum Github-Repo drücke (als Fernbedienung hinzugefügt).

PS D:\git\tests\pullahead> cd workrepo
PS D:\git\tests\pullahead\workrepo> echo aModif >> afile.txt
PS D:\git\tests\pullahead\workrepo> git ci -a -m "a modif to send to github"
PS D:\git\tests\pullahead\workrepo> git remote add github d:/git/tests/pullahead/github
PS D:\git\tests\pullahead\workrepo> git push github

Ich erstelle ein von GitHub geklontes Home-Repo, in dem ich einige Änderungen vornehme, die an GitHub gesendet werden:

PS D:\git\tests\pullahead\workrepo> cd ..
PS D:\git\tests\pullahead> git clone github homerepo
PS D:\git\tests\pullahead> cd homerepo
PS D:\git\tests\pullahead\homerepo> type afile.txt
firstContent
aModif

PS D:\git\tests\pullahead\homerepo> echo aHomeModif1  >> afile.txt
PS D:\git\tests\pullahead\homerepo> git ci -a -m "a first home modif"
PS D:\git\tests\pullahead\homerepo> echo aHomeModif2  >> afile.txt
PS D:\git\tests\pullahead\homerepo> git ci -a -m "a second home modif"
PS D:\git\tests\pullahead\homerepo> git push github

Ich klone dann Workrepo für ein erstes Experiment

PS D:\git\tests\pullahead\workrepo4> cd ..
PS D:\git\tests\pullahead> git clone workrepo workrepo2
Initialized empty Git repository in D:/git/tests/pullahead/workrepo2/.git/
PS D:\git\tests\pullahead> cd workrepo2
PS D:\git\tests\pullahead\workrepo2> git remote add github d:/git/tests/pullahead/github
PS D:\git\tests\pullahead\workrepo2> git pull github master
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (6/6), done.
From d:/git/tests/pullahead/github
 * branch            master     -> FETCH_HEAD
Updating c2763f2..75ad279
Fast forward
 afile.txt |  Bin 46 -> 98 bytes
 1 files changed, 0 insertions(+), 0 deletions(-)

In diesem Repo erwähnt der Git-Status das Master-Geing vor ' origin':

PS D:\git\tests\pullahead\workrepo5> git status
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.
#
nothing to commit (working directory clean)

Aber das ist nur originkein Github:

PS D:\git\tests\pullahead\workrepo2> git remote -v show
github  d:/git/tests/pullahead/github (fetch)
github  d:/git/tests/pullahead/github (push)
origin  D:/git/tests/pullahead/workrepo (fetch)
origin  D:/git/tests/pullahead/workrepo (push)

Aber wenn ich die Sequenz in einem Repo wiederhole, das einen Ursprung für Github hat (oder überhaupt keinen Ursprung, nur einen entfernten 'Github' definiert), ist der Status sauber:

PS D:\git\tests\pullahead\workrepo2> cd ..
PS D:\git\tests\pullahead> git clone workrepo workrepo4
PS D:\git\tests\pullahead> cd workrepo4
PS D:\git\tests\pullahead\workrepo4> git remote rm origin
PS D:\git\tests\pullahead\workrepo4> git remote add github d:/git/tests/pullahead/github
PS D:\git\tests\pullahead\workrepo4> git pull github master
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (6/6), done.
From d:/git/tests/pullahead/github
 * branch            master     -> FETCH_HEAD
Updating c2763f2..75ad279
Fast forward
 afile.txt |  Bin 46 -> 98 bytes
 1 files changed, 0 insertions(+), 0 deletions(-)
PS D:\git\tests\pullahead\workrepo4> git status
# On branch master
nothing to commit (working directory clean)

Wenn ich nur origindarauf zeigen würde github, statuswäre sauber für git1.6.5.
Es kann mit einer "Voraus" -Warnung für frühere Git sein, aber auf jeden git config branch.master.remote yourGitHubRepo.gitFall sollte eine explizit definierte in der Lage sein, dies auch mit frühen Versionen von Git zu erledigen.

VonC
quelle
Vielen Dank, dass Sie sich die Zeit genommen haben, dies zu untersuchen. Die Ursprungsfernbedienung zeigt bereits auf mein GitHub-Repo. Ich habe dieses Projekt von einer GitHub-URL geklont und mein lokaler Master-Zweig verfolgt Origin / Master. Ich bin mir ziemlich sicher, dass ich die Mybranch außerhalb des Ursprungs- / Mybranch-Zweigs erstellt habe, der sie automatisch verfolgen sollte. Aber vielleicht ist das das Problem? Dass die lokale Mybranch den Ursprung / die Mybranch nicht wirklich verfolgt? PS: Ich benutze Git 1.6.1 (über MacPorts).
Matthias
Gibt es einen git-Befehl, mit dem ich sehen kann, ob ein lokaler Zweig einen anderen Zweig verfolgt? Ich kann es nicht in den Manpages finden.
Matthias
Sie können sehen, mit welchen Remote-Zweigen verfolgt wird git remote show origin.
Ted Percival
2

Achten Sie darauf, alle Ihre Fernbedienungen (außer origindenen, die mit Ihrem ursprünglichen Klon geliefert werden) mit hinzuzufügen git remote add NAME URL? Ich habe diesen Fehler gesehen, als sie gerade zur Git-Konfiguration hinzugefügt wurden.

Pat Notz
quelle
Ich habe das gemacht, als ich das Repo geklont habe. Ich habe dies jedoch nicht bei jedem Zweig gemacht. Zum Beispiel mybranch würde ich dann zuerst vom Ursprung holen git checkout -b mybranch origin/mybranch. Laut der Manpage von git-branch ist der Ursprung / die Mybranch der Startpunkt und außerdem heißt es für --track: "... Verwenden Sie diese Option, wenn Sie immer von demselben Upstream-Zweig in den neuen Zweig ziehen, und Wenn Sie "git pull <Repository> <Refspec>" nicht explizit verwenden möchten. Dieses Verhalten ist die Standardeinstellung, wenn der Startpunkt ein Remote-Zweig ist. "
Matthias