Wie habe ich die Ströme überquert, und wie kann ich sie entkreuzen?

8

Ich habe git die meiste Zeit eines Jahres gerne benutzt, und unser Team benutzt das git-flow-Modell (obwohl es nicht git-flow ist). Letzte Woche habe ich einen Release Branch erstellt und habe die Änderungen glücklicherweise wieder in den Zweig development / instable zusammengeführt - bis heute etwas sehr Seltsames passiert ist.

Irgendwie wurde der Release-Zweig hyper-fusioniert oder so. Ich kann mir ehrlich gesagt keinen besseren Weg vorstellen es zu beschreiben als "die Flüsse zu überqueren". Hier ist ein Visual von Git Extensions:

Ich verschleiere die meisten Commit-Kommentare, sorry. Aber von unten beginnend, können Sie den Entwicklungszweig auf der linken deutlich sehen, und der Release-Zweig auf der rechten wird regelmäßig in ihn eingefügt. Bis etwa zur Hälfte, als ich mit der Zusammenführung etwas falsch gemacht haben musste, weil zu diesem Zeitpunkt der Release-Zweig wörtlich mit dem Entwicklungszweig verschmolzen ist - sie scheinen tatsächlich zu teilen Merge-Commit, das nur im Entwicklungszweig sein sollte.

GitHub bietet eine etwas klarere Sicht:

Das sieht nicht so ungewöhnlich aus, außer dass die blauen und schwarzen Linien der selbe Zweig sind. Nur um das Offensichtliche anzukreuzen:

  • Es gibt Commits von anderen Mitwirkenden, aber die spezifischen Commits sind von mir. Ich weiß, ich kann den Commit-Nachrichten vertrauen.

  • Die Commit-Nachrichten all sagen dasselbe: "Verzweigung 'release-1.3' in develop migrieren." Ich weiß also, dass ich zum Beispiel den Entwicklungszweig nicht versehentlich in den Freigabezweig eingefügt habe.

  • Ich habe nie neue Zweige erstellt oder andere Befehle als git pull --rebase , git commit und git merge verwendet. Ich habe nicht experimentiert oder versucht, etwas Kreatives mit dem Repository zu machen.

Es sieht so aus, als hätte ich den ursprünglichen Zweig release-1.3 abgelegt und einen neuen Eintrag aus dem Zweig develop nahe der Mitte erstellt. Aber ich das nicht. Der Zweig release-1.3 war die ganze Zeit aktiv. Ich schwöre, dass die blauen und schwarzen Commits wirklich der gleiche Zweig sind und dass ich nie irgendwelche Merges gemacht habe, außer sie beide in den Entwicklungszweig (pink) zu verschmelzen.

Ich habe also zwei Fragen:

  1. Wie ist das überhaupt möglich? Ich verstehe technisch wie es möglich ist, mit Git-Commits als Graph-Knoten und all dem, aber ich kann nicht ganz finde heraus, wie dies aus prozeduraler Sichtweise geschehen ist. Welchen Fehler hätte ich machen können, und wie kann ich es vermeiden, es noch einmal zu tun?

  2. Wie kann ich diese Zweige entwirren , so dass ich nicht einen Haufen halbfertigen Code aus dem unstable-Zweig in meinem blitzsauberen Release-Zweig habe? Es sollte nur wie zwei parallele Linien aussehen, die gelegentlich durch Zusammenführungen verbunden sind. Am liebsten würde ich ohne eine erzwungene Push- oder destruktive Rebase machen, da dies ein gemeinsames Repository ist, obwohl es ein kleines Team und ein privates Repository ist, damit ich Leute dazu bringen kann, sie erneut zu klonen absolut notwendig.

Aaronaught 10.07.2013, 23:55
quelle

2 Antworten

4

Die Möglichkeiten

Ich kann mir ein paar Wege vorstellen, wie dies hätte passieren können.

  • Schnellzusammenführung. Ich glaube, dass dies die wahrscheinlichste Ursache ist. Dies ist, was ich glaube passiert ist:

    1. release-1.3 wurde in develop zusammengeführt
    2. unmittelbar danach, develop wurde im Schnellvorlauf in release-1.3 zusammengeführt


    Das ist alles. release-1.3 wurde mit develop zusammengeführt, bevor zusätzliche Commits für release-1.3 ausgeführt wurden, führte jemand develop in release-1.3 zusammen. Wenn möglich, verwendet git standardmäßig eine Schnellvorlauf-Zusammenführung (ein "Feature", das die Hälfte der Zeit falsch ausführt), weshalb das Diagramm verwirrend aussieht.

    Beachten Sie, dass eine Schnellvorlauf-Zusammenführung im resultierenden Diagramm keinen direkten Hinweis enthält. Im Gegensatz zu einer normalen Zusammenführung erstellt eine Schnellvorlauf-Zusammenführung kein neues Festschreibungsobjekt und keine bestehende Festschreibung wird geändert. Bei einer Schnellvorlauf-Zusammenführung wird die Verzweigungsreferenz einfach so angepasst, dass sie auf eine bestehende Festschreibung zeigt.

    Auch wenn es keinen direkten Beweis für eine Fast-Forward-Zusammenführung gibt, zeigt die Tatsache, dass Sie diesen Commit für die Zusammenführung erreichen können, indem Sie den ersten Parent-Pfad jedes Zweiges verfolgen, stark darauf hin, dass dies ein Ergebnis einer Schnellvorlauf-Zusammenführung war / p>

  • Accidental git branch anstelle von git checkout . Bei einem Projekt, an dem ich gerade arbeitete, machte ein anderer Git-Entwickler den Fehler, git branch foo einzugeben, um zum Zweig zu wechseln %Code%. Das ist ein vollkommen natürlicher Fehler, den sogar ein Experte machen kann, wenn er müde ist. Wie auch immer, dieser Fehler führte schließlich zu etwas, das wie eine Schnellvorlauf-Zusammenführung aussah, obwohl foo nie getippt wurde. Ähnliches könnte hier geschehen sein. So spielt das Szenario ab:

    1. Der Benutzer hat den Zweig git merge ausgecheckt, und develop zeigt zufällig auf den Zusammenführungs-Commit, der im Mittelpunkt dieses Mysteriums steht.
    2. Der Benutzer möchte zur Arbeit develop wechseln, aber versehentlich release-1.3 anstelle von git branch release-1.3 .
    3. eingeben
    4. Da es sich um einen frischen Klon handelt, gibt es noch keinen lokalen git checkout release-1.3 Zweig (nur release-1.3 ). Daher erstellt Git glücklich einen neuen lokalen Zweig mit dem Namen origin/release-1.3 , der auf denselben Merge-Commit verweist.
    5. Einige Zeit vergeht, während der Benutzer einige Dateien bearbeitet.
    6. Vor dem Festschreiben führt der Benutzer release-1.3 aus. Da der aktuelle Zweig immer noch git status und nicht develop ist, gibt Git "On branch develop" aus.
    7. Der Benutzer wird überrascht und denkt: "Habe ich nicht schon vor langer Zeit auf Release-1.3 gewechselt? Na ja, ich muss vergessen haben, die Zweige zu wechseln."
    8. Der Benutzer führt release-1.3 aus, dieses Mal erinnert er sich an den richtigen Befehl.
    9. Der Benutzer erstellt ein Commit und führt git checkout release-1.3 .
    10. aus
    11. Das Standard-Push-Verhalten von Git (siehe git push in push.default ) ist git help config . Obwohl matching keinen konfigurierten Upstream-Zweig hat, wählt release-1.3 den git push -Zweig des Upstream, an den Push gesendet werden soll .
    12. Die neue Version von release-1.3 ist ein Nachkomme des vorherigen release-1.3 , so dass das Remote-Repository die Push-Funktion gerne akzeptiert.


    Dies ist alles, was Sie benötigen, um das Diagramm zu erstellen, das Sie in Ihrer Frage angegeben haben.

Angenommen, release-1.3 wurde absichtlich in develop zusammengeführt

Wenn die Zusammenführung von release-1.3 in develop beabsichtigt war (jemand hat eine bewusste Entscheidung getroffen, dass release-1.3 gut genug ist), ist das völlig normal und korrekt. Trotz der visuellen Unterschiede befinden sich die blauen und schwarzen Linien auf dem Zweig develop ; Die blaue Linie passiert einfach mit auch im release-1.3 Zweig.

Das einzige, was falsch ist, ist, dass es für jemanden, der die Geschichte überprüft, etwas peinlich ist, herauszufinden, was vor sich geht (sonst hättest du diese Frage nicht). Um dies zu vermeiden, befolgen Sie die folgenden Faustregeln:

  • Wenn Sie zwei unterschiedlich benannte Zweige zusammenführen (z. B. develop und develop , dann immer release-1.3 .
  • Wenn Sie zwei Versionen derselben Verzweigung zusammenführen (z. B. git merge --no-ff und develop ), dann tun immer origin/develop . Wenn das fehlschlägt, weil Sie nicht schnell vorspulen können, ist es Zeit für git merge --ff-only .

Wenn Sie die obigen Faustregeln befolgt hätten, dann hätte das Diagramm so ausgesehen:

%Vor%

Beachten Sie, dass dieser zusätzliche Merge-Commit den Verlauf deutlich lesbarer macht.

Wenn die Zusammenführung von git rebase in develop ein Fehler war

Doh! Sieht so aus, als hättest du etwas Rebasing und Force-Pushing zu tun. Dies wird die anderen Benutzer dieses Repositorys nicht glücklich machen.

So können Sie es beheben:

  1. Führen Sie release-1.3 .
  2. aus
  3. Finde das Sha1 dieses mittleren Commits (wo die zwei Zweige zusammenkommen). Nennen wir es git checkout release-1.3 .
  4. Führen Sie X aus. Das resultierende Diagramm sieht folgendermaßen aus:

    %Vor%

    Dies behebt den git rebase --onto X^2 X Zweig, aber beachte, dass du nun zwei Versionen des release-1.3 Commits hast. Die nächsten Schritte entfernen diese Duplikate aus dem Zweig release-1.3 .

  5. Führen Sie develop aus.
  6. Führen Sie git checkout develop aus, um als temporärer Platzhalter für dieses Commit zu fungieren.
  7. Führen Sie git branch temp aus, um zwei Commits aus dem Zweig git reset --hard HEAD^^ zu entfernen: den Befehl tip develop und das Commit, bei dem die alte Version von develop in release-1.3 eingefügt wird. Wir werden das Tip-Commit später wiederherstellen.
  8. Führen Sie develop aus, um das zweite Commit für den neuen Zweig git merge --no-ff release-1.3^ und seine Vorfahren in release-1.3 .
  9. zusammenzuführen
  10. Führen Sie develop aus, um das in Schritt 6 entfernte Tipp-Commit zurückzuholen.
  11. Führen Sie git cherry-pick temp aus, um den temporären Platzhalterzweig zu entfernen. Ihr Diagramm sollte nun so aussehen:

    %Vor%
  12. Führen Sie git branch -D temp aus, um die Upstream-Zweige zu erzwingen.

Verhindert, dass dies in der Zukunft erneut passiert

Wenn Sie Kontrolle über das Upstream-Repository haben und einige Hooks installieren können, können Sie einen Hook erstellen, der alle Pushs ablehnt, bei denen die alte Version der Verzweigung nicht erreichbar ist, indem Sie bei der neuen Version der Verzweigung beginnen und die erste durchlaufen -Parenter Pfad Dies hat auch den Vorteil, dass diese dummen Commits, die von git push -f origin release-1.3 develop erstellt wurden, abgelehnt werden.

    
Richard Hansen 11.07.2013, 04:20
quelle
2
  1. Nicht sicher, über reine Spekulation hinaus. Wenn Sie eine git log --decorate --graph --all --oneline und eine git reflog release-1.3 (und vielleicht eine Shell-Historie) angeben können, können wir Ihnen vielleicht helfen.

  2. Dies beinhaltet einen Kraftstoß. Sprich mit deinen Teamkollegen darüber. Ich kenne Ihre Hashes nicht, da Sie sie nicht zur Verfügung gestellt haben. Ersetzen Sie <blah> durch den entsprechenden Hash.

    %Vor%
Peter Lundgren 11.07.2013 00:15
quelle

Tags und Links