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 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:
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?
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.
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:
release-1.3
wurde in develop
zusammengeführt
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:
git merge
ausgecheckt, und develop
zeigt zufällig auf den Zusammenführungs-Commit, der im Mittelpunkt dieses Mysteriums steht. develop
wechseln, aber versehentlich release-1.3
anstelle von git branch release-1.3
. 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. release-1.3
aus. Da der aktuelle Zweig immer noch git status
und nicht develop
ist, gibt Git "On branch develop" aus. release-1.3
aus, dieses Mal erinnert er sich an den richtigen Befehl. git checkout release-1.3
. 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 . 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.
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:
develop
und develop
, dann immer release-1.3
. 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.
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:
release-1.3
. git checkout release-1.3
. Führen Sie X
aus. Das resultierende Diagramm sieht folgendermaßen aus:
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
.
develop
aus.git checkout develop
aus, um als temporärer Platzhalter für dieses Commit zu fungieren. 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. 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
. develop
aus, um das in Schritt 6 entfernte Tipp-Commit zurückzuholen. Führen Sie git cherry-pick temp
aus, um den temporären Platzhalterzweig zu entfernen. Ihr Diagramm sollte nun so aussehen:
Führen Sie git branch -D temp
aus, um die Upstream-Zweige zu erzwingen.
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.
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.
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.
Tags und Links git