Warum muss ich "git push --set-upstream origin <branch>"?

145

Ich habe eine lokale Niederlassung zum Testen von Solaris und Sun Studio erstellt. Ich schob dann den Zweig stromaufwärts. Nachdem Sie eine Änderung vorgenommen und versucht haben, die Änderungen zu übernehmen:

$ git commit blake2.cpp -m "Add workaround for missing _mm_set_epi64x"
[solaris 7ad22ff] Add workaround for missing _mm_set_epi64x
 1 file changed, 5 insertions(+)
$ git push
fatal: The current branch solaris has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin solaris

Warum muss ich dafür etwas Besonderes tun?

Gibt es einen vernünftigen Anwendungsfall, in dem jemand etwas erstellen <branch>, die <branch>Fernbedienung drücken und dann behaupten würde, dass ein Commit für <branch>nicht vorgesehen ist <branch>?


Ich habe diese Frage und Antwort zum Stapelüberlauf befolgt: Schieben Sie einen neuen lokalen Zweig in ein entferntes Git-Repository und verfolgen Sie ihn ebenfalls . Ich vermute, es ist ein weiteres Beispiel für eine unvollständige oder falsch akzeptierte Antwort. Oder es ist eine weitere Instanz von Git, die eine einfache Aufgabe übernimmt und sie schwierig macht.


Hier ist die Ansicht auf einer anderen Maschine. Der Zweig existiert eindeutig, also wurde er erstellt und verschoben:

$ git branch -a
  alignas
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/alignas
  remotes/origin/arm-neon
  remotes/origin/det-sig
  remotes/origin/master
  remotes/origin/solaris
jww
quelle
Mögliches Duplikat von Warum muss ich die ganze Zeit "--set-upstream" machen?
Alexei Levenkov
2
Danke @Alexi. Leider erklärt der zitierte Dup nicht den lächerlichen Anwendungsfall, der standardmäßig dargestellt wird. (Das sind keine rhetorischen Fragen. Der Grund für das UX-Design interessiert mich wirklich.)
Jww
1
Beachten Sie, dass dies konfigurierbar ist. Wenn Sie dies tun git config --add push.default current, erstellt git push bei Bedarf automatisch den Zweig im Remote-Repo.
Gogowitsch

Antworten:

270

TL; DR: git branch --set-upstream-to origin/solaris


Die Antwort auf die Frage , die Sie gefragt-die ich ein wenig anders formulieren werde als „muss ich eine Upstream - Set“ -ist: Nein, müssen Sie nicht haben einen vorgeschalteten überhaupt einzustellen.

Wenn Sie jedoch keinen Upstream für den aktuellen Zweig haben, ändert Git sein Verhalten bei git pushund auch bei anderen Befehlen.

Die komplette Push-Story hier ist lang und langweilig und geht zurück in die Geschichte vor Git Version 1.5. Um es viel zu verkürzen, git pushwurde schlecht umgesetzt. 1 Ab Git Version 2.0 verfügt Git jetzt über einen Konfigurationsknopf, push.defaultder standardmäßig verwendet wird simple. Bei mehreren Git-Versionen vor und nach 2.0 gab Git jedes Mal, wenn Sie git pushes ausführten, viel Lärm von sich, um Sie davon zu überzeugen, push.defaultnur um git pushden Mund zu halten.

Sie erwähnen nicht, welche Version von Git Sie ausführen oder ob Sie konfiguriert haben push.default, also müssen wir raten. Meine Vermutung ist , dass Sie verwenden Git Version 2-Punkt-etwas, und dass Sie gesetzt , push.defaultum simplees zu bekommen , um den Mund halten. Gerade , welche Version von Git haben Sie, und was ist, wenn alles , was Sie haben push.defaultzu setzen, tut Angelegenheit, wegen der langen und langweiligen Geschichte, aber am Ende ist die Tatsache , dass Sie immer noch ein weitere Beschwerde von Git zeigt an, dass Ihr Git ist konfiguriert, um einen der Fehler aus der Vergangenheit zu vermeiden.

Was ist ein Upstream?

Ein Upstream ist einfach ein anderer Zweigstellenname, normalerweise ein Fernverfolgungszweig, der einem (regulären, lokalen) Zweig zugeordnet ist.

Jeder Zweig hat die Möglichkeit, einen (1) Upstream-Satz zu haben. Das heißt, jeder Zweig hat entweder einen Upstream oder keinen Upstream. Kein Zweig kann mehr als einen Upstream haben.

Der Upstream sollte , muss aber kein gültiger Zweig sein (ob Remote-Tracking-ähnlich oder lokal-ähnlich ). Das heißt, wenn der aktuelle Zweig B stromaufwärts U hat , sollte funktionieren. Wenn es nicht funktioniert - wenn es sich beschwert, dass U nicht existiert - dann verhält sich der Großteil von Git so, als ob der Upstream überhaupt nicht eingestellt ist. Einige Befehle, wie z. B. , zeigen die Upstream-Einstellung an, markieren sie jedoch als "weg".origin/Bmastergit rev-parse U git branch -vv

Was nützt ein Upstream?

Wenn Sie push.defaultauf simpleoder eingestellt sind upstream, git pushfunktioniert die Upstream-Einstellung ohne zusätzliche Argumente.

Das ist es - das ist alles, wofür es tut git push. Aber das ist ziemlich wichtig, da dies git pusheiner der Orte ist, an denen ein einfacher Tippfehler große Kopfschmerzen verursacht.

Wenn Ihr push.defaultist auf nothing, matchingoder currenteine Upstream - Einstellung tut nichts für git push.

(All dies setzt voraus, dass Ihre Git-Version mindestens 2.0 ist.)

Der Upstream wirkt sich aus git fetch

Wenn Sie git fetchohne zusätzliche Argumente arbeiten, ermittelt Git anhand der Upstream-Funktion des aktuellen Zweigs , von welcher Fernbedienung abgerufen werden soll. Wenn der Upstream ein Remote-Tracking-Zweig ist, ruft Git von diesem Remote ab. (Wenn der Upstream nicht festgelegt ist oder ein lokaler Zweig ist, versucht Git, ihn abzurufen origin.)

Der Upstream beeinflusst git mergeund git rebaseauch

Wenn Sie ausführen git mergeoder git rebasekeine zusätzlichen Argumente haben, verwendet Git den Upstream des aktuellen Zweigs. Dies verkürzt die Verwendung dieser beiden Befehle.

Der Upstream wirkt sich aus git pull

Sie sollten ohnehin nie 2 verwenden git pull, aber wenn Sie dies tun, git pullverwenden Sie die Upstream-Einstellung, um herauszufinden, von welcher Fernbedienung abgerufen werden soll und mit welchem ​​Zweig Sie dann zusammenführen oder neu aufbauen möchten. Das heißt, git pullmacht dasselbe wie - git fetchweil es tatsächlich läuft git fetch - und macht dann dasselbe wie git mergeoder git rebase, weil es tatsächlich läuft git merge oder git rebase.

(Normalerweise sollten Sie diese beiden Schritte nur manuell ausführen, zumindest bis Sie Git gut genug kennen. Wenn einer der beiden Schritte fehlschlägt, erkennen Sie schließlich, was schief gelaufen ist, und wissen, was Sie dagegen tun müssen.)

Der Upstream wirkt sich aus git status

Dies kann tatsächlich das wichtigste sein. Sobald Sie einen Upstream-Satz haben, git statuskönnen Sie den Unterschied zwischen Ihrer aktuellen Niederlassung und ihrem Upstream in Bezug auf Commits melden.

Wenn Sie sich wie im Normalfall in einem Zweig befinden, Bdessen Upstream auf eingestellt ist , und Sie ausführen , sehen Sie sofort, ob Sie Commits haben, die Sie pushen können, und / oder Commits, auf die Sie zusammenführen oder neu aufbauen können.origin/Bgit status

Dies liegt daran, git statusläuft:

  • git rev-list --count @{u}..HEAD: Wie viele Commits haben Sie B, die nicht aktiviert sind ?origin/B
  • git rev-list --count HEAD..@{u}: Wie viele Commits haben Sie , die nicht aktiviert sind ?origin/BB

Wenn Sie einen Upstream einrichten, erhalten Sie all diese Dinge.

Wie kommt es, dass masterbereits ein Upstream eingestellt ist?

Wenn Sie zum ersten Mal von einer Fernbedienung klonen, verwenden Sie:

$ git clone git://some.host/path/to/repo.git

oder ähnlich, der letzte Schritt, den Git macht, ist im Wesentlichen git checkout master. Diese Kontrollen Ihrer lokalen Niederlassung master-nur Sie nicht haben eine lokale Niederlassung master.

Auf der anderen Seite, Sie tun haben einen Remote-Tracking - Zweig genannt origin/master, weil Sie es nur geklont.

Git vermutet, dass Sie gemeint haben müssen: "Machen Sie mich zu einem neuen Lokal master, das auf dasselbe Commit wie Remote-Tracking verweist origin/master, und stellen Sie, während Sie gerade dabei sind, den Upstream für masterauf ein origin/master."

Dies geschieht für jeden Zweig git checkout, den Sie noch nicht haben. Git erstellt den Zweig und lässt ihn den entsprechenden Remote-Tracking-Zweig "verfolgen" (als Upstream haben).

Aber das funktioniert nicht für neue Filialen, dh Zweige ohne Fernverfolgung Zweig noch .

Wenn Sie einen neuen Zweig erstellen :

$ git checkout -b solaris

es gibt noch keine origin/solaris. Ihr lokaler Zweig solaris kann den Remote-Tracking-Zweig origin/solarisnicht verfolgen, da er nicht vorhanden ist.

Wenn Sie den neuen Zweig zum ersten Mal drücken:

$ git push origin solaris

das erstellt solaris auf originund damit auch origin/solarisin Ihrem eigenen Git-Repository. Aber es ist zu spät: Sie haben bereits einen Einheimischen solaris, der keinen Upstream hat . 3

Sollte Git das jetzt nicht einfach als Upstream automatisch einstellen?

Wahrscheinlich. Siehe "schlecht implementiert" und Fußnote 1. Es ist jetzt schwer zu ändern : Es gibt Millionen von 4 Skripten, die Git verwenden, und einige hängen möglicherweise von ihrem aktuellen Verhalten ab. Das Ändern des Verhaltens erfordert eine neue Hauptversion, nag-ware, um Sie zu zwingen, ein Konfigurationsfeld festzulegen, und so weiter. Kurz gesagt, Git ist ein Opfer seines eigenen Erfolgs: Welche Fehler es heute hat, kann nur behoben werden, wenn die Änderung entweder größtenteils unsichtbar, deutlich besser oder im Laufe der Zeit langsam durchgeführt wird.

Tatsache ist, dass dies heute nicht der Fall ist, es sei denn, Sie verwenden --set-upstreamoder -uwährend der git push. Das sagt Ihnen die Nachricht.

Du musst es nicht so machen. Nun, wie oben erwähnt, müssen Sie das überhaupt nicht tun, aber nehmen wir an, Sie möchten einen Upstream. Sie haben bereits Zweig erstellt solarisauf origin, durch eine frühere Push, und als git branchAusgabe zeigt, haben Sie bereits haben origin/solaris in Ihrem lokalen Repository.

Sie haben es einfach nicht als Upstream für festgelegt solaris.

Verwenden Sie zum Einstellen jetzt und nicht beim ersten Drücken git branch --set-upstream-to. Der --set-upstream-toUnterbefehl verwendet den Namen eines vorhandenen Zweigs, z. B. origin/solaris, und setzt den Upstream des aktuellen Zweigs auf diesen anderen Zweig.

Das ist es - das ist alles, was es tut - aber es hat all die oben genannten Implikationen. Es bedeutet, dass Sie einfach laufen git fetch, sich dann umschauen, dann laufen git mergeoder git rebasenach Bedarf neue Commits vornehmen und ausführen können git push, ohne zusätzliche Aufregung.


1 Um fair zu sein, war damals nicht klar, dass die anfängliche Implementierung fehleranfällig war. Das wurde erst klar, als jeder neue Benutzer jedes Mal die gleichen Fehler machte. Es ist jetzt "weniger arm", was nicht "großartig" heißt.

2 "Nie" ist ein bisschen stark, aber ich finde, dass Git-Neulinge die Dinge viel besser verstehen, wenn ich die Schritte trenne, insbesondere wenn ich ihnen zeigen kann, was git fetchtatsächlich getan wurde, und sie dann sehen können, was git mergeoder git rebasewas als nächstes tun wird.

3 Wenn Sie Ihre erste git push als git push -u origin solarisausführen, dh wenn Sie das -uFlag hinzufügen, wird Git origin/solarisals Upstream für Ihren aktuellen Zweig festgelegt, wenn (und nur wenn) der Push erfolgreich ist. Sie sollten also -ubeim ersten Druck liefern . Tatsächlich können Sie es bei jedem späteren Push bereitstellen, und es wird den Upstream an diesem Punkt einstellen oder ändern . Aber ich denke git branch --set-upstream-toist einfacher, wenn Sie vergessen haben.

4 Gemessen an der Methode von Austin Powers / Dr. Evil, einfach "ein MILLLL-YUN" zu sagen.

torek
quelle
2
Wenn der häufigste Fall {Zweig erstellen / Zweig verschieben / Zweig verwenden} ist, sollte das Ergebnis des Verschiebens eines neuen lokalen Zweigs in ein entferntes Git-Repository und dessen Verfolgung nicht auch tatsächlich funktionieren? Und wenn jemand {Zweig erstellen / Zweig verschieben / Zweig nicht verwenden} möchte, sollte er dann nicht etwas Besonderes tun müssen, wie z --set-upstream /dev/null. Warum wird die Last auf den allgemeinen Fall gelegt? Ich verstehe einige dieser technischen und Usability-Entscheidungen wirklich nicht.
JWW
1
@VonC: rechts, dass der Punkt ist git push -u, aber es scheint wirklich , wie git push -usollte der Standard sein, oder zumindest der Standard , wenn es keine stromaufwärts noch , und es sollte eine sein , git push --no-set-upstreamwenn gibt es derzeit nicht ein Upstream und Sie behalten möchten es so (aus irgendeinem unverständlichen Grund :-)).
Torek
2
"Sie stellen immer wieder Fragen wie diese, weil Sie Git, glaube ich, als" wirklich widerlich "abgeschrieben haben." Bitte behalten Sie diese Art von Spekulation für sich. Ich bin auf diese Frage gestoßen, weil ich mir auch immer wieder solche Fragen stelle. Ich bin nicht der beste UX-Designer der Welt, aber selbst ich erkenne, dass das Standardverhalten in diesem speziellen Szenario besser sein könnte.
Steven Byks
4
@torek - Danke. Ihre Antwort war ansonsten fantastisch; gut durchdacht, gut strukturiert und äußerst informativ. :-)
Steven Byks
6
Beachten Sie, dass dies konfigurierbar ist. Wenn Sie dies tun git config --add push.default current, erstellt git push bei Bedarf automatisch den Zweig im Remote-Repo.
Gogowitsch
30

Der Unterschied zwischen
git push origin <branch>
und
git push --set-upstream origin <branch>
besteht darin, dass beide problemlos in das Remote-Repository übertragen werden. Wenn Sie jedoch ziehen, bemerken Sie den Unterschied.

Wenn Sie dies tun: Wenn Sie
git push origin <branch>
ziehen, müssen Sie Folgendes tun:
git pull origin <branch>

Aber wenn Sie dies tun
git push --set-upstream origin <branch>
, müssen Sie beim Ziehen nur Folgendes tun:
git pull

Wenn Sie also das hinzufügen --set-upstream, müssen Sie nicht jedes Mal angeben, welchen Zweig Sie abrufen möchten git pull.

Adam
quelle
der Unterschied zwischen zwei Versionen von "git push", von denen ich nicht weiß, warum ich sie verwenden möchte / muss. Zwecklos!
Frank Puck
16

Ein grundsätzlich voller Befehl ist wie git push <remote> <local_ref>:<remote_ref>. Wenn Sie nur ausführen git push, weiß Git nicht genau, was zu tun ist, es sei denn, Sie haben eine Konfiguration vorgenommen, die Git hilft, eine Entscheidung zu treffen. In einem Git-Repo können wir mehrere Fernbedienungen einrichten. Wir können auch eine lokale Referenz an eine beliebige Remote-Referenz senden. Der vollständige Befehl ist der einfachste Weg, einen Push auszuführen. Wenn Sie weniger Wörter eingeben möchten, müssen Sie zuerst konfigurieren, z. B. --set-upstream.

ElpieKay
quelle