Wie man mehrere Commits auswählt

875

Ich habe zwei Zweige. Commit aist der Kopf von einem, während der andere hat b, c, d, eund fauf der Oberseite a. Ich mag bewegen c, d, eund fzum ersten Zweig ohne zu begehen b. Verwendung Kirsche es holen ist einfach: Kasse ersten Zweiges kirsch Pick nacheinander czu fund zweiten Zweig auf den ersten rebase. Aber ist es eine Möglichkeit, alle herauspicken c- fin einem Befehl?

Hier ist eine visuelle Beschreibung des Szenarios (danke JJD ):

Geben Sie hier die Bildbeschreibung ein

tig
quelle
3
Die von Ihnen erwähnte Rebase ist für die Frage nicht wirklich relevant, oder? (Ich verstehe , dass Sie vielleicht später bdarauf basieren möchten f, aber das hat nichts mit dem Kirschpflücken zu tun.)
Superole

Antworten:

1281

Mit Git 1.7.2 wurde die Möglichkeit eingeführt, eine Reihe von Commits auszuwählen. Aus den Versionshinweisen :

git cherry-picklernte, eine Reihe von Commits (z. B. cherry-pick A..Bund cherry-pick --stdin) auszuwählen, und tat dies auch git revert; Diese unterstützen jedoch nicht die schönere Sequenzierungskontrolle rebase [-i].

Führen Sie Folgendes aus, um alle Commits von Commit Azu Commit B(wo Aälter als B) auszuwählen :

git cherry-pick A^..B

Wenn Sie A selbst ignorieren möchten, führen Sie Folgendes aus:

git cherry-pick A..B

(Gutschrift geht an Damian, JB Rainsberger und Sschaef in den Kommentaren)

Eric Darchis
quelle
249
In der Form "Cherry-Pick A..B" sollte A älter als B sein. Wenn sie in der falschen Reihenfolge sind, schlägt der Befehl stillschweigend fehl.
Damian
294
Auch wird dies nicht A, sondern alles nach A bis einschließlich B
auswählen
455
Um A nur git cherry-pick A^..B
einzuschließen, geben Sie
17
Wenn Sie Git 1.7.1 oder früher haben und nicht aktualisieren können, können Sie sie ziemlich schnell in der richtigen Reihenfolge auswählen, indem Sie git cherry-pick f~3dann git cherry-pick f~2usw. bis ausführen git cherry-pick f(durch Drücken des Aufwärtspfeils wird der vorherige Befehl abgerufen, sodass ich die Nummer schnell ändern und ausführen kann es sollte in den meisten Konsolen ähnlich sein).
David Mason
19
Es kann gut sein zu wissen, dass diese Syntax auch mit Zweignamen funktioniert. git cherry-pick master..somebranchwählt alle Commits auf einem Zweig seit dem Master aus (vorausgesetzt, er basiert bereits auf dem Master) und wendet sie auf Ihre aktuelle Filiale an.
Tor Klingberg
103

Der einfachste Weg, dies zu tun, ist mit der ontoOption zu rebase. Nehmen wir an, dass der Zweig, der aktuelle beendet ist bei amybranch genannt wird , und dies ist der Zweig, den Sie verschieben wollen c- fauf.

# checkout mybranch
git checkout mybranch

# reset it to f (currently includes a)
git reset --hard f

# rebase every commit after b and transplant it onto a
git rebase --onto a b
CB Bailey
quelle
1
Vielen Dank! Könnten Sie auch git checkout secondbranch && git rebase mybranchfür die vollständige Antwort hinzufügen
tig
1
Diese Antwort hat mir sehr geholfen, herauszufinden, welches Commit in diesem Szenario welches ist. Und: Sie können auch rebaseden interaktiven Modus verwenden. Danke, @Charles!
Oliver
1
Das Schöne an diesem Ansatz ist, dass Sie --interactiveeinige Commits aus der Sequenz entfernen oder vor dem "Cherry Pick" neu anordnen können. +1
Michael Merickel
Dies ist ein genialer Befehl, der etwas schwierig ist, den Kopf herumzureißen, aber er wirkt Wunder.
Valerio
Wild, dass Sie das Commit geben müssen, das Sie nicht als eines der Argumente neu definieren möchten ( bin diesem Beispiel), aber ja, das hat bei mir funktioniert.
Asontu
85

Oder der gewünschte Einzeiler:

git rebase --onto a b f
wolfc
quelle
5
Wenn auch nur wegen seiner Kürze, ist dies die beste Antwort.
Nate Chandler
9
Upvoted, aber Sie werden im getrennten HEAD-Status belassen, wenn f ein Commit ist (im Gegensatz zu einem Zweig) - Sie sollten bearbeiten, um hinzuzufügen, dass man einen Zweig wie in der Antwort unten
auschecken sollte
68

Sie können eine serielle Kombination von git rebaseund verwenden git branch, um eine Gruppe von Commits auf einen anderen Zweig anzuwenden. Wie bereits von wolfc gepostet, kopiert der erste Befehl die Commits. Die Änderung ist jedoch erst sichtbar, wenn Sie dem obersten Commit der Gruppe einen Zweignamen hinzufügen.

Bitte öffnen Sie das Bild in einem neuen Tab ...

Arbeitsablauf

So fassen Sie die Befehle in Textform zusammen:

  1. Öffnen Sie gitk als unabhängigen Prozess mit dem Befehl : gitk --all &.
  2. Ausführen git rebase --onto a b f.
  3. Drücken Sie F5in gitk . Nichts verändert sich. Aber nein HEADist markiert.
  4. Lauf git branch selection
  5. Drücken Sie F5in gitk . Der neue Zweig mit seinen Commits wird angezeigt.

Dies sollte die Dinge klarstellen:

  • Commit aist das neue Stammziel der Gruppe.
  • Commit bist das Commit vor dem ersten Commit der Gruppe (exklusiv).
  • Commit fist das letzte Commit der Gruppe (einschließlich).

Anschließend können Sie git checkout feature && git reset --hard bdie Commits cbis faus dem featureZweig löschen .

Zusätzlich zu dieser Antwort habe ich einen Blog-Beitrag geschrieben, in dem die Befehle in einem anderen Szenario beschrieben werden, um die allgemeine Verwendung zu erleichtern.

JJD
quelle
2
Wenn die Mybranch (die a..f Commits) nicht mehr benötigt wird, kann dies vereinfacht werden zu: git rebase --onto a b mybranchund übrigens - welches Programm macht diese raffinierten Git-Bilder?
Mr_and_Mrs_D
2
@Mr_and_Mrs_D Danke für deinen Kommentar. Ich glaube, ich habe cacoo.com verwendet, um die Bilder zu zeichnen.
JJD
48

So wenden Sie die Kommentare von JB Rainsberger und sschaef an, um die Frage spezifisch zu beantworten ... So verwenden Sie in diesem Beispiel einen Cherry-Pick-Bereich:

git checkout a
git cherry-pick b..f

oder

git checkout a
git cherry-pick c^..f
Andy
quelle
3
Ich benutze git 2.7.0.windows.1und bemerkte, dass, wenn ich versuche, eine Reihe von Commits auszuwählen, alles in Ordnung ist, aber Git sagt Ihnen nirgendwo, was Sie tun müssen, git cherry-pick --continue | --abort | --quitbevor Sie erneut versuchen, eine Commit / Cherry-Pick durchzuführen. Wenn Sie also eine Reihe von Commits auswählen, müssen Sie git cherry-pick --continuejedes Mal, wenn Sie bereit sind (Konflikte lösen oder so), ein Commit aus dem angegebenen Bereich ausführen .
Kuskmen
Ich habe genau das Gleiche getan, aber tödlich: Kann 'a..b' nicht finden
Amit Karnik
Ich weiß nicht, wo ich falsch liege, aber wenn ich auf meiner Seite 'git cherry-pick c ^ .. f' mache, schließt dies das Commit f ein, aber nicht das Commit c. Aber wie ich überall lese, soll es c und f als inklusive definieren. Oder liege ich falsch?
Samuel
@ Samuel ja, das ist richtig. Das ^nach dem c bedeutet tatsächlich "das Festschreiben vor c", was in diesem Fall b ist. Deshalb c^..fist das auch so b..f. Versuchen Sie es git log c^..fund Sie sollten Commits c bis f sehen, genau so, als ob Sie es getan hättengit log b..f
Andy
41

Wenn Sie selektive Revisionen zum Zusammenführen haben, z. B. A, C, F, J von A, B, C, D, E, F, G, H, I, J, verwenden Sie einfach den folgenden Befehl:

Git Cherry-Pick ACFJ

Shrikant Wandhare
quelle
1
nett und einfach
Spinup
21
git rev-list --reverse b..f | xargs -n 1 git cherry-pick
Dustin
quelle
2
Funktioniert einwandfrei, wenn keine Konflikte vorliegen. Andernfalls ist das "Rebase on" möglicherweise einfacher, da Sie nicht herausfinden müssen, wo es gestoppt wurde, und den Rest der Patches erneut anwenden müssen.
Ruslan Kabalin
6
Bitte fügen Sie Kommentare hinzu, die erklären, was dies tut
Mr_and_Mrs_D
7
da niemand erklärt hat ... git rev-list druckt alle Revisionen von Zweig b nach f (umgekehrt), so dass, wenn jede Zeile (der Commit-Hash) der Reihe nach übergeben wird, jede auf dem aktuellen git HEAD ausgewählt wird. dhgit cherry-pick {hash of c}; git cherry-pick {hash of d}; ...
Coderatchet
8

Um von einer Commit-ID bis zur Spitze des Zweigs zu wählen, können Sie Folgendes verwenden:

git cherry-pick commit_id^..branch_name

ut9081
quelle
Dies ist bereits Teil der Antwort stackoverflow.com/a/31640427/96823
tig
1
Diese Antwort ist eigentlich anders und hat mir geholfen. Es gibt den Filialnamen an, nicht die endgültige Commit-SHA.
Subtletree
7

Eine andere erwähnenswerte Variante ist, dass ndie ~Syntax nützlich sein kann , wenn Sie die letzten Commits von einem Zweig möchten :

git cherry-pick some-branch~4..some-branch

In diesem Fall würde der obige Befehl die letzten 4 Commits aus einem aufgerufenen Zweig auswählen some-branch(obwohl Sie anstelle eines Zweignamens auch einen Commit-Hash verwenden könnten).

Nick F.
quelle
1
Sehr nützliche Antwort, danke! :)
Jacek Dziurdzikowski
3

Der einfachste Weg, dies zu tun, könnte sein:

  1. Zeichnen Sie die Zusammenführungsbasis zwischen den beiden Zweigen auf: MERGE_BASE=$(git merge-base branch-a branch-b)
  2. Schnellvorlauf oder Neustart des älteren Zweigs auf den neueren Zweig
  3. Setzen Sie den resultierenden Zweig neu auf sich selbst, beginnend mit der Zusammenführungsbasis ab Schritt 1, und entfernen Sie manuell nicht gewünschte Commits:

    git rebase ${SAVED_MERGE_BASE} -i
    

    Wenn es nur wenige neue Commits gibt, überspringen Sie alternativ Schritt 1 und verwenden Sie sie einfach

    git rebase HEAD^^^^^^^ -i
    

    Verwenden Sie im ersten Schritt genug ^, um an der Zusammenführungsbasis vorbeizukommen.

Sie werden so etwas in der interaktiven Rebase sehen:

pick 3139276 commit a
pick c1b421d commit b
pick 7204ee5 commit c
pick 6ae9419 commit d
pick 0152077 commit e
pick 2656623 commit f

Entfernen Sie dann die Zeilen b (und alle anderen gewünschten Zeilen).

ealfonso
quelle
1
git format-patch --full-index --binary --stdout range... | git am -3
Roger Wang
quelle
42
Bitte fügen Sie Kommentare hinzu, die erklären, was dies tut
Mr_and_Mrs_D
0

Hier ist ein Skript, mit dem Sie mehrere Commits hintereinander auswählen können, indem Sie dem Skript einfach mitteilen, welche Quell- und Zielzweige für die Cherry-Picks und wie viele Commits vorhanden sind:

https://gist.github.com/nickboldt/99ac1dc4eb4c9ff003a1effef2eb2d81

So wählen Sie von Ihrem Zweig zum Master aus (verwendet den aktuellen Zweig als Quelle):

./gcpl.sh -m

So wählen Sie die letzten 5 Commits aus Ihrem 6.19.x-Zweig zum Master aus:

./gcpl.sh -c 5 -s 6.19.x -t master
Nickboldt
quelle
Warum sollte dieses Skript benötigt werden, wenn Sie dies direkt mit Git tun können? ...
code_dredd
Weniger tippen, und mein Skript wählt automatisch die Commits für Sie aus, sodass Sie nicht jedes nach seiner SHA auswählen müssen. Wie auch immer, YMMV.
Nickboldt