Wie wählt man eine Reihe von Commits aus und führt sie in einem anderen Zweig zusammen?

Lesezeit: 9 Minuten

Wie wahlt man eine Reihe von Commits aus und fuhrt
Crazybyte

Ich habe folgendes Repository-Layout:

  • Hauptzweig (Produktion)
  • Integration
  • Arbeiten

Was ich erreichen möchte, ist, eine Reihe von Commits aus dem Working-Branch herauszupicken und mit dem Integration-Branch zusammenzuführen. Ich bin ziemlich neu in Git und kann nicht herausfinden, wie ich das genau machen soll (das Rosinenpicken von Commit-Bereichen in einem Vorgang, nicht das Zusammenführen), ohne das Repository durcheinander zu bringen. Irgendwelche Hinweise oder Gedanken dazu? Danke!

Wie wahlt man eine Reihe von Commits aus und fuhrt
VonC

Wenn es um eine Reihe von Commits geht, ist Rosinenpickerei angesagt ist war nicht praktisch.

Wie unten von Keith Kim erwähnt, hat Git 1.7.2+ die Möglichkeit eingeführt, eine Reihe von Commits auszuwählen (aber Sie müssen sich immer noch der Konsequenzen der Rosinenauswahl für zukünftige Zusammenführungen bewusst sein).

git cherry-pick“ gelernt, eine Reihe von Commits auszuwählen
(z.B “cherry-pick A..B” und “cherry-pick --stdin“), auch “git revert“; diese unterstützen die schönere Ablaufsteuerung nicht “rebase [-i]“ hat aber.

Damian kommentiert und warnt uns:

In dem “cherry-pick A..B” bilden, A sollte älter sein als B.
Wenn sie die falsche Reihenfolge haben, schlägt der Befehl stillschweigend fehl.

Wenn Sie die auswählen möchten Reichweite B durch D (einschließlich B) das wäre B^..D (anstatt B..D).
Siehe „Git erstellt einen Zweig aus einem Bereich früherer Commits?“ als Illustration.

Wie Jubobs in den Kommentaren erwähnt:

Dies setzt das voraus B ist kein Root-Commit; du bekommst ein “unknown revision“Fehler sonst.

Hinweis: Ab Git 2.9.x/2.10 (Q3 2016) können Sie eine Reihe von Commit direkt auf einem verwaisten Zweig (leerer Kopf) auswählen: siehe „Wie man einen bestehenden Zweig in Git zu einem verwaisten Zweig macht“.


Ursprüngliche Antwort (Januar 2010)

EIN rebase --onto wäre besser, wenn Sie den angegebenen Commit-Bereich über Ihrem Integrationszweig wiedergeben, wie Charles Bailey hier beschrieben hat.
(Suchen Sie auch nach „Hier ist, wie Sie einen Themenzweig basierend auf einem Zweig in einen anderen verpflanzen würden“ in der git rebase Manpageum ein praktisches Beispiel zu sehen git rebase --onto)

Wenn Ihr aktueller Zweig Integration ist:

# Checkout a new temporary branch at the current location
git checkout -b tmp

# Move the integration branch to the head of the new patchset
git branch -f integration last_SHA-1_of_working_branch_range

# Rebase the patchset onto tmp, the old location of integration
git rebase --onto tmp first_SHA-1_of_working_branch_range~1 integration

Das wird alles wiederholen zwischen:

  • nach dem Elternteil von first_SHA-1_of_working_branch_range (daher die ~1): das erste Commit, das Sie wiedergeben möchten
  • bis zu “integration” (der auf den letzten Commit zeigt, den Sie wiederholen möchten, von der working sich verzeigen)

zu “tmp” (was wohin zeigt integration zeigte vorher)

Wenn bei der Wiedergabe eines dieser Commits ein Konflikt auftritt:

  • entweder lösen und laufen “git rebase --continue“.
  • oder überspringen Sie diesen Patch und führen Sie stattdessen “git rebase --skip
  • oder brechen Sie das Ganze mit einem “git rebase --abort” (und legte die zurück integration Zweig auf der tmp sich verzeigen)

Nachdem rebase --onto, integration wird beim letzten Commit des Integrationszweigs zurück sein (das ist “tmp” Verzweigung + alle wiederholten Commits)

Beim Rosinenpflücken bzw rebase --ontovergessen Sie nicht, dass dies Auswirkungen auf nachfolgende Zusammenführungen hat, wie hier beschrieben.


Ein reines “cherry-pick„Lösung ist hier diskutiertund würde so etwas beinhalten wie:

Wenn Sie einen Patch-Ansatz verwenden möchten, sind „git format-patch|git am“ und „git cherry“ Ihre Optionen.
Zur Zeit, git cherry-pick akzeptiert nur einen einzigen Commit, aber wenn Sie den Bereich auswählen möchten B durch D das wäre B^..D in Git-Jargon, also

git rev-list --reverse --topo-order B^..D | while read rev 
do 
  git cherry-pick $rev || break 
done 

Aber wie auch immer, wenn Sie eine Reihe von Commits “wiederholen” müssen, sollte das Wort “Wiedergabe” Sie dazu bringen, das “rebase“Funktion von Git.

  • Wenn Sie Commits haben, die Eltern haben, die die -m Option, wie gehen Sie mit diesen Commits um? Oder gibt es eine Möglichkeit, diese Commits herauszufiltern?

    – Aug

    14. Juli 2016 um 19:16 Uhr


  • @aug -m soll sie für Sie handhaben, indem Sie die Hauptleitung auswählen, auf die durch die verwiesen wird -m Parameter, den Sie für dieses Rosinenpicken gewählt haben.

    – VonC

    14. Juli 2016 um 19:20 Uhr


  • Die Sache ist, wenn Sie eine Reihe von Commits aussuchen, werden die übergeordneten Commits korrekt ausgewählt, aber wenn es dann auf ein normales Commit trifft, schlägt es fehl und sagt, dass Commit kein Merge ist. Ich denke, meine Frage ist besser formuliert, wie man es passieren lässt -m Option nur, wenn es beim Rosinenpicken einer Reihe von Commits auf ein übergeordnetes Commit trifft? Gerade jetzt, wenn ich bestehe -m wie git cherry-pick a87afaaf..asfa789 -m 1 es gilt für alle Commits innerhalb des Bereichs.

    – Aug

    14. Juli 2016 um 19:25 Uhr


  • @aug Seltsam, ich habe das Problem nicht reproduziert. Was ist Ihre Git-Version und was ist die genaue Fehlermeldung, die Sie sehen?

    – VonC

    14. Juli 2016 um 19:36 Uhr

  • Ah, ich verwende Git-Version 2.6.4 (Apple Git-63). Der Fehler, den ich sehe, wäre so etwas wie error: Commit 8fcaf3b61823c14674c841ea88c6067dfda3af48 is a merge but no -m option was given. Ich habe tatsächlich erkannt, dass du es einfach könntest git cherry-pick --continue und es wäre in Ordnung (aber es würde das übergeordnete Commit nicht enthalten)

    – Aug

    14. Juli 2016 um 20:40 Uhr

1646895490 364 Wie wahlt man eine Reihe von Commits aus und fuhrt
Keith Kim

Ab git v1.7.2 kann Cherry Pick eine Reihe von Commits akzeptieren:

git cherry-pick gelernt, eine Reihe von Commits auszuwählen (z cherry-pick A..B und cherry-pick --stdin), tat es auch git revert; diese unterstützen die schönere Ablaufsteuerung nicht rebase [-i] hat aber.

  • Beachten Sie, dass cherry-pick A..B wird kein Commit A erhalten (Sie müssten A~1..B dafür), und wenn es irgendwelche Konflikte gibt, wird git nicht automatisch fortfahren, wie es rebase tut (zumindest ab 1.7.3.1)

    – Gabe Moothart

    1. März 2011 um 23:49 Uhr

  • Es ist auch gut, das zu beachten git cherry-pick A..B C funktioniert nicht so, wie Sie es erwarten würden, naiv. Es wird nicht alles im Bereich auswählen A..B und begehen C! Dazu müssen Sie zunächst in zwei Zeilen aufteilen git cherry-pick A..B und dann git cherry-pick C. Wenn Sie also einen Bereich haben, müssen Sie ihn separat ausführen.

    – MikroVirus

    10. Juni 2016 um 23:38 Uhr


Angenommen, Sie haben 2 Zweige,

„branchA“ : enthält Commits, die Sie kopieren möchten (von „commitA“ nach „commitB“

„branchB“ : der Branch, von dem die Commits von „branchA“ übertragen werden sollen

1)

 git checkout <branchA>

2) Holen Sie sich die IDs von “commitA” und “commitB”

3)

git checkout <branchB>

4)

git cherry-pick <commitA>^..<commitB>

5) Falls Sie einen Konflikt haben, lösen Sie ihn und geben Sie ihn ein

git cherry-pick --continue

um den Cherry-Pick-Prozess fortzusetzen.

  • Arbeitete wie Charme! Vielen Dank!

    – Snukone

    8. Mai 2020 um 11:18 Uhr

  • Was macht das “^” im Befehl “git cherry-pick ^..” bei 4)?

    – JVM

    25. August 2020 um 20:38 Uhr

  • @JVM stackoverflow.com/questions/2221658/…

    Benutzer10063119

    21. September 2020 um 10:11 Uhr


  • Jemand bearbeitet bitte den Beitrag, der die cherry-pick Bereich ist NICHT inklusive.

    – Lolololol ol

    19. Dezember 2021 um 1:08 Uhr

  • @JVM wenn Sie Cherry-Pick ohne die verwenden ^ im Bereich wird der erste Commit nicht eingeschlossen

    – Tomás Vancoillie

    6. Januar um 14:28 Uhr


Sind Sie sicher, dass Sie die Zweige nicht tatsächlich zusammenführen möchten? Wenn der funktionierende Zweig einige neuere Commits enthält, die Sie nicht möchten, können Sie einfach einen neuen Zweig mit einem HEAD an der gewünschten Stelle erstellen.

Wenn Sie nun wirklich aus irgendeinem Grund eine Reihe von Commits auswählen möchten, besteht eine elegante Möglichkeit darin, einfach ein Patchset abzurufen und es auf Ihren neuen Integrationszweig anzuwenden:

git format-patch A..B
git checkout integration
git am *.patch

Dies ist im Wesentlichen das, was git-rebase sowieso tut, aber ohne die Notwendigkeit, Spiele zu spielen. Du kannst hinzufügen --3way zu git-am wenn Sie zusammenführen müssen. Stellen Sie sicher, dass sich keine anderen *.patch-Dateien bereits in dem Verzeichnis befinden, in dem Sie dies tun, wenn Sie die Anweisungen wörtlich befolgen …

Wie wahlt man eine Reihe von Commits aus und fuhrt
Adam Franco

Ich habe den Code von VonC in ein kurzes Bash-Skript verpackt, git-multi-cherry-pickfür leichten Lauf:

#!/bin/bash

if [ -z $1 ]; then
    echo "Equivalent to running git-cherry-pick on each of the commits in the range specified.";
    echo "";
    echo "Usage:  $0 start^..end";
    echo "";
    exit 1;
fi

git rev-list --reverse --topo-order $1 | while read rev 
do 
  git cherry-pick $rev || break 
done 

Ich verwende dies derzeit, da ich den Verlauf eines Projekts neu aufbaue, bei dem sowohl Code von Drittanbietern als auch Anpassungen im selben SVN-Stamm gemischt wurden. Ich teile jetzt den Kerncode von Drittanbietern, Module von Drittanbietern und Anpassungen auf ihre eigenen Git-Zweige auf, um die zukünftigen Anpassungen besser zu verstehen. git-cherry-pick ist in dieser Situation hilfreich, da ich zwei Bäume im selben Repository habe, aber ohne einen gemeinsamen Vorfahren.

git Kirschpickel start_commit_sha_id^..end_commit_sha_id

z.B git cherry-pick 3a7322ac^..7d7c123c

Vorausgesetzt du bist dran branchA wo Sie Commits auswählen möchten (Anfangs- und Ende-Commit-SHA für den Bereich ist angegeben und linker Commit-SHA ist älter) von branchB. Die gesamte Bandbreite an Commits (beide inklusive) wird ausgewählt branchA.

Die Beispiele in der offiziellen Dokumentation angegeben sind sehr nützlich.

Ich habe das vor einigen Tagen getestet, nachdem ich die sehr klare Erklärung von Vonc gelesen hatte.

Meine Schritte

Start

  • Sich verzeigen dev : ABCDEFGHIJ
  • Sich verzeigen target: A B C D
  • Ich will nicht E Noch H

Schritte zum Kopieren von Features ohne die Schritte E und H im Zweig dev_feature_wo_E_H

  • git checkout dev
  • git checkout -b dev_feature_wo_E_H
  • git rebase --interactive --rebase-merges --no-ff D wo ich hingelegt habe drop vor E und H im Rebase-Editor
  • Konflikte lösen, fortfahren und commit

Schritte zum Kopieren der Verzweigung dev_feature_wo_E_H am Ziel.

  • git checkout target
  • git merge --no-ff --no-commit dev_feature_wo_E_H
  • Konflikte lösen, fortfahren und commit

Einige Bemerkungen

  • Ich habe das wegen zu viel getan cherry-pick in den Tagen davor
  • git cherry-pick ist mächtig und einfach, aber

    • es erstellt doppelte Commits
    • und wann ich will merge Ich muss Konflikte zwischen den anfänglichen Commits und doppelten Commits lösen, also für ein oder zwei cherry-pickes ist in Ordnung zum “Rosinenpicken”, aber für mehr ist es zu ausführlich und der Zweig wird zu komplex
  • In meinem Kopf sind die Schritte, die ich getan habe, klarer als git rebase --onto

  • Guter Post. Hochgestimmt. Es erinnert mich an stackoverflow.com/a/38418941/6309. Ich habe die Nachteile des Rosinenpickens im Jahr 2012 noch einmal zusammengefasst: stackoverflow.com/a/13524494/6309.

    – VonC

    17. Februar 2020 um 7:09 Uhr


986750cookie-checkWie wählt man eine Reihe von Commits aus und führt sie in einem anderen Zweig zusammen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy