wake-up-neo.net

Git: Wie kann man sich auf ein bestimmtes Commit beziehen?

Ich möchte auf ein bestimmtes Commit zurückgreifen, nicht auf ein HEAD des anderen Zweigs:

A --- B --- C          master
 \
  \-- D                topic

zu

A --- B --- C          master
       \
        \-- D          topic

anstatt 

A --- B --- C          master
             \
              \-- D    topic

Wie kann ich das erreichen?

107
Ondra Žižka

Sie können die Verwendung des Parameters --onto vermeiden, indem Sie einen temporären Zweig für das Commit erstellen, das Sie mögen, und dann rebase in seiner einfachen Form verwenden:

git branch temp master^
git checkout topic
git rebase temp
git branch -d temp
70
Adam Dymitruk

Sie können sogar direkt vorgehen:

git checkout topic
git rebase <commitB>
51
r0hitsharma

Verwenden Sie die Option "Auf":

git rebase --onto master^ D^ D
40
Adam Dymitruk

Der Kommentar von jsz hat mir eine Menge Schmerzen erspart, daher folgt hier ein Schritt-für-Schritt-Rezept, das ich dazu benutze, um ein Commit zusätzlich zu jedem anderen Commit zurückzuweisen oder zu verschieben:

  1. Suchen Sie nach einem vorherigen Verzweigungspunkt des Zweigs, der umbasiert (verschoben) werden soll. Im obigen Beispiel ist dasA
  2. Suchen Sie nach "commit", zu dem Sie den Zweig verschieben möchten, und nennen Sie ihn "new parent". In der exampe ist dasB
  3. Sie müssen sich in Ihrem Zweig befinden (derjenige, den Sie umziehen): 
  4. Wenden Sie Ihre Rebase an: git rebase --onto <new parent> <old parent>

Im obigen Beispiel ist das so einfach wie:

   git checkout topic
   git rebase --onto B A
6
Nestor Milyaev

Ich habe eine Mischung von oben beschriebenen Lösungen verwendet:

$ git branch temp <specific sha1>
$ git rebase --onto temp master topic
$ git branch -d temp

Ich fand es viel einfacher zu lesen und zu verstehen. Die akzeptierte Lösung führte mich zu einem Verschmelzungskonflikt (zu faul, um sie von Hand zu reparieren):

$ git rebase temp
First, rewinding head to replay your work on top of it...
Applying: <git comment>
Using index info to reconstruct a base tree...
M       pom.xml
.git/rebase-apply/patch:10: trailing whitespace.
    <some code>
.git/rebase-apply/patch:17: trailing whitespace.
        <some other code>
warning: 2 lines add whitespace errors.
Falling back to patching base and 3-way merge...
Auto-merging pom.xml
CONFLICT (content): Merge conflict in pom.xml
error: Failed to merge in the changes.
Patch failed at 0001 <git comment>
The copy of the patch that failed is found in: .git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".
2
malat

Thema Lösung

Der richtige Befehl zum Beantworten der gestellten Frage kann einer der folgenden sein (vorausgesetzt, der Zweig topic ist bereits ausgecheckt):

git rebase --onto B master
git rebase --onto master~1 master
git rebase --onto B A
git rebase --onto B C
git rebase --onto B

Wenn topic nicht ausgecheckt ist, hängen Sie einfach topic an den Befehl an (mit Ausnahme des letzten):

git rebase --onto B master topic

Alternativ können Sie zuerst die Filiale überprüfen mit:

git checkout topic

Starten Sie eine beliebige Folge von Commits erneut für ein Ziel-Commit

Die Grundform des von uns benötigten Befehls, die aus der Dokumentation hervorgeht, lautet:

git rebase --onto <Target> [<Upstream> [<Branch>]]

<Branch> ist optional und checkt lediglich den angegebenen Zweig aus, bevor der Rest des Befehls ausgeführt wird. Wenn Sie den Zweig, den Sie zurücksetzen möchten, bereits ausgecheckt haben, benötigen Sie diesen nicht. Beachten Sie, dass Sie <Upstream> angegeben haben müssen, um <Branch> anzugeben. Andernfalls wird git annehmen, dass Sie <Upstream> angeben.

<Target> ist das Commit, an das wir unsere Commit-Zeichenfolge anhängen. Wenn Sie einen Zweignamen angeben, geben Sie einfach das Head-Commit dieses Zweigs an. <Target> kann jedes Commit sein, das nicht in der Zeichenfolge der zu verschiebenden Commits enthalten ist. Zum Beispiel:

A --- B --- C --- D         master
      \
       \-- X --- Y --- Z    feature

Um den gesamten Feature-Zweig zu verschieben, können Sie nicht X, Y, Z oder feature als <Target> auswählen, da dies alles Festschreibungen innerhalb der zu verschiebenden Gruppe sind.

<Upstream> ist etwas Besonderes, weil es zwei verschiedene Dinge bedeuten kann. Wenn es sich um ein Commit handelt, das Vorläufer des ausgecheckten Zweigs ist, dient es als Schnittpunkt. In dem von mir angegebenen Beispiel ist dies alles, was nicht C, D oder master ist. Alle Commits nach <Upstream>, bis der Kopf des ausgecheckten Zweigs verschoben wird.

Wenn <Upstream> jedoch kein Vorfahr ist, sichert git die Kette ab dem angegebenen Commit, bis ein gemeinsamer Vorfahr mit dem ausgecheckten Zweig gefunden wird (und bricht ab, wenn er keinen findet). In unserem Fall führt ein <Upstream> von B, C, D oder master dazu, dass B festgeschrieben wird und als Schnittpunkt dient. <Upstream> ist selbst ein optionaler Befehl, und wenn er nicht angegeben ist, überprüft git das übergeordnete Element des ausgecheckten Zweigs, was der Eingabe von master entspricht.

Nachdem git die Commits ausgewählt hat, die es ausschneidet und verschiebt, wendet es sie auf <Target> an und überspringt alle bereits auf das Ziel angewendeten.

Interessante Beispiele und Ergebnisse

Unter Verwendung dieses Ausgangspunkts:

A --- B --- C --- D --- E         master
            \
             \-- X --- Y --- Z    feature
  • git rebase --onto D A feature
    Wendet Festschreibungen für B, C, X, Y, Z an, um D festzuschreiben, und überspringt B und C, weil sie bereits angewendet wurden.

  • git rebase --onto C X feature
    Wendet Commits Y und Z auf Commit C an und löscht effektiv Commit X.

1
Isaac Brown

Eine einfachere Lösung ist git rebase <SHA1 of B> topic. Dies funktioniert unabhängig davon, wo sich Ihr HEAD befindet.

Wir können dieses Verhalten von git rebase doc bestätigen.

<upstream> Upstream-Zweig zum Vergleich. Kann beliebig sein commit, nicht nur ein vorhandener Zweigname. Der Standardwert ist das konfigurierte Upstream für die aktuelle Branche.


Sie denken vielleicht darüber nach, was passiert, wenn ich im obigen Befehl auch SHA1 von topic erwähne?

git rebase <SHA1 of B> <SHA1 of topic>

Dies funktioniert auch, aber rebase führt nicht dazu, dass Topic auf den so erstellten neuen Zweig verweist, und HEAD befindet sich im getrennten Zustand. Von hier aus müssen Sie also alte Topic manuell löschen und eine neue Verzweigungsreferenz für die von rebase erstellte neue Verzweigung erstellen.

0

Es gibt eine andere Möglichkeit, dies zu tun oder wenn Sie zu mehr als einem Commit zurückkehren möchten.

Hier ist ein Beispiel, um zu n Anzahl der Commits zurückzukehren:

git branch topic master~n

Für diese Frage kann dies auch gemacht werden:

git branch topic master~1

Der Befehl funktioniert perfekt für git version 2.7.4. Ich habe es noch nicht in einer anderen Version getestet.

0
Talha Ashraf

Da Umbasierung so grundlegend ist, ist hier eine Erweiterung der Antwort von Nestor Milyaev . Die Kombination von jsz's und Simon Souths Kommentaren aus Adam Dymitruks Antwort ergibt diesen Befehl, der auf den Zweig topic angewendet werden kann, unabhängig davon, ob er von der master-Verzweigung A oder C verzweigt:

git checkout topic
git rebase --onto <commit-B> <pre-rebase-A-or-post-rebase-C-or-base-branch-name>

Beachten Sie, dass das letzte Argument erforderlich ist (andernfalls wird Ihr Zweig zurückgespult, um B zu übergeben).

Beispiele:

# if topic branches from master commit A:
git checkout topic
git rebase --onto <commit-B> <commit-A>
# if topic branches from master commit C:
git checkout topic
git rebase --onto <commit-B> <commit-C>
# regardless of whether topic branches from master commit A or C:
git checkout topic
git rebase --onto <commit-B> master

Der letzte Befehl ist der, den ich normalerweise verwende.

0
Zack Morris