git - Überspringen bestimmter Commits beim Zusammenführen

200

Ich benutze Git seit ungefähr einem Jahr und finde es fantastisch, aber ich habe gerade mit einer zweiten Version des Projekts begonnen und einen neuen Zweig dafür gestartet. Ich kämpfe ein wenig mit der besten Art und Weise, mit den zukünftigen Dingen umzugehen.

Ich habe zwei Zweige mit den Namen master10 (für v1) und master20 (für v2). Ich habe Fehlerbehebungen in Version 1 auf Zweig master10 vorgenommen und neue Inhalte von master20 entwickelt. Immer wenn ich einen Bugfix mache, füge ich ihn in v2 ein, indem ich master20 auschecke und mache git merge master10. So weit, ist es gut.

Jetzt habe ich jedoch eine Änderung in Version 1 vorgenommen, die ich in Version 2 nicht möchte, aber ich möchte weiterhin andere Fehlerkorrekturen zusammenführen. Wie kann ich Git anweisen, dieses bestimmte Commit (oder eine Reihe von Commits) zu überspringen, aber in Zukunft möchte ich noch andere Fehlerbehebungen zusammenführen.

Ich dachte, es git rebasekönnte das sein, was ich brauche, aber ich habe das Dokument gelesen und mein Kopf explodierte fast.

Ich denke, was ich will, ist so etwas wie ein "git sync" -Befehl, der git mitteilt, dass zwei Zweige jetzt synchron sind und in Zukunft nur die Commits ab diesem Synchronisierungspunkt zusammenführen.

Jede Hilfe geschätzt.

Brad Robinson
quelle

Antworten:

289

Wenn Sie beispielsweise die meisten, aber nicht alle Commits in Zweig "main" mit "master" zusammenführen möchten, können Sie dies tun. Es erfordert einige Arbeit - wie oben erwähnt, besteht der übliche Anwendungsfall darin, alles aus einem Zweig zusammenzuführen - aber manchmal kommt es vor, dass Sie eine Änderung an einer Release-Version vorgenommen haben, die nicht wieder integriert werden sollte (möglicherweise der Code) wurde bereits im Master abgelöst), wie repräsentieren Sie das? Hier geht...

Nehmen wir also an, bei der Wartung wurden 5 Änderungen angewendet, und eine davon (Wartung ~ 3) soll nicht wieder in den Master eingefügt werden, obwohl alle anderen Änderungen vorgenommen werden sollten. Sie tun dies in drei Schritten: Führen Sie tatsächlich alles vor diesem Schritt zusammen, sagen Sie git, dass Sie main ~ 3 als zusammengeführt markieren sollen, auch wenn dies nicht der Fall ist, und führen Sie dann den Rest zusammen. Die Magie ist:

bash <master>$ git merge maint~4
bash <master>$ git merge -s ours maint~3
bash <master>$ git merge maint

Der erste Befehl führt alles zusammen, bevor Ihr mühsames Maint Commit auf den Master übertragen wird. Die Standardnachricht für das Zusammenführungsprotokoll erklärt, dass Sie "Zweig 'Wartung' (früher Teil)" zusammenführen.

Der zweite Befehl führt das lästige Maint ~ 3-Commit zusammen, aber die Option "-s our" weist git an, eine spezielle "Merge-Strategie" zu verwenden, die tatsächlich funktioniert, indem einfach der Baum, in den Sie zusammenführen, beibehalten und die Commits ignoriert werden ) Sie verschmelzen vollständig. Es wird jedoch immer noch ein neues Zusammenführungs-Commit mit HEAD und Maint ~ 3 als Eltern durchgeführt, sodass das Revisionsdiagramm jetzt besagt, dass Maint ~ 3 zusammengeführt wird. In der Tat möchten Sie wahrscheinlich auch die Option -m verwenden, um 'Merge' zu machen, um zu erklären, dass dieses Maint ~ 3-Commit tatsächlich ignoriert wird!

Der letzte Befehl führt einfach den Rest der Wartung (main ~ 2..maint) in den Master ein, sodass Sie alle wieder synchronisiert sind.

araqnid
quelle
5
Ich denke, wenn Sie das Zusammenführen dieses Commits verschieben müssen, haben Sie keine andere Wahl, als es zu überspringen (unsere zusammenführen) und es später mit dem Befehl cherry-pick anzuwenden. Sobald das Commit vom Master aus erreichbar ist, kann es nicht mehr zusammengeführt werden. Das zweimalige Zusammenführen derselben Änderung ist eines der Hauptziele des Git.
Araqnid
3
In Bezug auf Ihr Unterzweigbeispiel: Ich vermute, dass Sie sich nach dem Zusammenführen des Unterzweigs in genau der gleichen Situation befinden wie nach dem zweiten Schritt meines Beitrags. Das Erstellen zusätzlicher Zweige hat keinen Einfluss auf die Festschreibungsbeziehungen.
Araqnid
5
Wenn Sie nur aus Interesse eine Änderung weglassen möchten, warum sollten Sie dann nicht einfach eine einzelne Zusammenführung durchführen und dann diese eine Änderungsmenge zurücksetzen, anstatt drei Zusammenführungen durchzuführen? Dies würde dazu führen, dass weniger Änderungssätze in das Repository übernommen werden und der Verlauf expliziter wird.
Mark Booth
3
Oft ist es einfacher, die Commits explizit zu benennen. Sie müssen also nur das Git-Protokoll des zu verschmelzenden Zweigs anzeigen und die Hashes des Commits notieren, die nicht zusammengeführt werden sollen, und das
vorhergehende
14
@MarkBooth: Das Commit, das Sie überspringen möchten, befindet sich möglicherweise in einem großen Konflikt mit dem Zweig, in dem Sie zusammenführen möchten. Es ist einfacher, es einfach zu überspringen, anstatt die Konflikte zu beheben, diese Änderung dann
rückgängig zu machen
39

IMHO ist es am logischsten, alles zusammenzuführen und dann mit git revert (commit_you_dont_want) zu entfernen .

Beispiel:

git merge master
git revert 12345678

Wenn Sie mehrere Commits zum Ignorieren haben oder die Nachricht zum Zurücksetzen bearbeiten möchten:

git merge master
git revert -n 123456
git revert -n abcdef
git commit -m "... Except commits 123456 and abcdef"

Dann könnte Ihre Geschichte aussehen wie:

| ... Except 123456 and abcdef
|\ Merge branch 'master' into 'your_branch'

Wenn Sie Konflikte haben, die NUR diese "zu ignorierenden" Commits betreffen, können Sie Folgendes verwenden:

git merge master -X ours

Ihre Version bleibt also über der anderen bestehen. Auch ohne Fehlermeldungen können Sie diese unerwünschten Festschreibungen "zurücksetzen", da sie möglicherweise andere Änderungen aufweisen, die nicht in Konflikt geraten sind, und Sie möchten sie dennoch nicht.

Wenn Sie Konflikte haben, die NICHT NUR die "zu ignorierenden" Commits betreffen, sollten Sie sie manuell lösen, und Sie müssen sie wahrscheinlich während des Zurücksetzens erneut lösen.

Alexandre T.
quelle
2
Wenn Sie diese zurückgesetzten Commits später in dem fraglichen Zweig zusammenführen möchten, wird Git sie dann trotzdem ignorieren?
Anriëtte Myburgh
@ AnriëtteMyburgh Sie können die Umkehrungs-Commits zurücksetzen, um sie später in etwas zusammenzuführen, was Sie mit der Strategie "Zusammenführen unserer" eigentlich nicht so einfach tun können.
Lily Chung
Vielen Dank, genau das brauchte ich, um ein paar ältere Commits in einem Feature-Zweig zu haben, die ich im Master nicht wollte, und ein paar, die ich im Master haben wollte. Schön und sauber.
Vale Trujillo
17

Zu den Commits gehört die Abstammung. Sie können ein Commit nicht zusammenführen, ohne vorherige Commits zusammenzuführen.

Sie können sie natürlich pflücken. Das ist ein guter Ablauf, wenn Sie einen Zweig haben, der sich im Wartungsmodus befindet.

Dustin
quelle
1
Danke, Cherry Pick wird den Job machen. Nicht so schön wie ich es mir erhofft hatte, aber es wird reichen.
Brad Robinson
3

Eine Art Werbung für mein Projekt, die im Grunde den von @araqnid beschriebenen Prozess umschließt.

Es ist eine Art Helfer, der folgenden GIT-Flow einführt:

  • Es gibt eine tägliche / wöchentliche Benachrichtigung über ausstehende Zusammenführungen von Wartungszweigen in Entwicklungs- / Hauptzweige
  • Der Filialleiter überprüft den Status und entscheidet selbst, ob alle Commits erforderlich sind, und blockiert entweder einige davon oder fordert die Entwickler auf, sich selbst zu blockieren. Am Ende wird der Wartungszweig in das Upsteam zusammengeführt.

Ein Zitat von der Projektseite:

Je nach Workflow können neben der Hauptniederlassung auch Wartungs- oder kundenspezifische Niederlassungen eingerichtet werden. Diese Zweige werden auch als LTS-Zweige bezeichnet.

Oft gehen die Hotfixes in die Zweige, in denen der Fehler gemeldet wurde, und dann wird das Commit wieder in den Hauptzweig zusammengeführt.

In der Regel müssen alle Zweige perfekt mit dem Master synchronisiert sein, dh Sie möchten ein klares Delta zwischen einem bestimmten Zweig und dem Master sehen, um zu verstehen, ob der Master alle Funktionen und Bugfixes enthält.

Manchmal möchten Sie jedoch keine bestimmten Commits, da diese kundenspezifisch sind und für andere Benutzer nicht sichtbar sein sollen. Oder Ihre Hauptniederlassung ist so weit auseinander gegangen, dass ein völlig anderer Ansatz zur Behebung des Problems erforderlich ist, oder noch besser, das Problem ist dort nicht mehr vorhanden.

Auch im Falle einer Kirschernte vom Master in den Wartungszweig wird das resultierende Commit im Master blockiert.

Dmytro
quelle
0

Erstellen Sie einen dritten Zweig für die gewünschten Änderungen in master10, jedoch nicht in master20. Betrachten Sie master10 immer als Ihren "Master", den stabilsten Zweig von allen. Der Zweig, mit dem alle anderen Zweige jederzeit synchron bleiben möchten.

wilhelmtell
quelle
Ich denke, das könnte funktionieren, aber ich habe mich bereits in diesen Zustand versetzt, und ein dritter Zweig würde mich wahrscheinlich noch mehr verwirren. :)
Brad Robinson
0

Anstelle von revertoder cherry-pickfür diesen Fall müssen Sie git dazu bringen, die Änderungen, die Sie überspringen, als älter als die von Ihnen vorgenommenen zu betrachten.

So:

  1. Führen Sie das letzte Commit vor den Commits zusammen, die Sie überspringen möchten. Dadurch werden natürlich alle Commits zuvor zusammengeführt. git merge ccc
  2. Führen Sie die Commits zusammen, die Sie überspringen möchten. git merge fff --no-commit
  3. Führen Sie alle Zusammenführungen durch, heben Sie alle Änderungen auf und machen Sie alle Änderungen rückgängig. (Vielleicht gibt es dafür narrensichere Befehle, aber ich würde diesen Teil nur in einer Benutzeroberfläche ausführen - wie auch immer Sie wissen, wie)
  4. Schließen Sie die leere Zusammenführung ab git merge --continue
  5. Führen Sie die Commits NACH dem überspringen, den Sie überspringen möchten. git merge source-branch-head

Nach Schritt 4 betrachtet git Ihren Zweig als aktueller als dieses Commit, da Sie sich bereits damit befasst haben (indem Sie IHRE Versionen der Dinge beibehalten).

Jason Kleban
quelle