481 Stimmen

git: Dein Zweig ist um X Commits voraus

Wie kommt das eigentlich zustande?

Ich arbeite im Moment nur an einem Repo, also ist dies mein Arbeitsablauf:

  1. Dateien ändern
  2. Commit
  3. Wiederholen Sie 1-2, bis Sie zufrieden sind.
  4. Zum Master schieben

Wenn ich dann eine git status wird mir mitgeteilt, dass mein Zweig um X Übertragungen voraus (vermutlich die gleiche Anzahl von Übertragungen, die ich vorgenommen habe). Liegt es daran, dass beim Pushen des Codes die lokal zwischengespeicherten Dateien (in den .git-Ordnern) nicht wirklich aktualisiert werden? git pull scheint diese seltsame Meldung zu "beheben", aber ich bin immer noch neugierig, warum es passiert, vielleicht benutze ich git falsch?


einschließlich der Verzweigung, die in der Nachricht gedruckt wird

Mein lokaler Zweig ist dem Master voraus

Wohin schieben/ziehen Sie den aktuellen Zweig?

Ich schiebe auf GitHub und ziehe auf den Computer, an dem ich gerade arbeite. Meine lokale Kopie ist immer auf dem neuesten Stand, da ich der einzige bin, der daran arbeitet.

es prüft nicht wirklich das entfernte Projektarchiv

Das habe ich mir auch gedacht, aber ich wollte mich vergewissern, dass ich es richtig verstanden habe.

Übergeben Sie dem Programm zusätzliche Argumente?

Keine, die ich sehen kann. Vielleicht läuft bei mir eine komische Konfiguration ab?

$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
nothing to commit (working directory clean)

28voto

Anatolii Pazhyn Punkte 1426

Ich hatte dieses Problem auf meinem Bühnenserver, wo ich nur Pulls mache. Und Hard-Reset half mir zu reinigen HEAD auf die gleiche wie remote.

git reset --hard origin/master

Das habe ich jetzt wieder:

On branch master
Your branch is up-to-date with 'origin/master'.

26voto

Jemand sagte, Sie könnten Ihre Nachricht falsch verstehen, das tun Sie nicht. Dieses Problem hat tatsächlich etwas mit Ihrer <project>/.git/config Datei. Darin befindet sich ein Abschnitt, der dem folgenden ähnelt:

[remote "origin"]
    url = <url>
    fetch = +refs/heads/*:refs/remotes/origin/*

Wenn Sie die fetch-Zeile aus der .git/config-Datei Ihres Projekts entfernen, wird die Meldung "Your branch is ahead of 'origin/master' by N Unannehmlichkeiten zu vermeiden.

Das hoffe ich zumindest :)

22voto

torek Punkte 381305

Anmerkung: Diese besondere Frage ist zu dem Zeitpunkt, zu dem ich diese Antwort schreibe, schon ziemlich alt. Sie wurde drei Jahre vor der ersten Veröffentlichung einer Version von Git veröffentlicht, die viele dieser Probleme behoben hat. Es lohnt sich jedoch, eine moderne Antwort zusammen mit Erklärungen hinzuzufügen. Die bisher akzeptierte Antwort schlägt vor zu laufen git fetch -p , 1 was eine gute Idee ist, wenn auch seltener requis in diesen Tagen. Es war viel notwendiger, bevor Git Version 1.8.2 herauskam; dieses Git wurde drei Jahre nach der ursprünglichen Frage veröffentlicht.


1 Le site -p o --prune ist nicht erforderlich und wird in der verlinkten Antwort nur in Klammern vorgeschlagen. Lesen Sie in den längeren Abschnitten unten nach, was sie bewirkt.


Wie kommt das eigentlich zustande?

Die ursprüngliche Frage lautet:

Wie kommt das eigentlich zustande?

Le site este in Frage steht, ist die Tatsache, dass nach git push origin master läuft der OP git status und sieht die Nachricht On branch master gefolgt von Your branch is ahead of 'origin/master' by 1 commit. Um die Frage richtig zu beantworten, müssen wir sie in Teile zerlegen.

Erstens hat jede (lokale) Zweigstelle eine stromaufwärts Einstellung

Diese Behauptung ist eigentlich ein bisschen zu stark. Jeder Ihrer eigenen lokalen Zweige, in Ihrem eigenen Git-Repository, peut tienen eine Einstellung, die Git als stromaufwärts . Oder dieser Zweig kann haben pas de stromaufwärts. Alte Versionen von Git waren nicht sehr konsequent darin, dies als stromaufwärts Einstellung, aber im modernen Git ist es konsistenter. Wir haben auch git branch --set-upstream-to y git branch --unset-upstream zum Setzen oder Löschen eines vorgelagerten Stromkreises.

Diese --set-upstream-to y --unset-upstream beeinflussen die aktuelle Branche . Der aktuelle Zweig ist derjenige, in dem Sie sich on wenn git status sagt on branch xyzzy oder was auch immer dort steht. Sie wählen. diesen Zweig mit git checkout oder - seit Git 2.23 - git switch . 2 Der Zweig, den Sie überprüft haben, ist derjenige, in dem Sie sich befinden. 3

Wenn Sie --unset-upstream diese beseitigt der aktuelle Zweig ist der Upstream. Wenn kein Upstream vorhanden ist, wird die Meldung über den Vorsprung, Rückstand oder die Abweichung nicht mehr angezeigt. Aber diese Meldung soll nützlich sein, also sollten Sie wahrscheinlich nicht einfach den Upstream entfernen, damit sie nicht mehr erscheint. (Sie können aber gerne ignorieren. die Botschaft - es ist keine Fehler wenn Sie es nicht nützlich finden.)

Wenn Sie git branch --set-upstream-to=origin/xyzzy die den Upstream des aktuellen Zweigs auf origin/xyzzy . Für einen Zweig namens xyzzy wäre dies die typische richtige Einstellung. Einige Handlungen zur Erstellung von Zweigen automatisch setzen den (typischerweise korrekten) Upstream, andere nicht. Wenn Sie also eine Operation zum Erzeugen eines Zweigs verwendet haben, die automatisch den richtigen Upstream setzt, müssen Sie nichts tun. Wenn Sie einen anderen Upstream wollen, oder wenn Sie eine Verzweigungserstellungsoperation verwendet haben, die pas de Upstream, können Sie damit den Upstream ändern.

Die Dinge, die Sie im Vorfeld festlegen können, sind:

  • eine andere Ihrer eigenen (lokalen) Filialen: git branch --set-upstream-to=experiment macht Ihr eigenes Lokal experiment den vorgelagerten Bereich der aktuellen Verzweigung oder
  • einer Ihrer Namen zur Fernverfolgung , wie zum Beispiel origin/main o origin/master o origin/xyzzy . Dies sind die Namen, die von git branch -r . Git nennt diese Namen von Zweigstellen mit Fernverfolgung (Ich lasse hier gerne das Wort "Zweig" weg), und wir werden gleich noch mehr darüber sprechen.

Die vorausgehende, nachfolgende, aktuelle oder abweichende Nachricht, die git status druckt, ergibt sich aus der Ausführung des etwas magisch anmutenden Befehls:

git rev-list --count --left-right $branch...$upstream

donde $branch ist die aktuelle Zweigstelle Name, und $upstream ist die Zeichenkette aus seiner vorgelagerten Einstellung (aus git branch --set-upstream-to oben). Hier stehen drei Punkte zwischen den beiden Namen, und die --count , --left-right und drei Punkte sind erforderlich, um git rev-list um die beiden Zahlen auszuspucken.


2 Wenn Sie Git 2.23 oder höher haben, ist es eine gute Idee, zu git switch weil es einige knifflige Probleme vermeidet git checkout Verhaltensweisen, die in der Vergangenheit Anfänger in Schwierigkeiten gebracht haben (und gelegentlich sogar Git-Experten zum Stolpern brachten). Wenn Sie jedoch an Folgendes gewöhnt sind git checkout können Sie es so lange verwenden, wie Sie wollen, da es noch unterstützt wird. Das eigentliche Problem ist im Grunde, dass git checkout zu stark war und die Arbeit unerwartet zerstören konnte. Die neue git switch ist absichtlich weniger leistungsfähig und wird das nicht tun; die Operationen "meine Arbeit absichtlich zerstören" wurden in git restore .

3 Es ist möglich, sich auf pas de Zweig, in dem, was Git als abgetrennter KOPF Modus. Wenn Sie den git checkout können Sie plötzlich in diesen Modus versetzt werden (obwohl eine große, beängstigende Warnung ausgegeben wird, wenn Sie also die beängstigende Warnung nicht sehen, hat es das nicht getan), aber wenn Sie git switch müssen Sie ermöglichen detached-HEAD-Modus mit git switch --detach . Es gibt nichts falsch In diesem Modus müssen Sie nur aufpassen, dass Sie keine neuen Übertragungen verlieren. Es ist leicht, sie zu verlieren, wenn man nicht aufpasst. Im normalen Modus verliert Git keine neuen Übertragungen auf diese Weise.

Wenn Sie sich im abgetrennten HEAD-Modus befinden, haben Sie per Definition keinen Upstream, weil Sie keinen Branch haben, und nichts von dem, was in dieser Frage steht, trifft zu.


Erreichbarkeit

Dieser Teil ist etwas technisch und ich werde vieles davon auf eine Website auslagern, Denken wie (ein) Git . Ich werde es hier jedoch so zusammenfassen: Filialnamen (wie main o xyzzy ) und Namen zur Fernverfolgung ( origin/main , origin/xyzzy ) sind, wie Git findet bindet. Bei Git dreht sich alles um die verpflichtet sich . Die Namen Ihrer Zweige sind nur wichtig für finden. Ihre Commits. Wenn Sie sie nicht finden können, haben Sie natürlich ein Problem, also sind die Namen Ihrer Zweige wichtig. Aber der Schlüssel ist Erreichbarkeit so lautet der Fachbegriff.

Jede Übergabe in einem Git-Repository ist nummeriert, mit einem großen, hässlichen hexadezimal Zeichenfolge aus Buchstaben und Ziffern. Dies ist der Name der Übertragung Hash-ID und das ist die Art und Weise, wie Git wirklich findet die Übergabe.

Jeder Commit enthält zwei Dinge: einen vollständigen Schnappschuss jeder Quelldatei (in einer speziellen, komprimierten, Git-ifizierten und de-duplizierten Form), und einige Informationen über den Commit selbst: Metadaten wer sie wann und warum durchgeführt hat (z. B. die Logmeldung). In den Metadaten enthält jeder Commit die Commit-Nummer(n) eines oder mehrerer früherer Commits. Das bedeutet, dass ein Commit einen anderen - früheren - Commit finden kann.

Como Denken wie (ein) Git Das ist ein bisschen wie bei einem Eisenbahnzug. Es ist großartig, wenn man auf den Zug, der Sie in diesem Fall automatisch zu allen früheren Haltestellen zurückbringt. Aber zuerst müssen Sie Ihren Weg finden zu einen Bahnhof. Ein Git-Zweigname tut dies: Er enthält die Hash-ID des neueste Commit für Ihren Zweig.

Wir können das so zeichnen:

... <-F <-G <-H   <--branch

Der Name der Niederlassung branch enthält die Hash-ID der neueste verpflichten. Wir sagen, dass der Name zeigt auf die Übergabe. Was auch immer das für eine große, hässliche Hash-ID ist, wir haben einfach den Buchstaben H hier zu vertreten.

H ist ein echter Commit, d.h. er enthält einen gespeicherten Schnappschuss - Ihre Dateien - und einige Metadaten. In den Metadaten speichert Git die Hash-ID einer früher verpflichten. Wir nennen diesen früheren Commit G . Wir sagen, dass H zeigt auf G . Git kann finden H durch den Zweignamenszeiger, und das gibt Git Zugriff auf den Commit, einschließlich der Metadaten, so dass Git jetzt die Hash-ID des früheren Commits hat G .

G ist natürlich auch eine tatsächliche Übergabe: Sie enthält einen gespeicherten Schnappschuss und einige Metadaten. In den Metadaten für G Git speichert die Hash-ID eines früheren Commits F . Wir sagen, dass G zeigt auf F und jetzt kann Git finden F unter Verwendung dieser gespeicherten Hash-ID.

Dies wiederholt sich ewig, oder besser gesagt, bis wir zur allerersten Übertragung kommen. Dieser Commit (vermutlich würden wir ihn als A hier) nicht auf eine frühere Übertragung verweisen, da es keine frühere Übertragung gibt.

Dieses Konzept der Erreichbarkeit ist im Grunde eine Zusammenfassung dessen, was passiert, wenn wir bei der Übergabe beginnen H nach dem Namen des Zweigs gefunden branch und arbeiten rückwärts. Wir erreichen Engagement H die nach hinten reicht, um die G die zurückreicht bis F , und so weiter.

Verzweigungsnamen und Namen für die Fernverfolgung

Wie wir gerade festgestellt haben, ist eine Niederlassungsname enthält die rohe Hash-ID einer Übertragung. Damit kann Git finden. die sich verpflichten. Es gibt noch eine weitere Besonderheit bei einer Zweigstelle Name allerdings nicht.

Wenn Sie git checkout o git switch zu erhalten auf eine Verzweigung, und machen Sie dann eine neu Übertragen, Git aktualisiert automatisch die gespeicherte Hash-ID des Zweignamens . Das heißt, nehmen wir an, wir haben eine Reihe von Übertragungen wie diese:

...--F--G--H   <-- xyzzy (HEAD)

Wir sind "on" Zweig xyzzy die ich gerne mit dem speziellen Namen bezeichnete HEAD dazu. Dies ist nützlich, wenn mehr als ein Zweigname im Diagramm vorhanden ist. Beachten Sie, dass H ist zur Zeit die neueste verpflichten. Aber jetzt werden wir eine weitere machen, auf die übliche Weise.

Diese neue Übertragung erhält eine neue, eindeutige, große, hässliche hexadezimale Hash-ID, genau wie jede andere Übertragung. Git stellt sicher, dass der neue Commit auf den Commit rückwärts zeigt H da dies die Übergabe ist, die wir für machen. die neue Übergabe. Wir verwenden den Buchstaben I um diese neue Übergabe zu repräsentieren. Zeichnen wir sie ein:

...--F--G--H   <-- xyzzy (HEAD)
            \
             I

Dieses Bild ist eigentlich mitten im Commit: Git hat die I wird aber nicht mit dem git commit Aktion noch nicht. Stellen Sie sich diese Frage: Wie werden wir finden. übergeben. I später? Wir werden seine Hash-ID brauchen. Wo können wir eine Hash-ID speichern?

Wenn Sie sagen würden: in einem Zweignamen Sie haben Recht. Der richtige Name für den Zweig - jedenfalls was Git betrifft - ist der, in dem Sie sich gerade befinden. Das ist der, den wir angehängt haben HEAD in dieser Zeichnung. Und nun, als letzter Teil von git commit schreibt Git I Hash-ID in den Namen xyzzy . Dies macht es sinnvoll, sich I , etwa so:

...--F--G--H
            \
             I   <-- xyzzy (HEAD)

und jetzt gibt es keinen Grund mehr für den Knick in der Zeichnung, also können wir ihn geradebiegen:

...--F--G--H--I   <-- xyzzy (HEAD)

So funktionieren die Namen der Zweige. Letztendlich ist es ziemlich einfach: Man muss sich nur mehrere Dinge auf einmal vorstellen. Der Name findet die Übergabe. Er findet die neueste verpflichten. Von dort aus arbeitet Git rückwärts denn jede Übertragung findet eine früher verpflichten.

Was ist mit den Namen für die Fernverfolgung? Nun, der Trick dabei ist, dass Ihr Git mit einem anderen Git spricht. Jeder Git hat seine eigene Filialnamen. Sie haben Ihr master o main Sie haben ihre . Sie haben Ihr xyzzy Zweigstelle und sie können auch ihre haben.

Ihr Git かもしれない immer und immer wieder ihre Git anrufen und sie nach den Namen ihrer Filialen fragen. Das ist allerdings nicht sehr effizient und funktioniert nicht, wenn man vom Internet abgeschnitten ist. 4 In jedem Fall tut Git das nicht. Stattdessen ruft Ihr Git deren Git auf und erhält von ihnen eine Liste mit allen Namen ihrer Zweige und deren Hash-IDs, Ihr Git nimmt diese Namen und Hash-IDs und speichert sie in Ihr Repository. Dies geschieht, wenn Sie git fetch . 5

Allerdings gibt es ein Problem. Ihre main o master oder ihre xyzzy wenn sie eine haben, bedeutet das nicht unbedingt, dass die dieselbe festlegen als Ihr main o master o xyzzy . Die Lösung ist jedoch einfach: Git nimmt einfach ihre Zweigstelle Namen und verwandelt ihn in Ihren Name der Fernverfolgung .

Si origin 's main o master o xyzzy verschoben hat, führen Sie einfach git fetch o git fetch origin vielleicht mit --prune . Ihr Git ruft deren Git auf. Sie geben ihre Branch-Namen und Commit-Hash-IDs an. Dein Git holt sich, wenn nötig, neue Commits von ihnen: Commits, die sie haben, die du nicht hast. Dann wandelt Ihr Git deren Zweigstelle Namen in Ihr Fernverfolgung Namen und erstellt oder aktualisiert Ihre Remote-Tracking-Namen, um sich zu merken, wo ihre Zweignamen zeigt, in dem Moment, in dem Sie diese git fetch .

Wenn Sie --prune Dies gilt für den Fall, dass sie gelöscht Name(n) der Zweigstelle(n). Nehmen wir an, sie hätten einen Zweig namens oldstuff . Sie haben es früher bekommen, also haben Sie origin/oldstuff in Ihren Namen für die Fernverfolgung. Dann werden sie gelöscht oldstuff Dieses Mal haben sie es einfach nicht mehr. Ohne --prune Ihr Git ignoriert dies. Sie behalten Ihr altes origin/oldstuff auch wenn es jetzt tot ist. Mit --prune sagt Ihr Git: Oh, hm, das sieht jetzt tot aus und entfernt sie: ein Name für die Fernverfolgung in Ihr Git, die nicht mit einer ihrer Zweigstelle Namen, wird einfach gelöscht.

Die Option "prune" hätte eigentlich schon immer die Standardeinstellung sein sollen, war es aber nicht und kann es daher auch nicht mehr sein. 6 Sie können jedoch Folgendes konfigurieren fetch.prune まで true y machen. es Ihr Standard.


4 Das ist jetzt im Jahr 2021 weniger häufig der Fall als noch 2010. Im Jahr 2005, als Git zum ersten Mal veröffentlicht wurde, war es wesentlich häufiger der Fall. Früher war es so, dass man z. B. auf einem Flug zu einer Linux-Konferenz nicht in den Genuss von tout Zugang zum Internet, zu jedem Preis.

5 Die Wahl der Namen und des Zeitpunkts, zu dem sie vergeben werden, ist ein Teil der Antwort auf diese Frage. Sie hat sich im Laufe der Zeit in Git geändert - und ändert sich immer noch ein wenig -, obwohl es immer noch verschiedene Einschränkungen gibt. Wir werden jedoch nicht auf alle Details eingehen.

6 Git nimmt die Abwärtskompatibilität im Allgemeinen sehr ernst. Erst mit der Umstellung von 1.x auf 2.0 wurde die push.default Standardeinstellung von matching まで simple zum Beispiel.


Wie git rev-list erhält die beiden Zahlen

Ich habe bereits darauf hingewiesen, dass die Meldung "voraus", "hinter", "aktuell" oder "abweichend", die git status Die Drucke kommen vom Laufen:

git rev-list --count --left-right $branch...$upstream

Was git rev-list tut, ist hier Erreichbare Commits zählen . Die Drei-Punkte-Syntax, beschrieben in die Dokumentation von gitrevisions erzeugt, was in der Mengenlehre als Symmetriedifferenz . Im Nicht-Mathe-Fachjargon können wir uns das so vorstellen, dass wir zwei Erreichbarkeitstests für Übergaben durchführen, die wir wie folgt zeichnen können:

          I--J   <-- xyzzy (HEAD)
         /
...--G--H
         \
          K   <-- origin/xyzzy

Hier, verpflichten Sie sich J von Ihrem Zweigstellennamen aus erreichbar ist xyzzy weil der Name darauf hinweist. Commit I ist erreichbar von commit J also zählt es auch. Dies führt zurück zu commit H -was, wie Sie aus dem Schaubild ersehen können, ein wenig speziell ist.

Gleichzeitig verpflichten Sie sich K ist über Ihren Remote-Tracking-Namen erreichbar origin/xyzzy . Commit H ist erreichbar von K . Vom Commit H auf dem Rücken, begeht G y F und so weiter sind ebenfalls alle erreichbar. Aber die beiden "Bahngleise" aufschließen bei der Übergabe H : verpflichten H und alle früheren Übertragungen sind erreichbar von beide Namen .

Dies macht Übertragungen I-J besonders, da sie *nur über den Namen erreichbar sind xyzzy y K besonders, da sie *nur über den Namen erreichbar ist origin/xyzzy . Die Drei-Punkte-Schreibweise findet diese Commits: die, die nur von einem Namen oder nur von dem anderen erreichbar sind.

Wenn wir den Namen der Verzweigung auf der linken Seite und den Namen des Upstreams auf der rechten Seite eintragen und die Drei-Punkte-Notation verwenden, finden wir alle drei Commits für diesen Fall. verwenden --count macht git rev-list diese Nummer drucken: 3. mit --left-right sagt git rev-list intelligenter sein: Es sollte zählen, wie viele Übertragungen aufgrund der links Name-der aktuelle Branche Name - und wie viele Übertragungen aufgrund der Tatsache gezählt werden, dass rechts eine, die stromaufwärts gelegene. Mit beiden Optionen - und den drei Punkten - erhalten wir also:

2       1

als Ausgabe, die uns sagt, dass es zwei Übertragungen auf xyzzy die nicht auf origin/xyzzy und eine Übertragung, die auf origin/xyzzy die nicht auf xyzzy . Dies sind Übertragungen J -und- I (auf xyzzy ) und K (auf origin/xyzzy ).

Ohne die --count Option, git rev-list würde die Hash-IDs auflisten, mit dem Präfix < (links) oder > (rechts) Symbole. Verwendung von git log 代わりに git rev-list , wie in:

git log --left-right xyzzy...origin/xyzzy

(beachten Sie erneut die drei Punkte: siehe gitrevisions und suchen Sie nach Symmetric Difference) erhalten wir die drei angezeigten Commits, wiederum mit dem Präfix < o > nach Bedarf.

Dies ist ein einfacher Weg, um zu sehen, welche Commits auf Ihrem Zweig und welche auf dem Upstream sind. Es ist normalerweise nützlicher mit --decorate , --oneline y --graph (und Sie sollten vielleicht hinzufügen --boundary in einigen Fällen auch).

Vorn, hinten, abweichend oder aktuell

Nehmen wir also an, wir sind gelaufen:

git rev-list --count --left-right $branch...$upstream

(oder- siehe gitrevisions wieder - mit $branch@{upstream} hier rechts) und haben unsere beiden Zählungen erhalten. Diese können sein:

  • 0 y 0 : Unser Branch-Name und unser Remote-Tracking-Name (oder was auch immer im Upstream steht) verweisen auf den dieselbe verpflichten. Niemand liegt vorne oder hinten. Die git status Der Befehl sagt Your branch is up to date with '<upstream>' .

  • ungleich Null, Null: Es gibt Commits auf der aktuelle Branche die sich nicht auf dem Upstream befinden. Es gibt keine Commits auf dem Upstream, die nicht auf dem aktuellen Zweig sind. Unser Zweig ist also vor den stromaufwärts gelegenen.

  • Null, Nicht-Null: Es gibt keine Übertragungen auf der aktuelle Branche die nicht auf dem Upstream sind, aber es gibt einige auf dem Upstream, die nicht auf dem aktuellen Zweig sind. Das bedeutet, unser Zweig ist hinter den stromaufwärts gelegenen.

  • ungleich null, ungleich null: Das ist wie das Diagramm, das ich oben gezeichnet habe. Sowohl der aktuelle Zweig als auch sein vorgelagerter Zweig liegen gleichzeitig vor und hintereinander. Die git status wird das Wort diverged .

Wir wollen nun zur ursprünglichen Frage zurückkehren. Nehmen wir an, das Upstrema des aktuellen Zweigs ist ein Remote-Tracking-Name. Beachten Sie, dass die Zählungen, die git rev-list basieren auf den Namen unserer Remote-Tracking-Zweige.

Wie kommt das eigentlich zustande?

Im Szenario des Auftraggebers macht nur eine Person neue Übertragungen und schickt sie mit git push . Wenn ich die eine Person bin, könnte ich git clone etwas von GitHub, dann machen Sie einen neuen Commit oder zwei und git push origin master .

Im modernen Git, git status würde mir sagen, dass ich auf dem neuesten Stand bin. In sehr alten Git-Versionen, git status würde mir jetzt sagen, dass mein master es vor origin/master . Der Grund dafür ist einfach: früher, git push Aktualisierung fehlgeschlagen origin/master . Laufen git fetch origin oder einfach git fetch Ihr eigenes Git erstellt haben, rufen Sie das Git auf GitHub auf, lesen Sie die Informationen und stellen Sie fest, dass Ihr git push funktioniert hatte.

Wenn Sie git push rufen Sie mit Ihrem Git ein anderes Git auf. Ihr Git bietet dem anderen Git dann alle neuen Commits an, die Sie haben und die es nicht hat und die es braucht, um die git push . Sie nehmen diese Zusagen und bringen sie irgendwo unter. 7 Dann fragt Ihr Git - standardmäßig höflich - ob sie bitte, wenn es OK ist, die ihre Zweigstelle Name, um auf die letzte Übergabe zu verweisen, und zwar durch ihre Hash-ID, wie sie in Ihr Name der Niederlassung. Hier findet keine Fernverfolgung statt. Sie bitten sie lediglich, den gleicher Name die Sie verwenden.

In der Regel ist diese Art der höflichen Anfrage erfolgreich, wenn Sie nur neue Commits in das Repository einfügen. Sie scheitert, wenn Sie sie bitten, einige Commits zu "verlieren": Sie werden eine Beschwerde darüber bekommen, dass dies ein "Nicht-schnell-weiterleiten" ist. Wenn Sie der einzige sind, der Senden Wenn sie neue Übertragungen vornehmen, sollten sie auf diese Weise nie etwas zu verlieren haben, so dass dies immer funktionieren sollte. 8

Wenn der Druck scheitert ist es für Ihr Git angemessen, den Namen für die Fernverfolgung unverändert zu lassen. Dein Git hat nie die Informationen von deren Git erhalten, die es deinem Git erlauben würden, ihn zu aktualisieren. Aber wenn der Push folgt auf ... nun, sie haben gerade ihre Zweigstelle Namen auf die Hash-ID, die Ihr Git von ihnen verlangt hat. Jetzt weiß Ihr Git, wohin der Name des Zweigs zeigt. Ihr Git sollte Ihren Remote-Tracking-Namen aktualisieren.

In alten Git-Versionen hat Ihr Git einfach hat sich nicht die Mühe gemacht, dies zu tun . In der Git-Version 1.8.2 haben die Git-Autoren dies endlich behoben: eine erfolgreiche git push lässt Ihr Git Ihren Remote-Tracking-Namen aktualisieren, da sein Git der von Ihrem Git bereitgestellten Aktualisierung zugestimmt hat. So etwas kommt also nicht mehr so oft vor.


7 In den schlechten alten Zeiten haben sie sie direkt in ihr Repository gestellt. Im modernen Git werden sie in einen Quarantänebereich verschoben und nur dann in das Repository migriert, wenn die neuen Commits tatsächlich akzeptiert werden.

8 Natürlich bieten Orte wie GitHub auch Funktionen wie geschützte Branchen die einfach nein sagen zu cada schieben, zum Beispiel. Wir können auch ausgefallenere Szenarien erfinden, z.B. wenn Sie mehrere Computer haben und vergessen, dass Sie neue Commits über Computer A gemacht und gepusht haben, und nun versuchen, von Computer B zu pushen.


Was, wenn Sie nicht der Einzige sind, der git push

Nehmen wir an, dass sowohl Alice als auch Bob ein GitHub-Repository geklont haben. Die Entwicklung in diesem Repository findet im Branch dev (für die Entwicklung). Also macht Alice ihr eigenes dev von ihr origin/dev :

...--G--H   <-- dev (HEAD), origin/dev  [Alice's computer]

Bob, ebenfalls, macht seine eigene dev :

...--G--H   <-- dev (HEAD), origin/dev  [Bob's computer]

Das GitHub-Repository dev endet bei H auch. (Sie haben keine origin/dev : Das GitHub-Repository kümmert sich nicht um Remote-Tracking-Namen).

Alice macht eine neue Übergabe, die wir als I und zeichne so auf Alices Computer:

          I   <-- dev (HEAD)
         /
...--G--H   <-- origin/dev

In der Zwischenzeit macht Bob eine neue Übergabe, die wir als J :

...--G--H   <-- origin/dev
         \
          J   <-- dev (HEAD)

Nun versuchen sowohl Alice als auch Bob git push origin dev . Eine von ihnen ist zuerst da - vielleicht Alice:

...--G--H--I   <-- dev  [GitHub's systems]

Bob sendet Commit J die auf GitHub wie folgt aussieht:

          I   <-- dev
         /
...--G--H
         \
          J   ... polite request to set dev to J

Wenn GitHub dies tun würde, würde der Commit von Alice "verloren" gehen I weil Git findet Übertragungen, indem Sie bei den Namen beginnen und sich rückwärts vorarbeiten. Sie lehnen den Vorstoß also mit der Beschwerde "kein schneller Vorlauf" ab.

Bob muss sich jetzt verpflichten I von GitHub in Bobs eigenes Repository, so dass Bob sieht:

          I   <-- origin/dev
         /
...--G--H
         \
          J   <-- dev (HEAD)  [Bob's computer]

Bob sollte dies tun mit git fetch o git fetch origin vielleicht mit --prune (oder mit fetch.prune eingestellt auf true ). Jetzt wenn Bob läuft git status erhält er die Nachricht "abweichend".

Als Verlierer des Push-Rennens muss Bob nun herausfinden, wie er die seine Arbeit (begehen J ) mit der von Alice (commit I ). Es gibt verschiedene Möglichkeiten, Arbeit zu kombinieren. Die beiden wichtigsten sind git merge y git rebase . Wir werden hier nicht darauf eingehen, wer was, wann und warum tun sollte, sondern nur darauf, dass dies eine weitere Möglichkeit ist, wie Sie in den "abweichenden" Status geraten können, wenn Sie dachten, dass Sie einem anderen Git strikt voraus sind.

12voto

AxCoder Punkte 568

In meinem Fall lag es daran, dass ich zum Master wechselte, indem ich

 git checkout -B master

Nur um die neue Version davon zu ziehen, anstatt

 git checkout master

Der erste Befehl setzt den Kopf des Masters zurück zu meinen letzten Übertragungen

Ich habe

git reset --hard origin/master

Um das zu beheben

11voto

erwin Punkte 290

Ich bin jede Lösung auf dieser Seite durchgegangen, und zum Glück hat @anatolii-pazhyn kommentiert, weil seine Lösung diejenige war, die funktioniert hat. Leider habe ich nicht genug Ruf um ihn hochzustufen, aber ich empfehle, zuerst seine Lösung auszuprobieren:

git reset --hard origin/master

Das gab mir:

HEAD is now at 900000b Comment from my last git commit here

Ich empfehle auch:

git rev-list origin..HEAD
# to see if the local repository is ahead, push needed

git rev-list HEAD..origin
# to see if the local repository is behind, pull needed

Sie können auch verwenden:

git rev-list --count --left-right origin/master...HEAD
# if you have numbers for both, then the two repositories have diverged

Viel Glück

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X