Zusammenfassung
Erstellt standardmäßig git pull
Zusammenführungs-Commits, die dem Codeverlauf Rauschen und Komplexität hinzufügen. Darüber hinaus pull
ist es einfach, nicht darüber nachzudenken, wie Ihre Änderungen durch eingehende Änderungen beeinflusst werden könnten.
Der git pull
Befehl ist sicher, solange er nur Schnellvorlaufzusammenführungen ausführt. Wenn git pull
konfiguriert ist, dass nur Schnellvorlaufzusammenführungen durchgeführt werden und eine Schnellvorlaufzusammenführung nicht möglich ist, wird Git mit einem Fehler beendet. Dies gibt Ihnen die Möglichkeit, die eingehenden Commits zu untersuchen, darüber nachzudenken, wie sie sich auf Ihre lokalen Commits auswirken könnten, und die beste Vorgehensweise (Zusammenführen, Wiederherstellen, Zurücksetzen usw.) festzulegen.
Mit Git 2.0 und neuer können Sie Folgendes ausführen:
git config --global pull.ff only
um das Standardverhalten auf nur schnellen Vorlauf zu ändern. Bei Git-Versionen zwischen 1.6.6 und 1.9.x müssen Sie sich angewöhnen, Folgendes zu tippen:
git pull --ff-only
Bei allen Git-Versionen empfehle ich jedoch, einen git up
Alias wie folgt zu konfigurieren :
git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'
und mit git up
anstelle von git pull
. Ich bevorzuge diesen Alias, git pull --ff-only
weil:
- es funktioniert mit allen (nicht alten) Versionen von Git,
- Es werden alle vorgelagerten Zweige abgerufen (nicht nur der Zweig, an dem Sie gerade arbeiten)
- es reinigt alte
origin/*
Äste, die stromaufwärts nicht mehr existieren.
Probleme mit git pull
git pull
ist nicht schlecht, wenn es richtig verwendet wird. Einige kürzlich vorgenommene Änderungen an Git haben die git pull
ordnungsgemäße Verwendung vereinfacht , aber leider git pull
weist das Standardverhalten einer Ebene mehrere Probleme auf:
- es führt unnötige Nichtlinearitäten in die Geschichte ein
- Dies macht es einfach, versehentlich wieder eingeführte Commits einzuführen, die absichtlich vorgelagert wurden
- Es ändert Ihr Arbeitsverzeichnis auf unvorhersehbare Weise
- Es ist ärgerlich, anzuhalten, was Sie tun, um die Arbeit eines anderen zu überprüfen
git pull
- Dies macht es schwierig, den Remote-Zweig korrekt wiederherzustellen
- Es werden keine Zweige bereinigt, die im Remote-Repo gelöscht wurden
Diese Probleme werden nachstehend ausführlicher beschrieben.
Nichtlineare Geschichte
Standardmäßig entspricht der git pull
Befehl der Ausführung git fetch
gefolgt von git merge @{u}
. Wenn sich im lokalen Repository nicht gepuschte Commits befinden, erstellt der Zusammenführungsteil von git pull
ein Zusammenführungs-Commit.
Merge Commits sind an sich nichts Schlechtes, aber sie können gefährlich sein und sollten mit Respekt behandelt werden:
- Zusammenführungs-Commits sind von Natur aus schwer zu untersuchen. Um zu verstehen, was eine Zusammenführung bewirkt, müssen Sie die Unterschiede zu allen Eltern verstehen. Ein herkömmliches Diff vermittelt diese mehrdimensionalen Informationen nicht gut. Im Gegensatz dazu ist eine Reihe normaler Commits leicht zu überprüfen.
- Die Lösung von Zusammenführungskonflikten ist schwierig, und Fehler bleiben oft lange Zeit unentdeckt, da Zusammenführungs-Commits schwer zu überprüfen sind.
- Zusammenführungen können die Auswirkungen regelmäßiger Commits stillschweigend ersetzen. Der Code ist nicht länger die Summe der inkrementellen Commits, was zu Missverständnissen darüber führt, was sich tatsächlich geändert hat.
- Zusammenführungs-Commits können einige kontinuierliche Integrationsschemata stören (z. B. automatisch nur den Pfad des ersten Elternteils gemäß der angenommenen Konvention erstellen, dass zweite Elternteile auf unvollständige laufende Arbeiten verweisen).
Natürlich gibt es eine Zeit und einen Ort für Zusammenführungen, aber das Verständnis, wann Zusammenführungen verwendet werden sollten und wann nicht, kann die Nützlichkeit Ihres Repositorys verbessern.
Beachten Sie, dass der Zweck von Git darin besteht, das Teilen und Konsumieren der Entwicklung einer Codebasis zu vereinfachen und den Verlauf nicht genau so aufzuzeichnen, wie er sich entfaltet hat. (Wenn Sie nicht einverstanden sind, berücksichtigen Sie den rebase
Befehl und warum er erstellt wurde.) Die von erstellten Zusammenführungs-Commits git pull
vermitteln anderen keine nützliche Semantik. Sie sagen lediglich, dass jemand anderes zufällig in das Repository verschoben wurde, bevor Sie mit Ihren Änderungen fertig waren. Warum haben diese Zusammenführungsverpflichtungen, wenn sie für andere nicht von Bedeutung sind und gefährlich sein könnten?
Es ist möglich, git pull
eine Neubasis anstelle einer Zusammenführung zu konfigurieren , dies hat jedoch auch Probleme (wird später erläutert). Sollte stattdessen git pull
so konfiguriert werden, dass nur Schnellvorlaufzusammenführungen durchgeführt werden.
Wiedereinführung von Rebased-Out-Commits
Angenommen, jemand stößt einen Zweig zurück und drückt ihn mit Gewalt. Dies sollte im Allgemeinen nicht passieren, ist jedoch manchmal erforderlich (z. B. um eine versehentlich festgeschriebene und gepusste 50-GB-Protokolldatei zu entfernen). Durch die Zusammenführung von git pull
wird die neue Version des Upstream-Zweigs mit der alten Version zusammengeführt, die noch in Ihrem lokalen Repository vorhanden ist. Wenn Sie das Ergebnis drücken, kommen Pitchgabeln und Taschenlampen auf Sie zu.
Einige mögen argumentieren, dass das eigentliche Problem darin besteht, Aktualisierungen zu erzwingen. Ja, es ist im Allgemeinen ratsam, Kraftstöße nach Möglichkeit zu vermeiden, aber manchmal sind sie unvermeidlich. Entwickler müssen bereit sein, mit Force-Updates umzugehen, da dies manchmal vorkommt. Dies bedeutet, dass die alten Commits nicht blind über ein gewöhnliches System zusammengeführt werden git pull
.
Überraschen Sie die Änderungen im Arbeitsverzeichnis
Es gibt keine Möglichkeit vorherzusagen, wie das Arbeitsverzeichnis oder der Index aussehen wird, bis git pull
dies abgeschlossen ist. Möglicherweise gibt es Zusammenführungskonflikte, die Sie lösen müssen, bevor Sie etwas anderes tun können. Möglicherweise wird eine 50-GB-Protokolldatei in Ihr Arbeitsverzeichnis eingefügt, weil jemand sie versehentlich verschoben hat. Möglicherweise wird ein Verzeichnis, in dem Sie arbeiten, umbenannt.
git remote update -p
(oder git fetch --all -p
) ermöglicht es Ihnen, die Commits anderer Personen zu überprüfen, bevor Sie sich für eine Zusammenführung oder Neugründung entscheiden. So können Sie einen Plan erstellen, bevor Sie Maßnahmen ergreifen.
Schwierigkeiten beim Überprüfen der Commits anderer Personen
Angenommen, Sie sind gerade dabei, einige Änderungen vorzunehmen, und jemand anderes möchte, dass Sie einige Commits überprüfen, die er gerade gepusht hat. git pull
Durch die Zusammenführungs- (oder Rebase-) Operation werden das Arbeitsverzeichnis und der Index geändert. Dies bedeutet, dass Ihr Arbeitsverzeichnis und Ihr Index sauber sein müssen.
Sie könnten git stash
und dann verwenden git pull
, aber was tun Sie, wenn Sie mit der Überprüfung fertig sind? Um dorthin zurückzukehren, wo Sie waren, müssen Sie die von erstellte Zusammenführung rückgängig machen git pull
und den Stash anwenden.
git remote update -p
(oder git fetch --all -p
) ändert das Arbeitsverzeichnis oder den Index nicht, sodass die Ausführung jederzeit sicher ist - selbst wenn Sie Änderungen vorgenommen und / oder nicht bereitgestellt haben. Sie können pausieren, was Sie tun, und das Commit eines anderen überprüfen, ohne sich Gedanken über das Verstecken oder Beenden des Commits machen zu müssen, an dem Sie arbeiten. git pull
gibt Ihnen diese Flexibilität nicht.
Wiederherstellen auf einem Remote-Zweig
Ein gängiges Git-Verwendungsmuster besteht darin git pull
, die neuesten Änderungen vorzunehmen, gefolgt von a git rebase @{u}
, um das eingeführte Zusammenführungs-Commit zu beseitigen git pull
. Es ist üblich genug , dass Git einige Konfigurationsoptionen hat diese beiden Schritte zu einem einzigen Schritt zu verringern , indem sie sagen , git pull
ein Fütterungsmaterial anstelle einer Serie auszuführen (siehe branch.<branch>.rebase
, branch.autosetuprebase
und pull.rebase
Optionen).
Wenn Sie ein nicht gepushtes Zusammenführungs-Commit haben, das Sie beibehalten möchten (z. B. ein Commit master
, in das ein Push- Feature-Zweig zusammengeführt wird ), gibt es leider weder ein Rebase-Pull ( git pull
mit branch.<branch>.rebase
set to true
) noch ein Merge-Pull (das Standardverhalten git pull
), gefolgt von a Rebase wird funktionieren. Dies liegt daran, git rebase
dass Zusammenführungen ohne die --preserve-merges
Option eliminiert werden (die DAG wird linearisiert) . Der Rebase-Pull-Vorgang kann nicht so konfiguriert werden, dass Zusammenführungen beibehalten werden, und ein Merge-Pull gefolgt von a git rebase -p @{u}
beseitigt die durch das Merge-Pull verursachte Zusammenführung nicht. Update: Git v1.8.5 hinzugefügt git pull --rebase=preserve
und git config pull.rebase preserve
. Diese Ursache git pull
zu tun , git rebase --preserve-merges
nachdem die Upstream - Commits holen. (Danke an Funkaster für das Heads-up!)
Bereinigte Zweige bereinigen
git pull
Bereinigt keine Remote-Tracking-Zweige, die Zweigen entsprechen, die aus dem Remote-Repository gelöscht wurden. Wenn beispielsweise jemand einen Zweig foo
aus dem Remote-Repo löscht , wird dies weiterhin angezeigt origin/foo
.
Dies führt dazu, dass Benutzer versehentlich getötete Zweige wiederbeleben, weil sie glauben, noch aktiv zu sein.
Eine bessere Alternative: Verwenden Sie git up
anstelle vongit pull
Stattdessen git pull
empfehle ich, den folgenden git up
Alias zu erstellen und zu verwenden :
git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'
Dieser Alias lädt die neuesten Commits von allen Upstream-Zweigen herunter (Bereinigen der toten Zweige) und versucht, den lokalen Zweig schnell auf den neuesten Commit im Upstream-Zweig vorzuspulen. Wenn dies erfolgreich war, gab es keine lokalen Commits, sodass kein Risiko für Zusammenführungskonflikte bestand. Der schnelle Vorlauf schlägt fehl, wenn lokale (nicht gepusste) Commits vorhanden sind, sodass Sie die Möglichkeit haben, die Upstream-Commits zu überprüfen, bevor Sie Maßnahmen ergreifen.
Dadurch wird Ihr Arbeitsverzeichnis immer noch auf unvorhersehbare Weise geändert, jedoch nur, wenn Sie keine lokalen Änderungen vorgenommen haben. Im Gegensatz zu git pull
, git up
werden Sie nie auf eine Aufforderung fallen Sie einen Merge - Konflikt zu beheben erwarten.
Andere Option: git pull --ff-only --all -p
Das Folgende ist eine Alternative zum obigen git up
Alias:
git config --global alias.up 'pull --ff-only --all -p'
Diese Version von git up
hat das gleiche Verhalten wie der vorherige git up
Alias, außer:
- Die Fehlermeldung ist etwas kryptischer, wenn Ihr lokaler Zweig nicht mit einem Upstream-Zweig konfiguriert ist
- Es basiert auf einer undokumentierten Funktion (dem
-p
Argument, an das übergeben wird fetch
), die sich in zukünftigen Versionen von Git ändern kann
Wenn Sie Git 2.0 oder neuer ausführen
Mit Git 2.0 und neuer können Sie konfigurieren git pull
, dass standardmäßig nur Schnellvorlaufzusammenführungen durchgeführt werden:
git config --global pull.ff only
Dies führt git pull
dazu git pull --ff-only
, dass es sich so verhält, aber es werden immer noch nicht alle Upstream-Commits abgerufen oder alte origin/*
Zweige bereinigt, daher bevorzuge ich es immer noch git up
.