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, ...).