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.