Warum führt git standardmäßig Schnellvorlaufzusammenführungen durch?


640

Ich komme aus Mercurial und verwende Zweige, um Features zu organisieren. Natürlich möchte ich diesen Workflow auch in meiner Geschichte sehen.

Ich habe mein neues Projekt mit git gestartet und mein erstes Feature fertiggestellt. Beim Zusammenführen der Funktion wurde mir klar, dass git den Schnellvorlauf verwendet, dh meine Änderungen werden nach Möglichkeit direkt auf den Hauptzweig angewendet und mein Zweig wird vergessen.

Um in die Zukunft zu denken: Ich bin der einzige, der an diesem Projekt arbeitet. Wenn ich den Standardansatz von git (schnelles Zusammenführen) verwende, würde meine Historie zu einem riesigen Hauptzweig führen. Niemand weiß, dass ich für jedes Feature einen eigenen Zweig verwendet habe, da ich am Ende nur diesen riesigen Hauptzweig haben werde. Wird das nicht unprofessionell aussehen?

Aus diesem Grund möchte ich kein schnelles Zusammenführen und kann nicht erkennen, warum dies die Standardeinstellung ist. Was ist daran so gut?


38
Hinweis: Siehe auch sandofsky.com/blog/git-workflow.html und vermeiden Sie das ' no-ff' mit seinen "Checkpoint Commits", die die Halbierung oder Schuld brechen.
VonC

15
Bedauern Sie es, Git für ein Ein-Mann-Projekt verwendet zu haben?
HaveAGuess

27
Absolut nicht! In meinem Arbeitsordner habe ich 7 Ein-Mann-Projekte, in denen ich Git verwende. Lassen Sie mich das umformulieren: Ich habe viele Projekte gestartet, seit ich diese Frage gestellt habe, und alle sind über git versioniert. Soweit ich weiß, unterstützen nur Git und Mercurial die lokale Versionierung, was für mich von wesentlicher Bedeutung ist, seit ich mich daran gewöhnt habe. Es ist einfach einzurichten und Sie haben immer die gesamte Geschichte dabei. In Gruppenprojekten ist es sogar noch besser, da Sie sich verpflichten können, ohne jemanden in Ihren Work-in-Progress-Code zu stören. Außerdem benutze ich Github, um einige meiner Projekte (z. B. Micro-Optparse) zu teilen, bei denen Git erforderlich ist.
Florian Pilz

7
@Cawas stimmt, -no-ffist selten eine gute Idee, kann aber dennoch dazu beitragen, einen funktionsinternen Verlauf beizubehalten, während nur ein Commit im Hauptzweig aufgezeichnet wird. Dies ist sinnvoll für eine lange Feature-Historie, wenn Sie von Zeit zu Zeit deren Verlauf auf dem Hauptzweig zusammenführen.
VonC

12
Übrigens zu Ihrer Frage: "Sieht das [eine lineare Zweiggeschichte] nicht unprofessionell aus?". Es ist nichts Unprofessionelles an der Verwendung eines Quellcodesystems mit seinen Standardeinstellungen. Hier geht es nicht um Professionalität. Hier geht es darum zu bestimmen, welche Philosophie der Verzweigung Sie abonnieren. Zum Beispiel hat @VonC einen Link zu Sandofskys Artikel erstellt, in dem er sich dafür einsetzt, den schnellen Vorlauf als überlegenen Ansatz zu verwenden. Nicht richtig oder falsch, nur unterschiedliche Philosophien für unterschiedliche Kontexte.
Marplesoft

Antworten:


717

Das Zusammenführen mit schnellem Vorlauf ist für kurzlebige Zweige sinnvoll. In einem komplexeren Verlauf kann das Zusammenführen mit nicht schnellem Vorlauf das Verständnis des Verlaufs erleichtern und das Zurücksetzen einer Gruppe von Commits erleichtern.

Warnung : Ein nicht schneller Vorlauf hat ebenfalls mögliche Nebenwirkungen. Bitte überprüfen Sie https://sandofsky.com/blog/git-workflow.html , vermeiden Sie das "no-ff" mit seinen "Checkpoint Commits", die die Halbierung oder Schuld brechen, und überlegen Sie sorgfältig, ob dies Ihr Standardansatz sein sollte master.

Alt-Text
(Von nvie.com , Vincent Driessen , Beitrag " Ein erfolgreiches Git-Verzweigungsmodell ")

Einbeziehen eines fertigen Features in die Entwicklung

Fertige Funktionen können in den Entwicklungszweig integriert werden, um sie der kommenden Version hinzuzufügen:

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git push origin develop

Das --no-ffFlag bewirkt, dass bei der Zusammenführung immer ein neues Festschreibungsobjekt erstellt wird, auch wenn die Zusammenführung mit einem schnellen Vorlauf durchgeführt werden könnte. Dadurch wird vermieden, dass Informationen über die historische Existenz eines Feature-Zweigs verloren gehen und alle Commits zusammengefasst werden, die das Feature hinzugefügt haben.

Jakub Narębski auch erwähnt die Configmerge.ff :

Standardmäßig erstellt Git kein zusätzliches Zusammenführungs-Commit, wenn ein Commit zusammengeführt wird, das ein Nachkomme des aktuellen Commits ist. Stattdessen wird die Spitze des aktuellen Zweigs vorgespult.
Wenn falsediese Variable auf gesetzt ist, weist sie Git an, in einem solchen Fall ein zusätzliches Merge-Commit zu erstellen (entspricht der Angabe der --no-ffOption über die Befehlszeile).
Bei der Einstellung ' only' sind nur solche Schnellvorlaufzusammenführungen zulässig (entspricht der --ff-onlyOption über die Befehlszeile).


Der schnelle Vorlauf ist die Standardeinstellung, weil:

  • kurzlebige Zweige sind in Git sehr einfach zu erstellen und zu verwenden
  • kurzlebige Zweige isolieren oft viele Commits, die innerhalb dieses Zweigs frei reorganisiert werden können
  • Diese Commits sind tatsächlich Teil des Hauptzweigs: Sobald sie neu organisiert wurden, wird der Hauptzweig schnell weitergeleitet, um sie einzuschließen.

Wenn Sie jedoch einen iterativen Workflow für einen Themen- / Feature-Zweig erwarten (dh ich füge zusammen, dann gehe ich zurück zu diesem Feature-Zweig und füge weitere Commits hinzu), ist es nützlich, nur die Zusammenführung in den Hauptzweig aufzunehmen und nicht Alle Zwischen-Commits des Feature-Zweigs.

In diesem Fall können Sie am Ende diese Art von Konfigurationsdatei festlegen :

[branch "master"]
# This is the list of cmdline options that should be added to git-merge 
# when I merge commits into the master branch.

# The option --no-commit instructs git not to commit the merge
# by default. This allows me to do some final adjustment to the commit log
# message before it gets commited. I often use this to add extra info to
# the merge message or rewrite my local branch names in the commit message
# to branch names that are more understandable to the casual reader of the git log.

# Option --no-ff instructs git to always record a merge commit, even if
# the branch being merged into can be fast-forwarded. This is often the
# case when you create a short-lived topic branch which tracks master, do
# some changes on the topic branch and then merge the changes into the
# master which remained unchanged while you were doing your work on the
# topic branch. In this case the master branch can be fast-forwarded (that
# is the tip of the master branch can be updated to point to the tip of
# the topic branch) and this is what git does by default. With --no-ff
# option set, git creates a real merge commit which records the fact that
# another branch was merged. I find this easier to understand and read in
# the log.

mergeoptions = --no-commit --no-ff

Das OP fügt in den Kommentaren hinzu:

Ich sehe einen gewissen Sinn im Schnellvorlauf für [kurzlebige] Zweige, aber wenn ich ihn zur Standardaktion mache, geht Git davon aus, dass Sie ... oft [kurzlebige] Zweige haben. Angemessen?

Jefromi antwortet:

Ich denke, die Lebensdauer der Zweige ist von Benutzer zu Benutzer sehr unterschiedlich. Bei erfahrenen Benutzern besteht jedoch wahrscheinlich die Tendenz, weitaus kurzlebigere Zweige zu haben.

Für mich ist ein kurzlebiger Zweig ein Zweig, den ich erstelle, um einen bestimmten Vorgang zu vereinfachen (erneutes Basieren, wahrscheinlich oder schnelles Patchen und Testen) und dann sofort zu löschen, wenn ich fertig bin.
Das bedeutet, dass es wahrscheinlich in den Themenzweig aufgenommen werden sollte, aus dem es gespalten wurde , und der Themenzweig wird als ein Zweig zusammengeführt. Niemand muss wissen, was ich intern getan habe, um eine Reihe von Commits zu erstellen, die diese bestimmte Funktion implementieren.

Ganz allgemein füge ich hinzu:

Es hängt wirklich von Ihrem Entwicklungsworkflow ab :

  • Wenn es linear ist, ist ein Zweig sinnvoll.
  • Wenn Sie Features isolieren und über einen längeren Zeitraum bearbeiten und wiederholt zusammenführen müssen, sind mehrere Zweige sinnvoll.

Siehe " Wann sollten Sie verzweigen? "

Wenn Sie das Mercurial-Zweigmodell betrachten, ist es im Kern ein Zweig pro Repository (obwohl Sie anonyme Köpfe, Lesezeichen und sogar benannte Zweige erstellen können ).
Siehe "Git und Mercurial - Vergleichen und Kontrastieren" .

Mercurial verwendet standardmäßig anonyme Lightweight-Codelines, die in ihrer Terminologie als "Köpfe" bezeichnet werden.
Git verwendet leichtgewichtige benannte Zweige mit injektiver Zuordnung, um Namen von Zweigen im Remote-Repository Namen von Remote-Tracking-Zweigen zuzuordnen.
Git "zwingt" Sie, Zweige zu benennen (nun, mit Ausnahme eines einzelnen unbenannten Zweigs, der als " losgelöster HEAD " bezeichnet wird), aber ich denke, dies funktioniert besser mit verzweigungsintensiven Workflows wie dem Themenzweig-Workflow mehrere Zweige in einem einzigen Repository-Paradigma.


Wow das war schnell. ;) Ich kenne die Option --no-ff, erfahre aber erst etwas über den schnellen Vorlauf, nachdem ich meine Funktion vermasselt habe. Ich sehe einen gewissen Sinn im Schnellvorlauf für kurzlebige Zweige, aber wenn ich es zur Standardaktion mache, geht Git davon aus, dass Sie am häufigsten so kurzlebige Zweige haben. Angemessen?
Florian Pilz

@Florian: Ich glaube, dies ist eine vernünftige Sicht des Prozesses. Ich habe ein Beispiel für eine Konfiguration hinzugefügt, mit der festgelegt wird, wie Sie die Zusammenführung zum Master verwalten möchten.
VonC

Vielen Dank, die Konfigurationsdatei sollte helfen, solche Fallstricke zu vermeiden. :) Diese Konfiguration wurde nur lokal mit "git config branch.master.mergeoptions '--no-ff'" angewendet
Florian Pilz

2
@BehrangSaeedzadeh: Rebasing ist ein anderes Thema (das auf dieser Seite noch nicht erwähnt wurde): Solange Sie Ihren featureZweig nicht in ein öffentliches Repo verschoben haben, können Sie ihn masterso oft wie Sie möchten neu gründen . Siehe stackoverflow.com/questions/5250817/…
VonC

4
@BehrangSaeedzadeh: Eine Rebase allein macht eine Geschichte nicht linear. Es ist die Art und Weise , wie Sie die Änderungen Ihres featureZweigs wieder integrieren master, die den Verlauf linear macht oder nicht. Eine einfache schnelle Zusammenführung macht es linear. Dies ist sinnvoll, wenn Sie den Verlauf dieses featureZweigs vor der Schnellvorlauf-Zusammenführung bereinigt haben und nur signifikante Commits hinterlassen haben, wie unter stackoverflow.com/questions/7425541/… erwähnt .
VonC

42

Lassen Sie mich auf eine etwas erweitern VonC ‚s sehr umfassende Antwort :


Wenn ich mich richtig erinnere, ist die Tatsache, dass Git im Schnellvorlauf standardmäßig keine Zusammenführungs-Commits erstellt, auf die Berücksichtigung von "gleichen Repositorys" mit einem Zweig zurückzuführen, bei denen das gegenseitige Ziehen verwendet wird, um diese beiden Repositorys zu synchronisieren (a Workflow finden Sie als erstes Beispiel in der Dokumentation der meisten Benutzer, einschließlich "The Git User's Manual" und "Version Control by Example". In diesem Fall verwenden Sie Pull nicht, um einen vollständig realisierten Zweig zusammenzuführen, sondern verwenden Sie ihn, um mit anderen Arbeiten Schritt zu halten. Sie möchten keine kurzlebigen und unwichtigen Tatsachen haben, wenn Sie eine Synchronisierung durchführen, die für die Zukunft gespeichert und im Repository gespeichert wird.

Beachten Sie, dass die Nützlichkeit von Feature-Zweigen und die Verwendung mehrerer Zweige in einem einzigen Repository erst später erfolgte, da VCS mit guter Unterstützung für das Zusammenführen häufiger verwendet wurde und verschiedene zusammenführungsbasierte Workflows ausprobiert wurden. Aus diesem Grund hat Mercurial beispielsweise ursprünglich nur einen Zweig pro Repository unterstützt (plus anonyme Tipps zum Verfolgen von Remote-Zweigen), wie in älteren Versionen von "Mercurial: The Definitive Guide" zu sehen ist.


Zweitens, wenn folgendes Best Practices der Verwendung von Feature Zweigen , nämlich dass Feature Zweige sollten alle gehen von stabiler Version ( in der Regel von den letzten Release), in der Lage sein , herauspicken und auswählen , welche durch die Auswahl , welche Funktion verzweigt zu verschmelzen umfassen Funktionen, Sie sind in der Regel nicht in der Schnellvorlaufsituation ... was dieses Problem strittig macht. Sie müssen sich Sorgen machen, dass beim Zusammenführen eines ersten Zweigs eine echte Zusammenführung und kein schneller Vorlauf erstellt wird (vorausgesetzt, Sie setzen Single-Commit-Änderungen nicht direkt auf 'master'). Alle anderen späteren Zusammenführungen befinden sich natürlich in einer Situation ohne schnellen Vorlauf.

HTH


In Bezug auf Feature-Zweige aus stabilen Releases: Was ist, wenn ein Feature, das ich für das nächste Release entwickle, von den Änderungen für ein anderes Feature abhängt, das ich bereits entwickelt und in Master zusammengeführt habe? Das bedeutet doch, dass ich diesen zweiten Feature-Zweig vom Master aus erstellen muss?
dOxxx

1
@dOxxx: Ja, es gibt Ausnahmen, z. B. wenn ein Zweig auf dem anderen aufbaut (entweder direkt oder nach dem Zusammenführen des vorherigen mit dem Master).
Jakub Narębski
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.