Wie verschiebe ich bestimmte Commits, um auf einem anderen Zweig in Git zu basieren?

381

Die Situation:

  • Meister ist bei X.
  • quickfix1 ist bei X + 2 Commits

So dass:

o-o-X (master HEAD)
     \
      q1a--q1b (quickfix1 HEAD)

Dann fing ich an, an quickfix2 zu arbeiten, nahm aber versehentlich quickfix1 als Quellzweig zum Kopieren, nicht den Master. Jetzt ist quickfix2 bei X + 2 Commits + 2 relevanten Commits.

o-o-X (master HEAD)
     \
      q1a--q1b (quickfix1 HEAD)
              \
               q2a--q2b (quickfix2 HEAD)

Jetzt möchte ich einen Zweig mit quickfix2 haben, aber ohne die 2 Commits, die zu quickfix1 gehören.

      q2a'--q2b' (quickfix2 HEAD)
     /
o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)

Ich habe versucht, einen Patch aus einer bestimmten Revision in quickfix2 zu erstellen, aber der Patch behält den Commit-Verlauf nicht bei. Gibt es eine Möglichkeit, meinen Commit-Verlauf zu speichern, aber einen Zweig ohne Änderungen in quickfix1 zu haben?

Alex Yarmula
quelle
8
@ Kevin Diese Frage fragt nur nach dem Verschieben von Commits von einem Zweig in einen anderen. Dieser hat die zusätzliche Anforderung, die Commits nicht einzuschließen quickfix1. (Beachten Sie auch den Unterschied in den Antworten.)
Scott Weldon

Antworten:

372

Dies ist ein klassischer Fall von rebase --onto:

 # let's go to current master (X, where quickfix2 should begin)
 git checkout master

 # replay every commit *after* quickfix1 up to quickfix2 HEAD.
 git rebase --onto master quickfix1 quickfix2 

Also solltest du gehen von

o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)
              \
               q2a--q2b (quickfix2 HEAD)

zu:

      q2a'--q2b' (new quickfix2 HEAD)
     /
o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)

Dies geschieht am besten an einem sauberen Arbeitsbaum.
Siehegit config --global rebase.autostash true insbesondere nach Git 2.10 .

VonC
quelle
24
Beachten Sie, dass diese Schritte den Verlauf von quickfix2 ändern. Wenn Sie den Zweig bereits freigegeben haben, verwenden Sie stattdessen Cherry-Picking (siehe folgende Antworten).
Max Chernyak
Nur für die Datensätze: Ziehen Sie mit dem SmartGit-Protokoll einfach q2aauf Xund ziehen Sie Rebase 2-Commits aus den Optionen des auftretenden Dialogfelds.
Thomas S.
1
@ ThomasS. Interessant. Das ist eine schöne GUI-Implementierung von a git rebase --onto.
VonC
1
Ich muss zugeben, ich mache alberne Dinge wie das Festlegen des falschen Zweigs öfter, als ich eigentlich sollte. Die Benutzeroberfläche der SmartGit-Protokollansicht hat mich in der gleichen Situation so oft gerettet.
WORMSS
1
@Cosine vereinbart. Ich habe meine Antwort bearbeitet, um den Verweis auf die rebase.autostashKonfiguration hinzuzufügen : Dadurch wird ein Verlust der laufenden Arbeit im Arbeitsbaum vermieden, wenn eine Rebase ausgeführt wird.
VonC
155

Sie können git cherry-pickeinfach das Commit auswählen, über das Sie kopieren möchten.

Der wahrscheinlich beste Weg ist, den Zweig aus dem Master heraus zu erstellen und dann in diesem Zweig git cherry-pickdie 2 Commits von quickfix2 zu verwenden, die Sie möchten.

DJ.
quelle
Dies ist auch die beste Option, wenn Sie nur ein Commit verschieben möchten. Vielen Dank.
Alex
142

Das Einfachste, was Sie tun können, ist, eine Auswahl an Kirschen zu treffen. Es macht das gleiche wie das rebase --onto, ist aber einfacher für die Augen :)

git cherry-pick quickfix1..quickfix2
Christoph
quelle
6
Außerdem verliert es nicht die ursprünglichen Commits, IIUC, scheint also für "Play-it-Safes" wie mich vorzuziehen;) oder behält es rebase --ontoauch die ursprünglichen Änderungen bei?
akavel
6
beide rebaseund cherry-pickgeben Ihnen neue SHA-Schlüssel. Dies liegt daran, dass jedes Commit eine eindeutige Momentaufnahme des Repositorys ist.
Christoph
6
Was @akavel bedeutete, ist, dass Cherry-Pick die ursprünglichen Commits in ihrem Zweig
behält,
4
Was auch immer es wert ist, ich habe versucht, cherry-pickeinen Bereich wie in dieser Antwort zu finden, und es hat mein Repo verwirrt. Ich musste cherry-pickfür jedes Commit individuelle s machen. (Und vielleicht ist es selbstverständlich, aber falls jemand Probleme hat, müssen Sie cherry-pickin der chronologischen Reihenfolge, in der Ihre
Verpflichtungen
3
git checkoutist hier entscheidend. Was ist dein KOPF :)?
Sławomir Lenart
28

Ich glaube es ist:

git checkout master
git checkout -b good_quickfix2
git cherry-pick quickfix2^
git cherry-pick quickfix2
Matthew Flaschen
quelle
3
cherry-pickfunktioniert mit Commit-Hashes. Wenn Sie also nur ein Commit von irgendwoher abrufen und an einem anderen Ort ablegen möchten, ist dies der richtige Weg. Stellen Sie einfach sicher, dass Sie checkout <branch>zuerst den richtigen Zweig ausführen.
John Leidegren
-1
// on your branch that holds the commit you want to pass
$ git log
// copy the commit hash found
$ git checkout [branch that will copy the commit]
$ git reset --hard [hash of the commit you want to copy from the other branch]
// remove the [brackets]

Weitere nützlichere Befehle hier mit Erläuterung: Git Guide

Gopher
quelle