Beachten Sie, dass dies git rebase
einen anderen Job hat als git merge
(mit oder ohne --ff-only
). Sie rebase
müssen vorhandene Commits übernehmen und kopieren . Nehmen wir zum Beispiel an, Sie sind eingeschaltet branch1
und haben zwei Commits durchgeführt A
und B
:
...-o--o--A--B <-- HEAD=branch1
\
o--C <-- branch2
und Sie entscheiden, dass diese beiden Commits lieber aktiviert werden sollen branch2
. Sie können:
- Erhalten Sie eine Liste der Änderungen, die Sie vorgenommen haben
A
(Unterschied zu A
den übergeordneten Elementen ).
- Holen Sie sich eine Liste der Änderungen, die Sie vorgenommen haben
B
(diff B
gegen A
)
- wechseln zu
branch2
- Nehmen Sie die gleichen Änderungen vor, die Sie vorgenommen haben,
A
und übernehmen Sie sie, indem Sie Ihre Festschreibungsnachricht von kopieren A
. Nennen wir dieses CommitA'
- Nehmen Sie dann dieselben Änderungen vor, die Sie vorgenommen haben,
B
und schreiben Sie sie fest, indem Sie Ihre Festschreibungsnachricht von kopieren B
. Nennen wir das B'
.
Es gibt einen git-Befehl, der dieses Diff-and-Then-Copy-and-Commit für Sie ausführt : git cherry-pick
. Damit:
git checkout branch2 # switch HEAD to branch2 (commit C)
git cherry-pick branch1^ # this copies A to A'
git cherry-pick branch1 # and this copies B to B'
Jetzt haben Sie Folgendes:
...-o--o--A--B <-- branch1
\
o--C--A'-B' <-- HEAD=branch2
Jetzt können Sie zurück zu branch1
Ihrem Original wechseln und es löschen A
und B
mit git reset
(ich werde es --hard
hier verwenden, ist es auf diese Weise bequemer, da es auch den Arbeitsbaum bereinigt):
git checkout branch1
git reset --hard HEAD~2
Dadurch wird das Original A
und B
, 1 so jetzt haben Sie:
...-o--o <-- HEAD=branch1
\
o--C--A'-B' <-- branch2
Jetzt müssen Sie nur noch einmal auschecken, um dort branch2
weiterarbeiten zu können.
Dies ist, was git rebase
bewirkt: Es "verschiebt" Commits (allerdings nicht, indem es sie tatsächlich verschiebt, weil es nicht möglich ist: In git kann ein Commit niemals geändert werden. Selbst wenn Sie nur die übergeordnete ID ändern, müssen Sie sie in eine neue und etwas andere kopieren verpflichten).
Mit anderen Worten, während git cherry-pick
es sich um ein automatisiertes Diff-and-Redo eines Commits handelt, git rebase
handelt es sich um einen automatisierten Prozess zum Wiederherstellen mehrerer Commits und zum Verschieben von Beschriftungen, um die Originale zu "vergessen" oder zu verbergen.
Das Obige zeigt das Verschieben von Commits von einem lokalen Zweig branch1
in einen anderen lokalen Zweig branch2
, aber git verwendet genau den gleichen Prozess , um Commits zu verschieben, wenn Sie einen Remote-Tracking-Zweig haben, der einige neue Commits erhält, wenn Sie einen ausführen git fetch
(einschließlich fetch
des ersten Schritts von git pull
). Sie können zunächst an einem Zweig arbeiten feature
, der einen Upstream von hat origin/feature
, und einige eigene Commits vornehmen:
...-o <-- origin/feature
\
A--B <-- HEAD=feature
Aber dann entscheidest du, dass du sehen sollst, was stromaufwärts passiert ist, also rennst du git fetch
, 2 und aha, jemand stromaufwärts hat ein Commit geschrieben C
:
...-o--C <-- origin/feature
\
A--B <-- HEAD=feature
An dieser Stelle können Sie einfach Ihre rebase feature
‚s A
und B
auf C
, geben:
...-o--C <-- origin/feature
\
A'-B' <-- HEAD=feature
Dies sind Kopien Ihres Originals A
und B
die Originale werden nach Abschluss der Kopien weggeworfen (siehe jedoch Fußnote 1).
Manchmal gibt es nichts zu widerlegen, dh keine Arbeit, die Sie selbst geleistet haben. Das heißt, die Grafik vor dem fetch
sieht folgendermaßen aus:
...-o <-- origin/feature
`-- HEAD=feature
Wenn Sie dann git fetch
und Commit C
eingehen, bleibt Ihr feature
Zweig auf dem alten Commit, während Sie origin/feature
vorwärts gegangen sind :
...-o--C <-- origin/feature
`---- <-- HEAD=feature
Dies ist , wo git merge --ff-only
kommt in: Wenn Sie fragen Sie Ihren aktuellen Zweig verschmelzen feature
mit origin/feature
, git sieht , dass es möglich ist , nur nach vorne auf den Pfeil schieben, wie es war, so dass feature
Punkte direkt zu begehen C
. Es ist keine tatsächliche Zusammenführung erforderlich.
Wenn Sie Ihre eigenen Commits hätten A
und B
Sie darum gebeten hätten, diese zusammenzuführen C
, würde git eine echte Zusammenführung durchführen und ein neues Zusammenführungs-Commit durchführen M
:
...-o--C <-- origin/feature
\ `-_
A--B--M <-- feature
Hier --ff-only
wird angehalten und Sie erhalten einen Fehler. Fütterungsmaterial, auf der anderen Seite, kopiert A
und B
zu A'
und B'
dann das Original verstecken , A
und B
.
Kurz gesagt (ok, zu spät :-)) machen sie einfach verschiedene Dinge. Manchmal ist das Ergebnis das gleiche und manchmal nicht. Wenn es in Ordnung ist, A
und zu kopieren B
, können Sie verwenden git rebase
; Wenn es jedoch einen guten Grund gibt, sie nicht zu kopieren, können Sie sie git merge
möglicherweise verwenden --ff-only
, um sie nach Bedarf zusammenzuführen oder fehlzuschlagen.
1 Git bewahrt die Originale tatsächlich einige Zeit auf - in diesem Fall normalerweise einen Monat -, versteckt sie jedoch. Der einfachste Weg, sie zu finden, sind die "Reflogs" von git, die HEAD
vor jeder Änderung, die den Zweig und / oder aktualisiert hat , einen Verlauf darüber führen, wohin und wo jeder Zweig zeigte HEAD
.
Schließlich werden die reflog History - Einträge verfallen, an welcher Stelle diese Commits für in Frage kommende werden Garbage Collection .
2 Sie können auch git pull
ein praktisches Skript verwenden , das zunächst ausgeführt wird git fetch
. Sobald der Abruf abgeschlossen ist, wird das Convenience-Skript entweder git merge
oder ausgeführt git rebase
, je nachdem, wie Sie es konfigurieren und ausführen.
git cherry-pick
erklärengit rebase
. Sieht großartig aus!--no-ff
hier.Ja, da gibt es einen Unterschied.
git merge --ff-only
wird abgebrochen, wenn es nicht schnell vorspulen kann, und es wird ein Commit (normalerweise ein Zweig) zum Zusammenführen benötigt. Es wird nur ein Commit-Commit erstellt, wenn es nicht schnell vorspulen kann (dh niemals mit--ff-only
).git rebase
Schreibt den Verlauf des aktuellen Zweigs neu oder kann verwendet werden, um einen vorhandenen Zweig auf einen vorhandenen Zweig umzustellen. In diesem Fall wird kein Zusammenführungs-Commit erstellt, da es neu basiert und nicht zusammengeführt wird.quelle
git merge
niemals neu (mit oder ohne--ff-only
).--ff-only
Verhindert eine andere Zusammenführung als eine Schnellvorlaufzusammenführung (keine Zusammenführung schreibt den Verlauf neu). Bei anderen Zusammenführungen als Schnellvorlauf-Zusammenführungen werden die Änderungssätze im Allgemeinen einfach in der falschen Reihenfolge angewendet (dies ist eine Vereinfachung, aber gut genug), und es werden Metadaten aufgezeichnet, mit denen ein Änderungssatz zusammengeführt wurde. Keine Umschreibung der Geschichte erforderlich.Ja,
--ff-only
wird immer dort versagen, wo eine Ebenegit merge
versagen würde, und könnte dort versagen, wo eine Ebene erfolgreich seingit merge
würde. Das ist der Punkt - wenn Sie versuchen, einen linearen Verlauf beizubehalten, und die Zusammenführung nicht auf diese Weise durchgeführt werden kann, möchten Sie, dass sie fehlschlägt.Eine Option, die einem Befehl Fehlerfälle hinzufügt, ist nicht nutzlos. Auf diese Weise können Sie eine Vorbedingung überprüfen. Wenn der aktuelle Status des Systems nicht Ihren Erwartungen entspricht, verschlimmern Sie das Problem nicht.
quelle
merge --ff-only
entfernen Sie Commits von einer Stelle im Verlaufsbaum und fügen sie (mit Änderungen) an einer anderen Stelle wieder ein. Dies wird als "Verlauf neu schreiben" bezeichnet und ist in Ordnung, wenn Sie sich in einem unveröffentlichten Zweig befinden. Nachdem Sie Ihren Zweig veröffentlicht haben und andere Personen ihn geklont haben, verursacht das Umschreiben des Verlaufs Probleme für sie.