2017-10-12 4 views
1

Ich habe an einem Feature Zweig für ein paar Tage gearbeitet und es ist jetzt bereit, in dev zu verschmelzen. Während der Arbeit an dieser Funktion habe ich mit dev verschmolzen, um einen Patch zu erhalten. Meine Geschichte sieht wie folgt aus:Wie komprimiere ich Commits, wenn ich mit Dev dazwischen fusioniert bin?

* E (feature1) 
* D:merge with dev 
| \ 
* C * B:patch (dev) 
    \ | 
    * A 

Ich mag würde die gesamte Branche in einem Squash commit, fusionieren mit dev und dann vorspulen dev. Das Problem ist, E kann nicht mit C gequetscht werden, wie die Zusammenführung zwischen ihnen kommt. Die einzige Option scheint Squash E, B und C zu sein (rufen Sie das neue Commit F auf). In diesem Fall enthält das gequetschte Commit auch Änderungen, die Teil eines irrelevanten Patches waren. Nach der Zusammenführung zu dev gibt es zwei Commits, die den Patch anwenden: F (der den Patch anwendet und die Funktion hinzufügt) und B (der nur den Patch anwendet). Außerdem wird F jetzt zwei unveränderte Änderungen vornehmen.

Gibt es einen Ausweg, der meine Geschichte schön und sauber hält? Muss ich meinen Workflow ändern?

+0

Empfohlene Workflow-Änderung: niemals fusionieren dev. Stattdessen Rebase darauf. Sie sollten das beheben können, indem Sie einfach eine Rebase auf "dev" machen. – o11c

+0

Vereinbarte (beide). Werde es versuchen – lfk

+0

@ o11c - Rebasing ändert Ihre Branche Geschichte. Während ich zufällig ein Fan bin, kann es manchmal ein bisschen gefährlich sein, besonders wenn du nicht weißt, was du tust. Außerdem wird das Rebasieren bei Konflikten sehr ärgerlich, da Konflikte bei jedem Rebase-Vorgang neu aufgelöst werden müssen. Bei einer Zusammenführung können Sie die Konflikte einmal beheben und dann weitermachen. – JDB

Antwort

0

Git registriert keine Änderungen von Commits. Jedes Commit enthält eine vollständige Kopie der Dateien im Repo. "Changes" werden bestimmt, indem zwei Commits unterschieden werden.

Also, kurz gesagt, es gibt absolut kein Problem mit Quetschen E, B und C in F begehen und dann, dass auf den dev Zweig zu verschmelzen. Das Commit B wird weiterhin auf dem Dev-Zweig existieren. Wenn git F mit B vergleicht, werden nur die von C und E eingeführten Änderungen F zugeordnet.

Sie können dieses wahrgenommene Problem natürlich umgehen, indem Sie git rebase verwenden, aber das kommt mit seinen eigenen Kopfschmerzen. Zum Beispiel, da git rebase Ihren Zweigverlauf ändert (Verschieben Ihrer Commits über den letzten Commit vom Entwickler), müssen Konflikte bei Konflikten jedes Mal neu gelöst werden, wenn Sie einen Rebase durchführen. Das wird schnell alt, wenn Ihr Problem eine Weile dauert, bis mehrere Fehler behoben sind.


Nur um zu zeigen, dass das alles wahr ist und dass Sie nichts zu befürchten, ich habe Setup ein Beispiel GitHub Repo: https://github.com/cyborgx37/sandbox

Zu Beginn haben wir die dev branch, die das hat B commit.

B:patch 
| 
A 

Dann habe ich die feature1 branch, die C, D und E hat begeht. (Beachten Sie, dass, da D eine Zusammenführung war und hat somit zwei Eltern, B zeigt sich auch in der Geschichte begehen up)

E 
| 
D:merge with dev 
|\ 
C \ 
| B 
A 

Schließlich gibt die dev-with-feature1 branch ist.

F 
| 
B:patch 
| 
A 

Ich habe diese abzweigen von Entwickler, verwendet dann

git merge --squash feature1 
git commit -m "F" 

alle feature1 Squash ‚s einen einzigen begeht in begehen, F.

Wenn Sie die diff for the F commit untersuchen, werden Sie sehen, dass es den Patch nicht anwendet. Da B already contains those changes und F sie einfach wiederholt, verbindet git sie nicht mit F.

Aus einer anderen Perspektive, here's the blame:

initial  hello! 
B:patch  patch! 
F   new feature!!! 

Git verfolgen keine Änderungen in Commits. Es speichert Ihren vollständigen Projektstatus. "Änderungen" werden bestimmt, indem ein Commit mit seinem übergeordneten (oder Vorgänger-) Commit verglichen wird. Weil B den Patch hat, verbindet sich Git mit B. Also, es wird erwartet, dass der Patch auch in F sein würde. Die einzige Möglichkeit, die es in F nicht wäre, ist, wenn Sie den Patch gelöscht haben.

+0

Denken Sie darüber nach: Die Commit-Nachricht für F besagt, dass sie feature1 implementiert. Aber in Wirklichkeit, wenn du in Dev von F^zu F wechselst, bekommst du auch den Patch. Grundsätzlich ist die Commit-Nachricht gelogen. – lfk

+0

Vielleicht verstehe ich nicht richtig. Planen Sie "B" aus dem Dev-Zweig zu entfernen? Wenn nicht, dann gibt es kein Problem. 'F' * sollte *' B' enthalten, weil 'F' hinter' B' steht. 'F' enthält eine vollständige Kopie aller Dateizustände. Wenn Sie also versuchen, festzustellen, welche Änderungen durch' F' verursacht wurden, vergleicht git 'F' mit' B' und gibt Ihnen den Unterschied. Da der Patch bereits in "B" war, wird git ihn nicht als "gehörig" zu "F" betrachten. – JDB

+0

@Farshid - Denken Sie an Git wie ein Ordner voller Zip-Dateien.Jede Zip-Datei hat einen Datumsstempel, so dass Sie die Reihenfolge verfolgen können. Jede Zip-Datei enthält den vollständigen Quellcode, wie er an diesem Datum angezeigt wurde. Wenn Sie wissen möchten, was an einem bestimmten Tag eingeführt wurde, vergleichen Sie den Zip dieses Tages mit dem vorherigen Zip. Das ist im Grunde wie Git funktioniert ... jedes Commit ist eine vollständige Kopie aller Dateizustände, ** nicht ** eine Aufzeichnung der Änderungen. – JDB

0

Wenn ich richtig verstehe, möchten Sie den gesamten Inhalt von Commit E als ein einziges Commit auf B angewendet haben.

Wenn das, was Sie erreichen möchten, können Sie git checkout E . verwenden können (vergessen Sie nicht die "."):

# go to your `dev` branch : 
git checkout dev 

# get the *content* of E (here comes the ".") : 
git checkout E . 

# all the content of E should appear as modifications staged for commit : 
git status -sb 

# you can double check that the content is to your liking : 
git diff --cached # --cached means 'compare with the index' 
gitk --cached  # as opposed to 'compare with what is on the disk' 

# commit 
git commit 
+0

Das ist eine sehr interessante Methode. Ich kann jedoch mindestens ein Problem erkennen: Sie werden wissen, ob das zusammengeführte Ergebnis erst nach dem Entwickeln funktioniert, im Gegensatz zum Zusammenführen (oder Rebasieren) des Devs, Testen und dann schnellem Weiterleiten. Natürlich muss man es nicht im Dev festschreiben, wenn es nicht funktioniert. Ein weiteres Problem besteht darin, dass Sie kein Merge-Commit erstellen können, um einen guten Verlauf zu behalten. – lfk

0

Hier ist, was ich getan habe: Ich zerquetscht E, B und C in eine F neue begehen , mit der Nachricht für F sagen, dass es Feature1 implementiert (beachten Sie, dass es auch den Patch hinzufügt). Ich habe dann auf dev rebased. Jetzt sind die Commit-Nachricht und der Verlauf korrekt: F enthält das Patch, aber es wurde nicht hinzugefügt - es wurde durch ein vorheriges Commit hinzugefügt.

Schließlich fusionierte ich mit dev (mit --no-ff, um eine Zusammenführung zu erzwingen).

In Zukunft werde ich vermeiden, mit dev und Rebase stattdessen zu verschmelzen.

Verwandte Themen