Warum führt git pull standardmäßig eine Zusammenführung statt einer Neugründung durch?

71

Betrachten Sie die folgende Situation:

  • Sie haben einen Klon eines Git-Repository
  • Sie haben einige lokale Commits (Commits, die noch nirgendwo gepusht wurden)
  • Das Remote-Repository verfügt über neue Commits, die Sie noch nicht abgeglichen haben

So etwas in der Art:

Nicht zusammengeführte Commits

Wenn Sie git pullmit den Standardeinstellungen ausführen , erhalten Sie ungefähr Folgendes:

Merge Commit

Dies liegt daran, dass git eine Zusammenführung durchgeführt hat.

Es gibt jedoch eine Alternative. Sie können pull anweisen, stattdessen eine Rebase durchzuführen:

git pull --rebase

und du bekommst folgendes:

neu gegründet

Meiner Meinung nach hat die neu basierende Version zahlreiche Vorteile, bei denen es hauptsächlich darum geht, Ihren Code und den Verlauf sauber zu halten. Daher bin ich ein wenig überrascht, dass git die Zusammenführung standardmäßig vornimmt. Ja, die Hashes Ihrer lokalen Commits werden geändert, aber dies scheint ein geringer Preis für die einfachere Historie zu sein, die Sie dafür erhalten.

Ich behaupte aber keineswegs, dass dies irgendwie ein schlechter oder falscher Standard ist. Ich habe nur Probleme beim Überlegen von Gründen, warum die Zusammenführung für die Standardeinstellung bevorzugt werden könnte. Haben wir einen Einblick, warum es ausgewählt wurde? Gibt es Vorteile, die es als Standard besser geeignet machen?

Die Hauptmotivation für diese Frage ist, dass mein Unternehmen versucht, einige grundlegende Standards (hoffentlich eher Richtlinien) für die Organisation und Verwaltung unserer Repositorys festzulegen, um Entwicklern die Annäherung an ein Repository zu erleichtern, mit dem sie zuvor noch nicht gearbeitet haben. Ich bin daran interessiert, einen Fall zu machen, in dem wir normalerweise in einer solchen Situation einen Rebase durchführen sollten (und wahrscheinlich, um Entwicklern zu empfehlen, ihre globale Konfiguration standardmäßig auf Rebase zu setzen), aber wenn ich dagegen wäre, würde ich mit Sicherheit fragen, warum Rebase nicht funktioniert. t der Standard, wenn es so toll ist. Also frage ich mich, ob ich etwas vermisse.

Es wurde vermutet, dass diese Frage ein Duplikat von Warum bevorzugen so viele Websites "Git Rebase" gegenüber "Git Merge"? ; Diese Frage ist jedoch etwas umgekehrt . In diesem Artikel werden die Vorteile von Zusammenführung über Zusammenführung erörtert, während in dieser Frage die Vorteile von Zusammenführung über Zusammenführung erörtert werden. Die Antworten dort spiegeln dies wider und konzentrieren sich auf Probleme mit dem Zusammenführen und den Vorteilen von Rebase.

jpmc26
quelle
Das andere Problem ist, dass, wenn Sie sich versehentlich zum Master verpflichten, ein Pull ausgeführt wird, der zusammengeführt wird, die beiden Master möglicherweise nicht synchron sind, obwohl das Zusammenführen normal aussieht. Aus diesem Grund enthält mein Pull-Alias ​​"--ff-only".
Ixrec
Wenn Sourcetree jemals die Diagrammansicht ändert, sodass Rebases / Merges anders angezeigt werden, werden Sie dann zur Zusammenführung wechseln?
Ewan
1
@Ewan SourceTree sollte die Grafikansicht nicht ändern. Es stellt das Diagramm genau dar.
jpmc26
4
Beachten Sie bitte, dass der Inhalt der von mir akzeptierten Antwort in der von Ihnen behaupteten Frage definitiv nicht doppelt vorhanden ist.
jpmc26

Antworten:

56

Es ist schwer zu wissen, warum das Zusammenführen die Standardeinstellung ist, ohne von der Person zu hören, die diese Entscheidung getroffen hat.

Hier ist eine Theorie ...

Git kann nicht davon ausgehen, dass es in Ordnung ist, jeden Pull zu löschen. Hören Sie, wie sich das anhört. "Wiederholen Sie jeden Zug." Klingt einfach falsch, wenn Sie Pull-Requests oder ähnliches verwenden. Würden Sie auf eine Pull-Anfrage zurückgreifen?

In einem Team, das Git nicht nur für die zentrale Quellcodeverwaltung verwendet ...

  • Sie können von stromaufwärts und von stromabwärts ziehen. Einige Leute ziehen viel von stromabwärts, von Mitwirkenden usw.

  • Möglicherweise arbeiten Sie in enger Zusammenarbeit mit anderen Entwicklern an Features, die Sie aus diesen oder einem Zweig mit gemeinsam genutzten Themen abrufen und gelegentlich noch über den Upstream aktualisieren. Wenn Sie sich immer zurücklehnen, ändern Sie letztendlich die gemeinsame Geschichte, ganz zu schweigen von unterhaltsamen Konfliktzyklen.

Git wurde für ein großes, stark verteiltes Team entwickelt, bei dem nicht jeder an einem einzigen zentralen Repo zieht und pusht. Die Voreinstellung macht also Sinn.

  • Entwickler, die nicht wissen, wann ein Rebase möglich ist, werden standardmäßig zusammengeführt.
  • Entwickler können nach Belieben rebasieren.
  • Commiter, die viel ziehen und viel ziehen, erhalten die Standardeinstellung, die am besten zu ihnen passt.

Zum Beweis der Absicht hier ein Link zu einer bekannten E-Mail von Linus Torvalds mit seinen Ansichten darüber, wann sie nicht zurückgewiesen werden sollten. Dri-Devel Git Pull E-Mail

Wenn Sie dem gesamten Thread folgen, können Sie sehen, dass ein Entwickler von einem anderen Entwickler und Linus von beiden Entwicklern zieht. Er macht seine Meinung ziemlich klar. Da er wahrscheinlich über Gits Standardeinstellungen entschieden hat, könnte dies den Grund erklären.

Viele Leute verwenden Git jetzt zentral, wobei jeder in einem kleinen Team nur von einem zentralen Upstream-Repo abruft und auf dieselbe Fernbedienung pusht. Dieses Szenario vermeidet einige Situationen, in denen eine Rebase nicht gut ist, beseitigt sie jedoch normalerweise nicht.

Vorschlag: Machen Sie keine Richtlinie zum Ändern der Standardeinstellung. Jedes Mal, wenn Sie Git mit einer großen Gruppe von Entwicklern zusammenstellen, werden einige der Entwickler Git nicht so gut verstehen (ich selbst eingeschlossen). Sie gehen zu Google, SO, holen sich Kochbuchratschläge und fragen sich dann, warum einige Dinge nicht funktionieren, z. B. warum git checkout --ours <path>die falsche Version der Datei abgerufen wird. Sie können Ihre lokale Umgebung jederzeit überarbeiten, Aliase usw. erstellen, um sie Ihrem Geschmack anzupassen.

joshp
quelle
5
+1, um die Standardeinstellungen nicht zu ändern - anstatt einen eigenen Git-Workflow zu erstellen, ist es wahrscheinlich besser, einen vorhandenen zu verwenden (z. B. einen von Atlassian atlassian.com/git/tutorials/comparing-workflows/… )
Rob Church
1
Danke für die Antwort. Die Info über das Abziehen vom Downstream hat mir gefehlt. Interessanterweise ermutigt der von Ihnen angegebene Link auch genau das, was ich erreichen möchte: "Die Menschen können (und sollten) ihre privaten Bäume (ihre eigene Arbeit) neu stützen ."
jpmc26
2
@jpmc Großartig. Tatsächlich. Das Wiederaufforsten von Privatbäumen kann eine Menge ablenkenden Stoff aus der gemeinsamen Geschichte heraushalten. Ich tue es. Die Klarheit, wann nicht, ist wichtig.
Joshp
"Einige Entwickler werden Git nicht so gut verstehen". Rebase ist KEINE super schicke ("deep", etc) Funktion von Git. Findest du das wirklich so schwer zu verstehen? Ich denke, dass dies ein Auslöser sein sollte, um Entwickler als inkompetent zu bezeichnen.
Victor Yarema
15

Wenn Sie die Git-Manpage für Rebase lesen, heißt es :

Das Neuformulieren (oder jede andere Form des Neuschreibens) eines Zweigs, auf dem andere basieren, ist eine schlechte Idee: Jeder, der sich dahinter befindet, muss seinen Verlauf manuell korrigieren. In diesem Abschnitt wird erläutert, wie die Fehlerbehebung aus Sicht des Downstreams durchgeführt wird. Die eigentliche Lösung wäre jedoch, zu vermeiden, dass der Upstream neu gegründet wird.

Ich denke, das sagt es als Grund genug, Rebase überhaupt nicht zu verwenden, geschweige denn es automatisch für jeden Zug zu tun. Einige Leute halten Rebase für schädlich . Vielleicht hätte es gar nicht in Schwung gebracht werden dürfen, denn alles, was es zu tun scheint, ist, die Geschichte zu verschönern. Dies sollte in keinem SCM notwendig sein, dessen einzige wesentliche Aufgabe darin besteht, die Geschichte zu bewahren.

Wenn Sie sagen, dass Sie die Geschichte sauber halten, denken Sie, dass Sie sich irren. Es sieht vielleicht besser aus, aber für ein Tool, mit dem der Verlauf von Revisionen festgehalten werden soll, ist es viel sauberer, jedes Commit beizubehalten, damit Sie sehen können, was passiert ist. Die Geschichte danach zu bereinigen ist wie die Patina wegzupolieren und ein reiches antikes Aussehen wie eine glänzende Reproduktion erscheinen zu lassen :-)

gbjbaanb
quelle
3
@Ewan IMHO "funktioniert nicht, sieht aber gut aus" ist etwas, das ausschließlich der Modeindustrie vorbehalten sein sollte, nicht der IT. IMHO Git sollte es entfernen, da es offensichtlich zu viele Menschen ermutigt, zu denken, dass Stil wichtiger ist als Substanz.
gbjbaanb
12
Ich würde Ihren Vorschlag bestreiten, dass es sinnlos ist, die Geschichte sauber zu halten. Es ist nicht. Ein Repository Geschichte ist für den menschlichen Verzehr bestimmt sind , und als solche gibt es eine Menge von Wert darin lesbar zu machen. In meinem speziellen Anwendungsfall beabsichtigen wir sogar, dass Nicht-Entwickler- Projektmanager den Verlauf lesen können. Ein sauberer Verlauf kann nur dabei helfen, und er kann einem neuen Entwickler helfen, der die Codebasis noch nie gesehen hat und einen Fehler beheben muss, um zu verstehen, was in einem bestimmten Codebereich passiert ist.
jpmc26
3
Code existiert in erster Linie, um von einer Maschine ausgeführt zu werden (möglicherweise nachdem er kompiliert wurde). Unter Anwendung der obigen Philosophie kommen wir zu dem Schluss, dass die Lesbarkeit des Codes keine Rolle spielt, da keine ausreichende Lesbarkeit die Schwierigkeit löst, Code zu verstehen. Ich habe nie vorgeschlagen, etwas zu zerdrücken. Ich sage nur, dass es schwierig ist, einem komplexen Graphen zu folgen, der in viele sich kreuzende Pfade abweicht. Es lohnt sich also, ein wenig in die Aufrechterhaltung einer relativ sauberen Historie zu investieren. Beachten Sie auch, dass eine lineare Historie die Nutzung von Git-Werkzeugen wie "Blame" und "Bisect" fördert.
jpmc26
6
Die Dokumente sagen nicht "Nicht rebasieren". Es heißt: "Verwandle keine Änderungen, die anderen Leuten übergeordnet sind ." Es gibt eine Welt voller Unterschiede zwischen diesen beiden. Linus selbst rät zu einer Umstrukturierung, um die Geschichte zu organisieren, wie aus dem Link in der akzeptierten Antwort hervorgeht. Und woher weiß ein Tool, welche Commits irrelevant sind (insbesondere, wenn Tools Schwierigkeiten haben, eine nichtlineare Historie zu analysieren!) Und mit welchem ​​Commit möchten Sie differenzieren (insbesondere, ohne in der Lage zu sein, die Historie zu durchforsten!)? Sie nehmen ein Wort der Vorsicht über eine bestimmte Situation zu einem dogmatischen Extrem.
jpmc26
4
Sie möchten auf keinen Fall die Änderungshistorie behalten, wenn dies alle Commits einschließt, die ein Entwickler jemals gemacht hat. Nach dieser Logik sollten wir auch die Originalversion des Codes jedes Mal aufzeichnen, wenn die Rücktaste gedrückt wurde. Jedes Commit sollte eine minimale und vollständige Änderung sein, die das gesamte Projekt in einem stabilen Zustand hält. Wenn sich später herausstellt, dass Ihr ursprüngliches Commit fehlerhaft ist, ist es viel besser, das Commit neu zu definieren, zu bearbeiten oder zu ändern, als ein neues zu erstellen. Siehe jedoch auch mail-archive.com/[email protected]/msg39091.html
Mikko Rantalainen
12

Sie haben Recht, vorausgesetzt, Sie haben nur ein lokales / geändertes Repository. Denken Sie jedoch beispielsweise daran, dass es einen zweiten lokalen PC gibt.

Sobald Ihre lokale / geänderte Kopie an einen anderen Ort verschoben wird, werden diese Kopien durch eine Neu-Basierung beschädigt. Natürlich kann man das Drücken erzwingen, aber das wird schnell kompliziert. Was passiert, wenn einer oder mehrere von ihnen einen völlig neuen Commit haben?

Wie Sie sehen, ist es sehr situativ, aber die Basisstrategie scheint (für mich) in nicht speziellen Fällen / Kollaborationsfällen viel praktischer zu sein.


Ein zweiter Unterschied: Die Merge-Strategie behält eine klare und zeitlich konsistente Struktur bei. Nach Rebases ist es sehr wahrscheinlich, dass ältere Commits auf neuere Änderungen folgen und die gesamte Historie und ihren Ablauf schwerer zu verstehen sind.

Mario
quelle
1
"Nach Rebases ist es sehr wahrscheinlich, dass ältere Commits auf neuere Änderungen folgen." Die Zeit, zu der ein Commit ausgeführt wurde, kann lange vor der Zusammenführung liegen, die es in diesen Zweig gebracht hat.
Steve Jessop
6

Der Hauptgrund ist wahrscheinlich, dass das Standardverhalten in öffentlichen Repos "nur funktionieren" sollte. Die Wiederaufnahme der Geschichte, die andere Menschen bereits zusammengeführt haben, wird ihnen Ärger bereiten. Ich weiß, dass Sie über Ihr privates Repo sprechen, aber im Allgemeinen weiß git nicht, was privat oder öffentlich ist, und kümmert sich nicht darum. Daher wird der ausgewählte Standard für beide der Standard sein.

Ich verwende git pull --rebaseziemlich viel in meinem privaten Repo, aber selbst dort hat es einen möglichen Nachteil, nämlich, dass die Geschichte meines HEADBaums nicht mehr den Baum widerspiegelt, an dem ich tatsächlich gearbeitet habe.

Angenommen, ich führe immer Tests durch und stelle sicher, dass sie erfolgreich sind, bevor ich ein Commit durchführe. Dies ist weniger relevant, nachdem ich a ausgeführt habe git pull --rebase, da es nicht mehr stimmt, dass der Baum bei jedem meiner Commits die Tests bestanden hat. Solange die Änderungen in irgendeiner Weise nicht stören, und der Code , den ich ziehe getestet wurde, dann vermutlich es würde die Tests bestehen, aber wir wissen nicht , weil ich es nie versucht. Wenn die fortlaufende Integration ein wichtiger Bestandteil Ihres Workflows ist, ist jede Art von Rebase in einem Repo, das CIed wird, problematisch.

Ich habe nichts dagegen, aber es stört einige Leute: Sie würden es vorziehen, wenn ihre Geschichte in git den Code widerspiegelt, an dem sie tatsächlich gearbeitet haben (oder vielleicht, wenn sie es pushen, eine vereinfachte Version der Wahrheit nach einigem Gebrauch von "fixup").

Ich weiß nicht, ob gerade dieses Problem der Grund ist, warum Linus sich für eine Zusammenführung entschieden hat, anstatt sich standardmäßig neu zu orientieren. Es könnte andere Nachteile geben, die ich nicht angetroffen habe. Aber da er nicht schüchtern ist, seine Meinung im Code auszudrücken, bin ich mir ziemlich sicher, dass es darauf ankommt, was er für einen geeigneten Workflow für Leute hält, die nicht zu viel darüber nachdenken möchten (und insbesondere für diejenigen, die eher in der Öffentlichkeit arbeiten) als ein privates Repo). Das Vermeiden von parallelen Linien in der hübschen Grafik zugunsten einer sauberen geraden Linie, die nicht die parallele Entwicklung darstellt, wie es passiert ist, ist wahrscheinlich nicht seine oberste Priorität, auch wenn es Ihre ist :-)

Steve Jessop
quelle