Master Branch und 'Origin / Master' sind auseinander gegangen, wie kann man 'Zweige' undivergen '?

964

Irgendwie sind mein Master und mein Herkunfts- / Master-Zweig auseinander gegangen.
Ich möchte eigentlich nicht, dass sie auseinander gehen.

Wie kann ich diese Unterschiede anzeigen und zusammenführen?

Frank
quelle
2
Was meinst du mit divergierend? Basen Sie Ihren Meister zurück, nachdem Sie ihn gedrückt haben?
Hasen
13
Ich erhalte die Meldung "Ihr Zweig und 'Ursprung / Master' sind auseinander gegangen, # und haben jeweils 1 und 1 verschiedene Commits."
Frank
Ich habe meine Antwort aktualisiert, um diese "divergierende" Warnmeldung wiederzugeben.
VonC
Die akzeptierte Antwort auf eine andere Frage kann auch hilfreich sein, um bestimmte Fälle zu lösen, in denen dies ins Spiel kommen könnte (z. B. wenn Sie versuchen, Ihren Master zu bewegen, dies wurde jedoch bereits verschoben
Lindes
8
Die Erklärung in diesem Blog hat mir unendlich mehr geholfen als jede Antwort unten: sebgoo.blogspot.com/2012/02/…

Antworten:

1014

Sie können die Unterschiede überprüfen mit:

git log HEAD..origin/master

vor dem Ziehen (Abrufen + Zusammenführen) (siehe auch "Wie bringt man Git dazu, immer von einem bestimmten Zweig zu ziehen?" )


Wenn Sie eine Nachricht haben wie:

"Ihr Zweig und 'Ursprung / Master' sind auseinander gegangen, # und haben jeweils 1 und 1 verschiedene Commits."

Überprüfen Sie, ob Sie ein Update durchführen müssenorigin . Wenn origines auf dem neuesten Stand ist, wurden einige Commits originvon einem anderen Repo verschoben, während Sie Ihre eigenen Commits vor Ort vorgenommen haben.

... o ---- o ---- A ---- B  origin/master (upstream work)
                   \
                    C  master (your work)

Sie haben Commit C auf Commit A basiert, da dies die letzte Arbeit war, die Sie zu diesem Zeitpunkt aus dem Upstream abgerufen hatten.

Bevor Sie jedoch versucht haben, zum Ursprung zurückzukehren, hat jemand anderes Commit B gedrückt. Die
Entwicklungshistorie ist in separate Pfade unterteilt.

Sie können dann zusammenführen oder neu aufbauen. Weitere Informationen finden Sie unter Pro Git: Git Branching - Rebasing .

Verschmelzen

Verwenden Sie den Befehl git merge:

$ git merge origin/master

Dies weist Git an, die Änderungen von origin/masterin Ihre Arbeit zu integrieren und ein Merge-Commit zu erstellen.
Die Grafik der Geschichte sieht jetzt so aus:

... o ---- o ---- A ---- B  origin/master (upstream work)
                   \      \
                    C ---- M  master (your work)

Die neue Zusammenführung, Commit M, hat zwei übergeordnete Elemente, die jeweils einen Entwicklungspfad darstellen, der zu dem in diesem Commit gespeicherten Inhalt geführt hat.

Beachten Sie, dass der Verlauf hinter M jetzt nicht linear ist.

Rebase

Verwenden Sie den Befehl git rebase:

$ git rebase origin/master

Dies weist Git an, Commit C (Ihre Arbeit) so
abzuspielen, als hätten Sie es auf Commit B anstelle von A basiert. CVS- und Subversion-Benutzer setzen ihre lokalen Änderungen routinemäßig zusätzlich zur Upstream-Arbeit neu, wenn sie vor dem Commit aktualisiert werden.
Git fügt lediglich eine explizite Trennung zwischen den Commit- und Rebase-Schritten hinzu.

Die Grafik der Geschichte sieht jetzt so aus:

... o ---- o ---- A ---- B  origin/master (upstream work)
                          \
                           C'  master (your work)

Commit C 'ist ein neues Commit, das mit dem Befehl git rebase erstellt wurde.
Es unterscheidet sich von C in zweierlei Hinsicht:

  1. Es hat eine andere Geschichte: B statt A.
  2. Sein Inhalt berücksichtigt Änderungen in B und C; Es ist dasselbe wie M aus dem Zusammenführungsbeispiel.

Beachten Sie, dass der Verlauf hinter C 'immer noch linear ist.
Wir haben (vorerst) gewählt, nur lineare Geschichte in zuzulassen cmake.org/cmake.git.
Dieser Ansatz behält den zuvor verwendeten CVS-basierten Workflow bei und kann den Übergang erleichtern.
Ein Versuch, C 'in unser Repository zu verschieben, funktioniert (vorausgesetzt, Sie haben Berechtigungen und niemand hat während des erneuten Basierens gepusht).

Der Befehl git pull bietet eine Kurzform zum Abrufen vom Ursprung und zum erneuten Basieren der lokalen Arbeit daran:

$ git pull --rebase

Dies kombiniert die obigen Schritte zum Abrufen und erneuten Basieren in einem Befehl.

VonC
quelle
5
Ich habe dies gefunden, als ich das gleiche Problem nachgeschlagen habe. Können Sie erklären, warum 'git reset --hard HEAD' das Problem nicht behoben hat?
Neth
12
@Neth: weil es nicht um abgestufte Änderungen geht (dh Änderungen, die im Index vorhanden, aber noch nicht festgeschrieben sind), sondern um lokale Festschreibungen (die sich von den auf der Fernbedienung vorhandenen Festschreibungen unterscheiden). git reset --hard HEADwürde nur lokal indizierte, nicht festgeschriebene Änderungen entfernen und nichts tun, um die Unterschiede zwischen lokalen und Remote- Festschreibungen auszugleichen . Nur eine Zusammenführung oder ein Rebase bringt die beiden Commits (das lokale und das entfernte) zusammen.
VonC
4
Wow, danke für diese tolle Antwort. Wir hatten versehentlich einen "Git Pull" ohne "--rebase" gemacht und "Git Rebase Origin / Master" war genau das Richtige!
Mrooney
3
Wie wäre es - ich möchte nur meine lokalen Änderungen ignorieren / sichern und bei meinem lokalen Zweig sein, in dem sich die Fernbedienung befindet? Mit anderen Worten, ich möchte auf Ihr Beispiel masterverweisen B.
CygnusX1
23
@ CygnusX1 das wäre ein git reset --hard origin/masterwie in der Antwort unten erwähnt: stackoverflow.com/a/8476004/6309
VonC
725

Ich hatte dies und bin verwirrt darüber, was es verursacht hat, selbst nachdem ich die obigen Antworten gelesen habe. Meine Lösung war zu tun

git reset --hard origin/master

Dann wird meine (lokale) Kopie des Masters (von der ich annehme, dass sie vermasselt ist) auf den richtigen Punkt zurückgesetzt, wie durch (entfernten) Ursprung / Master dargestellt.

WARNUNG : Sie verlieren alle Änderungen, die noch nicht vorgenommen wurden origin/master.

Skiphoppy
quelle
21
Ja, es fühlt sich ein bisschen wie die Dummies-Option an, aber wenn es keine wirkliche Gefahr gibt und Sie hier sind, um eine schnelle Lösung zu finden - das funktioniert (für mich jedenfalls)
PandaWood
7
Dies muss vorher im Master-Zweig sein ("git checkout master").
blau
Dies passierte mir einmal, als ich spätestens vom Ursprung kam, dann machte jemand anderes einen Force-Push zum Ursprung, der dazu führte, dass das vorherige Commit im Ursprung zurückgesetzt wurde. Meine lokale Niederlassung hatte also das rückgängig gemachte Commit, und als ich versuchte, das Neueste aus dem Ursprung zu ziehen, hieß es, ich müsse zusammenführen. In diesem Fall war es nur sinnvoll, --hard origin / (branch) zurückzusetzen, da das Problem bereits im Ursprung behoben wurde.
Landon Poch
96
Sie sollten Benutzer wahrscheinlich warnen, dass sie dadurch alle Änderungen verlieren, die noch nicht zum Ursprung
verschoben wurden
6
@PedroLoureiro Commits sind Notiz wirklich verloren, Sie können die Commits immer noch mit finden git reflogoder in sehen gitk --all. Aber natürlich ist der Hard-Reset eine andere Sache als eine Rebase.
Sebkraemer
52
git pull --rebase origin/master 

ist ein einzelner Befehl, der Ihnen die meiste Zeit helfen kann.

Bearbeiten: Ruft die Commits vom Ursprung / Master ab und wendet Ihre Änderungen auf den neu gezogenen Zweigverlauf an.

asitmoharna
quelle
89
Bitte erwähnen Sie, was der Befehl tut, sonst könnten die Leute ihn ausführen und es
vermasseln
1
Wenn es kein Problem gibt, sollten Sie am Ende Ihren Master haben, der alle Änderungen des Ursprungs / Masters enthält, und alle Ihre lokalen Commits werden darüber hinaus wiedergegeben. Scheint mir gut zu sein.
Philipp Claßen
7
Außer wenn es echte Unterschiede gibt und Sie in eine abgebrochene Rebase geraten.
Jungvogel
Dies führt zu einem Fehler: Fehler: Fehler beim Zusammenführen der Änderungen. Patch fehlgeschlagen bei 0024 Request and Response Models
IgorGanapolsky
32

Ich fand mich in dieser Situation , als ich versuchte rebase einen Zweig, der einen entfernten Zweig verfolgt, und ich versuche es auf Master rebase. Wenn Sie in diesem Szenario versuchen, die Basis neu zu definieren, wird Ihr Zweig höchstwahrscheinlich divergieren und es kann zu einem Durcheinander kommen, das nichts für Git-Nubees ist!

Angenommen, Sie befinden sich in der Verzweigung my_remote_tracking_branch, die vom Master verzweigt wurde

$ git status

# Auf Zweig my_remote_tracking_branch

nichts festzuschreiben (Arbeitsverzeichnis sauber)

Und jetzt versuchen Sie, vom Master zurückzugreifen als:

Git Rebase Master

STOPPEN SIE JETZT und sparen Sie sich Ärger! Verwenden Sie stattdessen Zusammenführen als:

Git Merge Master

Ja, Sie werden zusätzliche Commits in Ihrer Filiale erhalten. Wenn Sie sich jedoch nicht für "nicht divergierende" Zweige interessieren, ist dies ein viel reibungsloserer Workflow als das erneute Basieren. In diesem Blog finden Sie eine ausführlichere Erklärung.

Wenn es sich bei Ihrer Niederlassung jedoch nur um eine lokale Niederlassung handelt (dh noch nicht auf eine entfernte Fernbedienung übertragen wurde), sollten Sie auf jeden Fall eine Rebase durchführen (und Ihre Niederlassung wird in diesem Fall nicht voneinander abweichen ).

Nun , wenn Sie dies lesen , weil Sie bereits sind in einem „abgezweigt“ Szenario aufgrund solchen Fütterungsmaterial können Sie zum letzten wieder begehen vom Ursprung (dh in einem nicht abwich Zustand) unter Verwendung von :

git reset --hard origin / my_remote_tracking_branch

Paneer Tikka
quelle
5
Als Faustregel gilt, rebasewenn der Zweig, den Sie neu gründen, nicht veröffentlicht wurde (und von anderen Personen verwendet wird). Andernfalls verwenden Sie merge. Wenn Sie bereits veröffentlichte (und verwendete) Zweige neu gründen, müssen Sie eine Verschwörung koordinieren, um den Verlauf für jeden Entwickler neu zu schreiben, der Ihren Zweig verwendet hat.
Mikko Rantalainen
1
Leider habe ich diese Nachricht vor dem git rebase master...
Vitaly Isaev
Wenn ich git rebase master mache, während ich mich auf dem Zweig 'foobar' befinde, dann weicht die foobar technisch von origin / foobar ab, bis ich einen git push -f mache, oder?
Relipse
1
git reset --hard origin/my_remote_tracking_branchist das, was wirklich funktioniert hat
roothahn
24

In meinem Fall habe ich Folgendes getan, um die divergierende Nachricht zu verursachen : Ich habe es getan, git pushaber dann getan, git commit --amendum der Festschreibungsnachricht etwas hinzuzufügen. Dann habe ich auch noch ein Commit gemacht.

In meinem Fall bedeutete das einfach, dass Herkunft / Master veraltet waren. Da ich wusste, dass niemand anderes Origin / Master berührte, war die Korrektur trivial: git push -f (wo -fbedeutet Kraft)

Darren Cook
quelle
8
+1 für git push -f, um die zuvor festgeschriebenen und auf den Ursprung übertragenen Änderungen zu überschreiben. Ich bin mir auch sicher, dass niemand anderes das Repository berührt hat.
Zacharydl
4
Sehr riskantes Kommando. Bitte schreiben Sie eine kurze Information bezüglich des Risikofaktors des Befehls.
J4cK
1
@Trickster: Ich hatte das Risiko bereits beschrieben: "Wie ich wusste, berührte niemand anderes Origin / Master". Ich glaube, in diesem Fall ist dies kein riskanter Befehl.
Darren Cook
1
Wenn sich jemand auf den Master verpflichtet und dann eine Person den Befehl git push -f
ausführt, handelt
11

In meinem Fall habe ich Änderungen vorgenommen origin/masterund dann festgestellt, dass ich dies nicht hätte tun sollen :-( Dies wurde durch die Tatsache erschwert, dass sich die lokalen Änderungen in einem Teilbaum befanden. Also ging ich zum letzten guten Commit vor dem "schlechten" lokalen zurück Änderungen (mit SourceTree) und dann bekam ich die "Divergenznachricht".

Nachdem ich mein Durcheinander lokal behoben hatte (die Details sind hier nicht wichtig), wollte ich den Remote- origin/masterZweig "in der Zeit zurückversetzen", damit er wieder mit dem lokalen Zweig synchronisiert masterwird. Die Lösung in meinem Fall war:

git push origin master -f

Beachten Sie den -f(Kraft-) Schalter. Dadurch wurden die "fehlerhaften Änderungen" gelöscht, die origin/masterversehentlich vorgenommen wurden, und jetzt sind die lokalen und Remote-Zweige synchron.

Beachten Sie bitte, dass dies ein potenziell zerstörerischer Vorgang ist. Führen Sie ihn daher nur aus, wenn Sie zu 100% sicher sind, dass das rechtzeitige Zurückbewegen des Remote-Masters in Ordnung ist.

Kehlkopf Decidua
quelle
Immer nützlich, aber sicherlich nicht beantwortet die Frage.
Thibault D.
1
@ThibaultD. Auch wenn dies nicht der Fall ist, ist dies genau das, wonach ich gesucht habe.
Neil Chowdhury
Ich bekomme You are not allowed to force push code to a protected branch on this project.. Ich versuche an meine Gabel zu drücken.
BanAnanas
Ich musste den Schutz auf gitlab repo stackoverflow.com/questions/32246503/…
BanAnanas
5

Ich weiß, dass es hier viele Antworten gibt, aber ich denke git reset --soft HEAD~1, dass es etwas Aufmerksamkeit verdient, weil Sie damit Änderungen im letzten lokalen (nicht gepushen) Commit beibehalten können, während Sie den divergierenden Zustand lösen. Ich denke, dies ist eine vielseitigere Lösung als Pull-With rebase, da das lokale Commit überprüft und sogar in einen anderen Zweig verschoben werden kann.

Der Schlüssel verwendet --softanstelle des harten --hard. Wenn es mehr als 1 Commit gibt, sollte eine Variation von HEAD~xfunktionieren. Hier sind alle Schritte, die meine Situation gelöst haben (ich hatte 1 lokales Commit und 8 Commits in der Fernbedienung):

1) git reset --soft HEAD~1 lokales Commit rückgängig machen. Für die nächsten Schritte habe ich die Schnittstelle in SourceTree verwendet, aber ich denke, die folgenden Befehle sollten auch funktionieren:

2) git stash Änderungen von 1) zu verstauen. Jetzt sind alle Änderungen sicher und es gibt keine Abweichungen mehr.

3) git pull um die Remote-Änderungen zu erhalten.

4) git stash pop oder git stash applyum die letzten versteckten Änderungen anzuwenden, gefolgt von einem neuen Commit, falls gewünscht. Dieser Schritt ist zusammen mit 2) optional, wenn die Änderungen im lokalen Commit verworfen werden sollen. Wenn Sie einen Commit für einen anderen Zweig durchführen möchten, sollte dieser Schritt ausgeführt werden, nachdem Sie zum gewünschten Zweig gewechselt haben.

Bianca Daniciuc
quelle
Eigentlich pull --rebasewürde sich das heutzutage sowieso automatisch verstecken. stackoverflow.com/a/30209750/6309
VonC
4

So zeigen Sie die Unterschiede an:

git difftool --dir-diff master origin/master

Dadurch werden die Änderungen oder Unterschiede zwischen den beiden Zweigen angezeigt. In araxis (Mein Favorit) wird es in einem Ordner-Diff-Stil angezeigt. Zeigt jede der geänderten Dateien an. Ich kann dann auf eine Datei klicken, um die Details der Änderungen in der Datei anzuzeigen.

C Johnson
quelle
1
Interessante Verwendung von Git-Dir: +1
VonC
3

In meinem Fall wurde dies dadurch verursacht, dass ich meine Konfliktlösung nicht begangen habe.

Das Problem wurde durch Ausführen des git pullBefehls verursacht. Änderungen in der Herkunft führten zu Konflikten mit meinem lokalen Repo, die ich löste. Ich habe sie jedoch nicht begangen. Die Lösung an dieser Stelle besteht darin, die Änderungen ( git commitdie aufgelöste Datei) festzuschreiben.

Wenn Sie seit der Lösung des Konflikts auch einige Dateien geändert haben, zeigt der git statusBefehl die lokalen Änderungen als nicht bereitgestellte lokale Änderungen und die Zusammenführungsauflösung als abgestufte lokale Änderungen an. Dies kann ordnungsgemäß behoben werden, indem zuerst Änderungen aus der Zusammenführung git commitfestgeschrieben werden , dann die nicht bereitgestellten Änderungen wie gewohnt hinzugefügt und festgeschrieben werden (z git commit -a. B. durch ).

Mohammad Reza Esmaeilzadeh
quelle
0

Ich hatte dieselbe Meldung, als ich versuchte, die letzte Festschreibungsnachricht zu bearbeiten, von bereits gepushtem Festschreiben, mit: git commit --amend -m "New message" Als ich die Änderungen mit übertrug, git push --force-with-lease repo_name branch_name gab es keine Probleme.

LoveForDroid
quelle
0

Dieses Problem ist aufgetreten, als ich einen Zweig basierend auf Zweig A von erstellt habe

git checkout -b a

und dann setze ich den Aufwärtsstrom von Zweig a zum Ursprungszweig B durch

git branch -u origin/B

Dann habe ich oben die Fehlermeldung bekommen.

Eine Möglichkeit, dieses Problem für mich zu lösen, war:

  • Zweig löschen a
  • Erstellen Sie einen neuen Zweig b von
git checkout -b b origin/B
YanQing
quelle