Git: Was ist der Unterschied zwischen pull und fetch?
git pull ist git fetch gefolgt von einem Merge. Dieser eine Satz ist die
ganze Antwort — und er lässt sich leichter glauben, wenn man einmal gesehen hat,
was jede Hälfte mit dem Repository macht.
fetch bewegt einen Zeiger und sonst nichts
before fetch: local main ea0365c origin/main ea0365c
after fetch: local main ea0365c origin/main a087a00 <- moved
file.txt one| <- unchanged
git fetch lädt die neuen Commits
herunter und aktualisiert origin/main, den Remote-Tracking-Ref. Dein Branch
bewegt sich nicht. Deine Dateien ändern sich nicht. Danach weiß dein
Repository von Arbeit, die es noch nicht übernommen hat.
Das ist der ganze Unterschied. origin/main ist die Notiz von git, wo der
Remote stand; main ist, wo du stehst.
Und genau deshalb kannst du erst schauen
user@pc:~$ git log main..origin/main
a087a00 colleague commit
user@pc:~$ git diff --stat main origin/main
file.txt | 1 +
1 file changed, 1 insertion(+)
Der Bereich main..origin/main heißt “Commits auf dem Remote, die ich nicht
habe”. Das ist das eigentliche Argument für fetch statt pull: In einem fremden
Repository, oder vor einem Release, kannst du lesen was angekommen ist, bevor es
in deinem Arbeitsverzeichnis landet.
pull macht die zweite Hälfte gleich mit
user@pc:~$ git pull
after pull: local main a087a00 file.txt one|two|
Dasselbe Ergebnis wie fetch plus merge. Bei einem Branch, der nicht
divergiert ist, ist das ein Fast-Forward — dein Branch-Zeiger rückt einfach vor
und es entsteht kein Merge-Commit.
Wenn sich beide Seiten bewegt haben
Hast du lokal committet und der Remote hat sich bewegt, gibt es nichts vorzurücken und git muss die beiden Historien zusammenführen:
--no-rebase: --rebase:
* 17ec289 Merge... * fb288d3 my local commit
|\ * a087a00 colleague commit
| * a087a00 colleague * ea0365c first commit
* | e1f425a my local
|/
Standardmäßig wird gemergt, mit dem Merge-Commit und der Gabelung im Graphen.
--rebase spielt deinen Commit stattdessen obenauf neu ein und ergibt eine
gerade Linie.
Sieh dir den Hash in der Rebase-Spalte an: Aus e1f425a wurde fb288d3. Ein
Rebase verschiebt deinen Commit nicht, es erzeugt einen neuen mit denselben
Änderungen. Für Commits, die nur du hast, ist das in Ordnung — sobald sie geteilt
sind, gilt die übliche Warnung.
Was immer dir lieber ist: Leg es ausdrücklich fest, damit es nicht vom Rechner abhängt.
user@pc:~$ git config --global pull.rebase true # oder false
Neuere git-Versionen warnen, wenn du bei divergierter Historie pullst ohne dich entschieden zu haben. Darauf zu reagieren ist besser, als es wegzuklicken.
fetch kann dich nicht auf halbem Weg stehen lassen
with an uncommitted edit:
fetch: ok, origin/main now a087a00
pull : error: Your local changes ... Aborting
fetch schreibt nur nach .git und funktioniert deshalb unabhängig vom Zustand
deines Arbeitsverzeichnisses. pull muss mergen, und ein Merge kann sich
weigern — oder, schlimmer, mittendrin stehenbleiben und Konfliktmarkierungen in
deinen Dateien hinterlassen.
Deshalb ist “oft fetchen, bewusst pullen” eine vernünftige Gewohnheit.
git fetch ist einer der wenigen git-Befehle, die dein Repository in keinen
Zustand bringen können, aus dem du wieder herausfinden musst.
Hinweis zu Netcup (Werbung)
Der deutsche Hoster Netcup bietet unter anderem günstige und zugleich leistungsstarke Webhosting Pakete, KVM-basierte Root Server und dezidierte Server an. Mit unseren Gutscheincodes kannst du noch mehr Geld sparen (6€ bei deiner ersten Bestellung, 30% Rabatt auf alle KVM-basierten Root Server, ...).