Angenommen, ich habe den folgenden Commit-Verlauf in meinem Zweig nur vor Ort:
A -- B -- C
Wie füge ich ein neues Commit zwischen A
und ein B
?
Angenommen, ich habe den folgenden Commit-Verlauf in meinem Zweig nur vor Ort:
A -- B -- C
Wie füge ich ein neues Commit zwischen A
und ein B
?
Antworten:
Es ist noch einfacher als in der Antwort von OP.
git rebase -i <any earlier commit>
. Dies zeigt eine Liste der Commits in Ihrem konfigurierten Texteditor an.a1b2c3d
). Ändern Sie pick
in Ihrem Editor für diese Zeile in edit
.a1b2c3d
), als wäre es gerade festgeschrieben worden .git commit
( NICHT im Gegensatz zu den meisten anderen edit
). Dadurch wird nach dem von Ihnen ausgewählten Commit ein neues Commit erstellt .git rebase --continue
. Dadurch werden die aufeinanderfolgenden Commits wiederholt, und Ihr neues Commit wird an der richtigen Stelle eingefügt.Beachten Sie, dass dies die Geschichte neu schreibt und jeden anderen bricht, der versucht zu ziehen.
A -- B -- C -- D
statt gewünscht A -- D -- B -- C
.
D
könnte überall ein Commit sein. Nehmen wir an, wir haben A - B - C
und wir haben ein Commit, D
das nicht einmal in diesem Zweig ist. Wir wissen, dass es SHA ist, aber wir können es tun git rebase -i HEAD~3
. Jetzt zwischen den A
und B
pick
Linien, legen wir eine neue pick
Linie , die sagt pick SHA
, den Hash des gewünschten geben D
. Es muss nicht der vollständige Hash sein, sondern nur der verkürzte. git rebase -i
Nur Cherry wählt die Commits aus, die durch pick
Zeilen im Puffer aufgelistet sind . Sie müssen nicht die Originale sein, die für Sie aufgelistet sind.
break
Schlüsselwort im Editor in einer eigenen Zeile zwischen zwei Commits zu verwenden (oder in der ersten Zeile, um ein Commit vor dem angegebenen Commit einzufügen).
Es stellt sich als recht einfach heraus, die Antwort hier zu finden . Angenommen, Sie befinden sich in einem Zweig branch
. Führen Sie die folgenden Schritte aus:
Erstellen Sie einen temporären Zweig aus dem Commit, nachdem Sie das neue Commit einfügen möchten (in diesem Fall Commit A
):
git checkout -b temp A
Führen Sie die Änderungen durch und schreiben Sie sie fest. Erstellen Sie ein Commit. Nennen wir es N
:
git commit -a -m "Message"
(oder git add
gefolgt von git commit
)
Basen Sie die Commits, die Sie nach dem neuen Commit (in diesem Fall Commits B
und C
) haben möchten, auf das neue Commit zurück:
git rebase temp branch
(Möglicherweise müssen Sie diese verwenden -p
, um Zusammenführungen beizubehalten, falls vorhanden - dank eines nicht mehr vorhandenen Kommentars von ciekawy )
Löschen Sie den temporären Zweig:
git branch -d temp
Danach sieht der Verlauf wie folgt aus:
A -- N -- B -- C
Es ist natürlich möglich, dass beim erneuten Basieren einige Konflikte auftreten.
Wenn Ihre Niederlassung nicht nur lokal ist, führt dies zum Umschreiben des Verlaufs und kann daher zu ernsthaften Problemen führen.
git push --force
das Remote-Repo ändern.
git rebase temp branch -Xtheirs
. Hilfreiche Antwort zum Einfügen in ein Skript!
git rebase temp branch
, aber vorher git branch -d temp
müssen Sie nur Konflikte und Probleme beheben und inszenieren git rebase --continue
, dh Sie müssen nichts begehen usw.
Noch einfachere Lösung:
Erstellen Sie am Ende Ihr neues Commit, D. Jetzt haben Sie:
A -- B -- C -- D
Dann renne:
$ git rebase -i hash-of-A
Git öffnet Ihren Editor und sieht folgendermaßen aus:
pick 8668d21 B
pick 650f1fc C
pick 74096b9 D
Bewegen Sie D einfach so nach oben, speichern Sie es und beenden Sie es
pick 74096b9 D
pick 8668d21 B
pick 650f1fc C
Jetzt haben Sie:
A -- D -- B -- C
Angenommen, der Commit-Verlauf lautet wie folgt: preA -- A -- B -- C
Wenn Sie einen Commit zwischen A
und einfügen möchten, B
lauten die Schritte wie folgt:
git rebase -i hash-of-preA
Git öffnet Ihren Editor. Der Inhalt könnte folgendermaßen aussehen:
pick 8668d21 A
pick 650f1fc B
pick 74096b9 C
Ändern Sie die erste pick
in edit
:
edit 8668d21 A
pick 650f1fc B
pick 74096b9 C
Speichern und schließen.
Ändern Sie Ihren Code und dann git add . && git commit -m "I"
git rebase --continue
Jetzt ist Ihr Git-Commit-Verlauf preA -- A -- I -- B -- C
Wenn Sie auf einen Konflikt stoßen, stoppt Git bei diesem Commit. Sie können git diff
Konfliktmarkierungen suchen und lösen. Nachdem Sie alle Konflikte git add <filename>
gelöst haben , müssen Sie Git mitteilen, dass der Konflikt gelöst wurde, und anschließend erneut ausführen git rebase --continue
.
Wenn Sie die Rebase rückgängig machen möchten, verwenden Sie git rebase --abort
.
Hier ist eine Strategie, die es vermeidet, während der Rebase einen "Edit-Hack" durchzuführen, wie in den anderen Antworten zu sehen ist, die ich gelesen habe.
Durch die Verwendung erhalten git rebase -i
Sie eine Liste der Commits seit diesem Commit. Fügen Sie einfach oben in der Datei einen "break" hinzu. Dadurch wird die Rebase an diesem Punkt unterbrochen.
break
pick <B's hash> <B's commit message>
pick <C's hash> <C's commit message>
Einmal gestartet, git rebase
stoppt nun an der Stelle der "Pause". Sie können jetzt Ihre Dateien bearbeiten und Ihr Commit normal erstellen. Sie können dann die Rebase mit fortsetzen git rebase --continue
. Dies kann zu Konflikten führen, die Sie beheben müssen. Wenn Sie sich verlaufen, vergessen Sie nicht, dass Sie jederzeit mit abbrechen können git rebase --abort
.
Diese Strategie kann verallgemeinert werden, um ein Commit an einer beliebigen Stelle einzufügen. Setzen Sie einfach die "Pause" an die Stelle, an der Sie ein Commit einfügen möchten.
Vergessen Sie nicht, nach dem Umschreiben der Geschichte git push -f
. Es gelten die üblichen Warnungen vor anderen Personen, die Ihre Filiale abrufen.
rebase
hier. Es ist kein großer Unterschied, ob Sie das Commit während der Rebase oder im Voraus erstellen.
Viele gute Antworten hier schon. Ich wollte nur eine "No Rebase" -Lösung in 4 einfachen Schritten hinzufügen.
Zusammenfassung
git checkout A
git commit -am "Message for commit D"
git cherry-pick A..C
git branch -f master HEAD
Erläuterung
(Hinweis: Ein Vorteil dieser Lösung besteht darin, dass Sie Ihren Zweig erst im letzten Schritt berühren, wenn Sie zu 100% sicher sind, dass Sie mit dem Endergebnis einverstanden sind, sodass Sie einen sehr praktischen Schritt zur "Vorbestätigung" haben AB-Tests zulassen .)
Ausgangszustand (ich habe master
für Ihren Filialnamen angenommen )
A -- B -- C <<< master <<< HEAD
1) Richten Sie den KOPF zunächst auf die richtige Stelle
git checkout A
B -- C <<< master
/
A <<< detached HEAD
(Optional hätten wir hier anstelle von HEAD einen temporären Zweig erstellen können, mit git checkout -b temp A
dem wir am Ende des Prozesses löschen müssten. Beide Varianten funktionieren nach Ihren Wünschen, da alles andere gleich bleibt.)
2) Erstellen Sie das neue Commit D, das eingefügt werden soll
# at this point, make the changes you wanted to insert between A and B, then
git commit -am "Message for commit D"
B -- C <<< master
/
A -- D <<< detached HEAD (or <<< temp <<< HEAD)
3) Bringen Sie dann Kopien der letzten fehlenden Commits B und C mit (wäre dieselbe Zeile, wenn es mehr Commits gäbe).
git cherry-pick A..C
# (if any, resolve any potential conflicts between D and these last commits)
B -- C <<< master
/
A -- D -- B' -- C' <<< detached HEAD (or <<< temp <<< HEAD)
(bequemer AB-Test hier bei Bedarf)
Jetzt ist der Moment gekommen, um Ihren Code zu überprüfen, alles zu testen, was getestet werden muss, und Sie können auch unterscheiden / vergleichen / überprüfen, was Sie hatten und was Sie nach den Operationen erhalten würden.
4) Abhängig von Ihren Tests zwischen C
und C'
ist entweder OK oder KO.
(BEIDES) 4-OK) Bewegen Sie zum Schluss den Ref vonmaster
git branch -f master HEAD
B -- C <<< (B and C are candidates for garbage collection)
/
A -- D -- B' -- C' <<< master
(ODER) 4-KO) Einfach master
unverändert lassen
Wenn Sie einen temporären Zweig erstellt haben, löschen Sie ihn einfach mit git branch -d <name>
. Wenn Sie sich jedoch für die getrennte HEAD-Route entschieden haben und zu diesem Zeitpunkt überhaupt keine Aktion erforderlich ist, können die neuen Commits unmittelbar nach dem erneuten Anhängen HEAD
mit a für die Speicherbereinigung verwendet werdengit checkout master
In beiden Fällen (OK oder KO) müssen Sie an dieser Stelle master
erneut auschecken, um die Verbindung wiederherzustellen HEAD
.