Ich verstehe das in Pro Git vorgestellte Szenario über die Gefahren der Wiederherstellung . Der Autor erklärt Ihnen grundsätzlich, wie Sie doppelte Commits vermeiden können:
Setzen Sie Commits, die Sie in ein öffentliches Repository verschoben haben, nicht erneut um.
Ich werde Ihnen meine besondere Situation mitteilen, da ich denke, dass sie nicht genau zum Pro Git-Szenario passt und ich immer noch doppelte Commits habe.
Angenommen, ich habe zwei entfernte Niederlassungen mit ihren lokalen Gegenstücken:
origin/master origin/dev
| |
master dev
Alle vier Zweige enthalten die gleichen Commits und ich werde mit der Entwicklung beginnen in dev
:
origin/master : C1 C2 C3 C4
master : C1 C2 C3 C4
origin/dev : C1 C2 C3 C4
dev : C1 C2 C3 C4
Nach ein paar Commits drücke ich die Änderungen auf origin/dev
:
origin/master : C1 C2 C3 C4
master : C1 C2 C3 C4
origin/dev : C1 C2 C3 C4 C5 C6 # (2) git push
dev : C1 C2 C3 C4 C5 C6 # (1) git checkout dev, git commit
Ich muss zurückgehen master
, um eine schnelle Lösung zu finden:
origin/master : C1 C2 C3 C4 C7 # (2) git push
master : C1 C2 C3 C4 C7 # (1) git checkout master, git commit
origin/dev : C1 C2 C3 C4 C5 C6
dev : C1 C2 C3 C4 C5 C6
Und zurück zu dev
Ich ändere die Änderungen neu, um die schnelle Lösung in meine eigentliche Entwicklung aufzunehmen:
origin/master : C1 C2 C3 C4 C7
master : C1 C2 C3 C4 C7
origin/dev : C1 C2 C3 C4 C5 C6
dev : C1 C2 C3 C4 C7 C5' C6' # git checkout dev, git rebase master
Wenn ich die Geschichte der Commits mit GitX Anzeige / gitk merke ich , dass origin/dev
jetzt zwei identische Commits enthält C5'
und C6'
die mit Git unterschiedlich sind. Wenn ich nun die Änderungen dazu origin/dev
dränge, ist das Ergebnis:
origin/master : C1 C2 C3 C4 C7
master : C1 C2 C3 C4 C7
origin/dev : C1 C2 C3 C4 C5 C6 C7 C5' C6' # git push
dev : C1 C2 C3 C4 C7 C5' C6'
Vielleicht verstehe ich die Erklärung in Pro Git nicht ganz, deshalb möchte ich zwei Dinge wissen:
- Warum dupliziert Git diese Commits beim erneuten Basieren? Gibt es einen bestimmten Grund, dies zu tun, anstatt sich nur zu bewerben
C5
undC6
danachC7
? - Wie kann ich das vermeiden? Wäre es klug, es zu tun?
origin/dev
. Beimdev
erneuten Basieren wird der Verlauf geändert (C5 / C6 wird vorübergehend entfernt und nach C7 erneut angewendet). Das Ändern des Verlaufs von Push-Repos ist im Allgemeinen eine wirklich schlechte Idee ™, es sei denn, Sie wissen, was Sie tun. In diesem einfachen Fall könnte das Problem gelöst werden, indem nach dem Rebase ein Force-Push vondev
bisorigin/dev
ausgeführt wird und alle anderen Mitarbeiter darüber informiert werden,origin/dev
dass sie wahrscheinlich einen schlechten Tag haben werden. Die bessere Antwort ist wiederum "Kurze Antwort
Sie haben die Tatsache, dass Sie ausgeführt wurden
git push
, weggelassen , den folgenden Fehler erhalten und dann ausgeführtgit pull
:Obwohl Git versucht, hilfreich zu sein, ist der Ratschlag "Git Pull" höchstwahrscheinlich nicht das, was Sie tun möchten .
Wenn du bist:
git push --force
die Fernbedienung mit Ihrer Post-rebase Commits zu aktualisieren ( wie pro user4405677 Antwort ).git rebase
. Umdev
mit Änderungen von zu aktualisierenmaster
, sollten Sie, anstatt zu laufengit rebase master dev
, laufen,git merge master
während Sie eingeschaltet sinddev
( gemäß Justins Antwort ).Eine etwas längere Erklärung
Jeder Commit-Hash in Git basiert auf einer Reihe von Faktoren, von denen einer der Hash des Commits ist, der davor steht.
Wenn Sie Commits neu anordnen, ändern Sie die Commit-Hashes. Durch erneutes Basieren (wenn es etwas tut) werden Commit-Hashes geändert. Das Ergebnis des Ausführens
git rebase master dev
, bei demdev
die Synchronisierung nicht stimmtmaster
, erzeugt neue Commits (und damit Hashes) mit demselben Inhalt wie die aktivierten,dev
jedoch mit denmaster
vor ihnen eingefügten Commits .Sie können auf verschiedene Weise in eine solche Situation geraten. Zwei Möglichkeiten, die ich mir vorstellen kann:
master
die Sie Ihredev
Arbeit stützen möchtendev
die bereits an einem entfernten geschoben worden sind, die Sie dann zu ändern gehen (reword Commit - Nachrichten, Neuordnungs Commits, Squash Commits, etc.)Lassen Sie uns besser verstehen, was passiert ist - hier ein Beispiel:
Sie haben ein Repository:
Anschließend ändern Sie die Commits.
(Hier müssen Sie mein Wort dafür nehmen: Es gibt eine Reihe von Möglichkeiten, Commits in Git zu ändern. In diesem Beispiel habe ich die Zeit von geändert
C3
, aber Sie fügen neue Commits ein, ändern Commit-Nachrichten, ordnen Commits neu an. Squashing Commits zusammen usw.)Hier ist es wichtig zu beachten, dass die Commit-Hashes unterschiedlich sind. Dies ist das erwartete Verhalten, da Sie etwas (irgendetwas) an ihnen geändert haben. Das ist okay, ABER:
Wenn Sie versuchen zu pushen, wird ein Fehler angezeigt (und ein Hinweis darauf, dass Sie ausgeführt werden sollten
git pull
).Wenn wir laufen
git pull
, sehen wir dieses Protokoll:Oder anders gezeigt:
Und jetzt haben wir doppelte Commits vor Ort. Wenn wir laufen
git push
würden, würden wir sie an den Server senden.Um dieses Stadium nicht zu erreichen, hätten wir laufen können
git push --force
(wo wir stattdessen gelaufen sindgit pull
). Dies hätte unsere Commits mit den neuen Hashes ohne Probleme an den Server gesendet. Um das Problem zu diesem Zeitpunkt zu beheben, können wir vor dem Ausführen auf Folgendes zurücksetzengit pull
:Schauen Sie sich das reflog (
git reflog
) an, um zu sehen, was der Commit-Hash war, bevor wir ausgeführt wurdengit pull
.Oben sehen wir, dass dies
ba7688a
das Commit war, an dem wir vor dem Laufen teilgenommen habengit pull
. Mit diesem Commit-Hash in der Hand können wir auf that (git reset --hard ba7688a
) zurücksetzen und dann ausführengit push --force
.Und wir sind fertig.
Aber warte, ich habe die Arbeit weiterhin auf die doppelten Commits gestützt
Wenn Sie irgendwie nicht bemerkt haben, dass die Commits dupliziert wurden, und weiterhin auf doppelten Commits arbeiten, haben Sie sich wirklich selbst durcheinander gebracht. Die Größe des Chaos ist proportional zur Anzahl der Commits, die Sie auf den Duplikaten haben.
Wie das aussieht:
Oder anders gezeigt:
In diesem Szenario möchten wir die doppelten Commits entfernen, aber die darauf basierenden Commits beibehalten - wir möchten C6 bis C10 beibehalten. Wie bei den meisten Dingen gibt es eine Reihe von Möglichkeiten, dies zu tun:
Entweder:
cherry-pick
jedes Commit (C6 bis einschließlich C10) für diesen neuen Zweig, und behandeln Sie diesen neuen Zweig als kanonisch.git rebase --interactive $commit
, wo$commit
sich das Commit vor den beiden duplizierten Commits befindet. 2 . Hier können wir die Zeilen für die Duplikate sofort löschen.1 Es spielt keine Rolle, welche der beiden Sie wählen
ba7688a
oder ob sie gut2a2e220
funktionieren.2 Im Beispiel wäre es
85f59ab
.TL; DR
Stellen Sie ein
advice.pushNonFastForward
auffalse
:quelle
git push
's--force-with-lease
heutzutage zu verwenden, da es eine bessere Standardeinstellung istIch denke, Sie haben bei der Beschreibung Ihrer Schritte ein wichtiges Detail übersprungen. Genauer gesagt, Ihr letzter Schritt
git push
auf dev hätte Ihnen tatsächlich einen Fehler gegeben, da Sie normalerweise keine nicht schnell vorlaufenden Änderungen vornehmen können.Sie haben dies also
git pull
vor dem letzten Push getan , was zu einem Zusammenführungs-Commit mit C6 und C6 'als Eltern führte, weshalb beide im Protokoll aufgeführt bleiben. Ein hübscheres Protokollformat hat möglicherweise deutlicher gemacht, dass es sich um zusammengeführte Zweige doppelter Commits handelt.Oder Sie haben stattdessen eine
git pull --rebase
(oder ohne explizite,--rebase
wenn dies durch Ihre Konfiguration impliziert wird) erstellt, die die ursprünglichen C5 und C6 in Ihrem lokalen Entwickler zurückzog (und die folgenden auf neue Hashes umstellte, C7 'C5' 'C6'). ').Ein Ausweg hätte
git push -f
darin bestehen können, den Push zu erzwingen, wenn der Fehler aufgetreten ist, und C5 C6 vom Ursprung zu löschen. Wenn jedoch jemand anderes sie auch ziehen ließ, bevor Sie sie abwischten, würden Sie viel mehr Probleme haben. Grundsätzlich müsste jeder, der C5 C6 hat, spezielle Schritte unternehmen, um sie loszuwerden. Genau aus diesem Grund heißt es, Sie sollten niemals etwas neu veröffentlichen, was bereits veröffentlicht wurde. Es ist jedoch immer noch machbar, wenn das "Veröffentlichen" in einem kleinen Team erfolgt.quelle
git pull
ist entscheidend. Ihre Empfehlunggit push -f
, obwohl gefährlich, ist wahrscheinlich das, wonach Leser suchen.git push --force
, nur um zu sehen, was Git tun würde. Ich habe seitdem eine Menge über Git gelernt und heutzutagerebase
gehört es zu meinem normalen Workflow. Ichgit push --force-with-lease
vermeide es jedoch, die Arbeit eines anderen zu überschreiben.--force-with-lease
ist eine gute Standardeinstellung, ich werde auch einen Kommentar unter meiner AntwortIch fand heraus, dass dieses Problem in meinem Fall die Folge eines Git-Konfigurationsproblems ist. (Mit Pull and Merge)
Beschreibung des Problems:
Sympthome: Commits, die nach dem Rebase auf dem untergeordneten Zweig dupliziert wurden, was zahlreiche Zusammenführungen während und nach dem Rebase impliziert.
Workflow: Hier sind die Schritte des Workflows, den ich ausgeführt habe:
Als Konsequenz dieses Workflows Duplizieren aller Commits von "Feature-Branch" seit vorheriger Rebase ... :-(
Das Problem war auf das Ziehen von Änderungen des untergeordneten Zweigs vor der erneuten Basis zurückzuführen. Die Standard-Pull-Konfiguration von Git ist "Merge". Dies ändert die Indizes der Commits, die für den untergeordneten Zweig ausgeführt werden.
Die Lösung: Konfigurieren Sie in der Git-Konfigurationsdatei Pull so, dass es im Rebase-Modus funktioniert:
Hoffe es kann JN Grx helfen
quelle
Möglicherweise haben Sie aus einem anderen Zweig als Ihrem aktuellen Zweig gezogen. Zum Beispiel haben Sie möglicherweise vom Master abgerufen, wenn Ihre Niederlassung entwickelt wird. Git zieht pflichtbewusst doppelte Commits ein, wenn es aus einem nicht verfolgten Zweig gezogen wird.
In diesem Fall können Sie Folgendes tun:
wo
n == <number of duplicate commits that shouldn't be there.>
Stellen Sie dann sicher, dass Sie aus dem richtigen Zweig ziehen, und führen Sie dann Folgendes aus:
Durch Ziehen mit
--rebase
wird sichergestellt, dass Sie keine überflüssigen Commits hinzufügen, die den Commit-Verlauf beeinträchtigen könnten.Hier ist ein bisschen Hand halten für Git Rebase.
quelle