Beim Verwenden von gitk log
konnte ich keinen Unterschied in der Wirkung von git merge
und git merge --no-ff
feststellen. Wie kann ich den Unterschied beobachten (mit einem git-Befehl oder einem Tool)?
Antworten
Zu viele Anzeigen?Die --no-ff
-Flag verhindert, dass git merge
einen "Fast-Forward" ausführt, wenn festgestellt wird, dass Ihr aktuelles HEAD
ein Vorfahr des Commits ist, den Sie zusammenführen möchten. Ein Fast-Forward ist, wenn Git statt eines Merge-Commits einfach den Branch-Pointer auf den eingehenden Commit verschiebt. Dies tritt häufig auf, wenn Sie ein git pull
ohne lokale Änderungen durchführen.
Gelegentlich möchten Sie jedoch verhindern, dass dieses Verhalten auftritt, in der Regel, weil Sie eine spezifische Branch-Topologie beibehalten möchten (z. B. wenn Sie einen Themen-Branch zusammenführen und sicherstellen möchten, dass dies beim Lesen der Historie so aussieht). Um dies zu erreichen, können Sie die --no-ff
-Flag übergeben und git merge
wird immer einen Merge erstellen, anstatt einen Fast-Forward durchzuführen.
Ebenso, wenn Sie ein git pull
ausführen oder git merge
verwenden möchten, um explizit einen Fast-Forward durchzuführen, und abbrechen möchten, wenn es nicht möglich ist, dann können Sie die --ff-only
-Flag verwenden. Auf diese Weise können Sie regelmäßig etwas wie git pull --ff-only
ohne Nachdenken ausführen, und wenn ein Fehler auftritt, können Sie zurückgehen und entscheiden, ob Sie zusammenführen oder rebaseen möchten.
Grafische Antwort auf diese Frage
Hier ist eine Seite mit einer klaren Erklärung und grafischen Darstellung zur Verwendung von git merge --no-ff
:
Bevor ich das gesehen habe, war ich mit Git komplett verloren. Die Verwendung von --no-ff
ermöglicht es jemandem, der die Historie überprüft, klar zu erkennen, welchen Branch du ausgecheckt hast, um daran zu arbeiten. (Dieser Link verweist auf das "Network"-Visualisierungstool von Github) Und hier ist eine weitere großartige Referenz mit Illustrationen. Diese Referenz ergänzt die erste schön und konzentriert sich mehr auf diejenigen, die weniger vertraut mit Git sind.
Grundlegende Informationen für Anfänger wie mich
Wenn du wie ich bist und kein Git-Guru, beschreibt meine Antwort hier den Umgang mit der Löschung von Dateien aus Git-Tracking, ohne sie vom lokalen Dateisystem zu löschen, was schlecht dokumentiert, aber häufig vorkommt. Eine weitere Anfängersituation ist das Abrufen des aktuellen Codes, was mir immer noch schwerfällt.
Beispiel-Workflow
Ich habe ein Paket auf meiner Website aktualisiert und musste in meinen Notizen nachsehen, um meinen Workflow zu sehen; Ich dachte, es wäre nützlich, ein Beispiel zu dieser Antwort hinzuzufügen.
Mein Workflow von Git-Befehlen:
git checkout -b kontaktformular
(tue deine Arbeit am "kontaktformular")
git status
git commit -am "Formular im Kontaktmodul aktualisiert"
git checkout master
git merge --no-ff kontaktformular
git branch -d kontaktformular
git push origin master
Unten: tatsächliche Verwendung, einschließlich Erklärungen.
Hinweis: Die unten stehende Ausgabe ist gekürzt; Git ist ziemlich ausführlich.
$ git status
# Im Branch master
# Geändert, aber nicht aktualisiert:
# (Nutze "git add/rm ..." um zu aktualisieren, was committed werden soll)
# (Nutze "git checkout -- ..." um Änderungen im Arbeitsverzeichnis zu verwerfen)
#
# geändert: ecc/Desktop.php
# geändert: ecc/Mobile.php
# gelöscht: ecc/ecc-config.php
# geändert: ecc/readme.txt
# geändert: ecc/test.php
# gelöscht: passthru-adapter.igs
# gelöscht: shop/mickey/index.php
#
# Nicht verfolgte Dateien:
# (Nutze "git add ..." um zu includieren, was committed werden soll)
#
# ecc/upgrade.php
# ecc/webgility-config.php
# ecc/webgility-config.php.bak
# ecc/webgility-magento.php
Beachte 3 Dinge von oben:
1) In der Ausgabe kannst du die Änderungen am ECC-Paket-Upgrade sehen, einschließlich der Hinzufügung neuer Dateien.
2) Beachte auch, dass es zwei Dateien (nicht im /ecc
Ordner) gibt, die ich unabhängig von dieser Änderung gelöscht habe. Anstatt diese Dateilöschungen mit ecc
zu verwechseln, werde ich später einen anderen cleanup
Branch erstellen, um diese Dateilöschungen widerzuspiegeln.
3) Ich habe meinen Workflow nicht beachtet! Ich habe Git vergessen, während ich versucht habe, ecc wieder zum Laufen zu bringen.
Unten: Statt des allumfassenden git commit -am "updated ecc package"
, den ich normalerweise machen würde, wollte ich nur die Dateien im /ecc
Ordner hinzufügen. Diese gelöschten Dateien waren nicht explizit Teil meines git add
, aber weil sie bereits in Git nachverfolgt wurden, musste ich sie von diesem Branch-Commit entfernen:
$ git checkout -b ecc
$ git add ecc/*
$ git reset HEAD passthru-adapter.igs
$ git reset HEAD shop/mickey/index.php
Nicht eingecheckte Änderungen nach dem Reset:
M passthru-adapter.igs
M shop/mickey/index.php
$ git commit -m "Webgility ecc Desktop Connector-Dateien; integriert mit Quickbooks"
$ git checkout master
D passthru-adapter.igs
D shop/mickey/index.php
Zu Branch 'master' gewechselt
$ git merge --no-ff ecc
$ git branch -d ecc
Branch ecc gelöscht (war 98269a2).
$ git push origin master
Zähle Objekte: 22, erledigt.
Delta-Komprimierung mit bis zu 4 Threads.
Objekte werden komprimiert: 100% (14/14), erledigt.
Schreibe Objekte: 100% (14/14), 59,00 KiB, erledigt.
Total 14 (delta 10), wiederverwendet 0 (delta 0)
Zu git@github.com:me/mywebsite.git
8a0d9ec..333eff5 master -> master
Skript zur Automatisierung des Obigen
Da ich diesen Prozess an einem Tag mehr als 10 Mal verwendet habe, habe ich begonnen, Batch-Skripte zu schreiben, um die Befehle auszuführen, also habe ich ein fast korrektes git_update.sh <"commit message">
Skript geschrieben, um die oben genannten Schritte durchzuführen. Hier ist die Gist-Quelle für dieses Skript.
Anstatt von git commit -am
wähle ich Dateien aus der "geänderte" Liste, die über git status
erzeugt wurde, und füge diese dann in das Skript ein. Dies ergab sich, weil ich Dutzende von Änderungen vorgenommen habe, aber verschiedene Branch-Namen wollte, um die Änderungen zu gruppieren.
Explizite Zusammenführung (auch bekannt als nicht fast-forward): Erstellt einen neuen Zusammenführungscommit. (Das ist das, was du bekommst, wenn du --no-ff
verwendet hast.)
Fast-Forward-Zusammenführung: Vorwärts schnell, ohne einen neuen Commit zu erstellen:
Rebase: Einen neuen Basislevel festlegen:
Squash: Füge oder drücke (etwas) mit Kraft zusammen, so dass es flach wird:
Die Option --no-ff
stellt sicher, dass ein Fast-Forward-Zusammenführung nicht stattfindet und dass immer ein neues Commit-Objekt erstellt wird. Das kann wünschenswert sein, wenn Sie möchten, dass git eine Historie von Feature-Zweigen beibehält. Im obigen Bild ist die linke Seite ein Beispiel für die Git-Historie nach Verwendung von
git merge --no-ff
und die rechte Seite ist ein Beispiel für die Verwendung von git merge
, wo ein ff-Merge möglich war.
BEARBEITEN: Eine frühere Version dieses Bildes zeigte nur ein einzelnes Elternteil für das Merge-Commit. Merge-Commits haben mehrere Elterncommits, die von git verwendet werden, um eine Historie des "Feature-Zweigs" und des ursprünglichen Zweigs beizubehalten. Die mehrfachen Elternlinks sind grün markiert.
- See previous answers
- Weitere Antworten anzeigen