Mit dem Befehl git fetch werden Commits, Dateien und Verweise aus einem Remote-Repository in dein lokales Repository heruntergeladen. Das Abrufen ist dann interessant, wenn du wissen willst, woran alle anderen arbeiten. Der Befehl ähnelt svn update: Du kannst damit die Fortschritte im zentralen Verlauf einsehen. Allerdings musst du die Änderungen nicht unbedingt in dein Repository mergen. Git isoliert abgerufene Inhalte von den vorhandenen lokalen Inhalten, sodass sie absolut keine Auswirkungen auf deine lokale Entwicklungsarbeit haben. Die abgerufenen Inhalte müssen mit dem Befehl git checkout explizit ausgecheckt werden. Daher ist das Abrufen eine gute Möglichkeit, Commits sicher zu reviewen, bevor du sie in dein lokales Repository integrierst.

Wenn du Inhalte aus einem Remote-Repository herunterladen möchtest, stehen dir die Befehle git pull und git fetch zur Verfügung. Dabei ist git fetch sozusagen die "sichere" Variante: Damit werden die Remote-Inhalte heruntergeladen, aber es erfolgt keine Aktualisierung des Arbeitsstatus deines lokalen Repositorys, sodass deine aktuelle Arbeit davon unberührt bleibt. Dagegen ist git pull der "aggressivere" Befehl: Damit werden die Remote-Inhalte für den aktiven lokalen Branch heruntergeladen, unmittelbar gefolgt von der Ausführung des Befehls git merge zum Erstellen eines Merge-Commits für die neuen Remote-Inhalte. Wenn noch ausstehende Änderungen vorhanden sind, entstehen Konflikte, und der Ablauf zum Lösen von Merge-Konflikten wird gestartet.

So funktioniert "git fetch" bei Remote-Branches

Um die Funktionsweise von git fetch besser zu verstehen, sehen wir uns zunächst an, wie Commits in Git organisiert und gespeichert werden. Hinter den Kulissen werden alle lokalen und Remote-Commits von Git im Verzeichnis ./.git/objects gespeichert. Mithilfe von Branch-Verweisen werden Remote- und lokale Branch-Commits streng voneinander getrennt. Die Verweise für lokale Branches werden im Verzeichnis ./.git/refs/heads/ gespeichert. Wenn du den Befehl git branch ausführst, wird eine Liste der lokalen Branch-Verweise ausgegeben. Unten siehst du ein Beispiel für die Ausgabe von git branch mit Demo-Branch-Namen.

git branch
master
feature1
debug2

Eine Abfrage der Inhalte des Verzeichnisses /.git/refs/heads/ hätte eine ähnliche Ausgabe.

ls ./.git/refs/heads/
master
feature1
debug2

Im Grunde genommen sind Remote-Branches dasselbe wie lokale Branches. Der einzige Unterschied: Sie sind Commits aus dem Repository eines anderen Benutzers zugeordnet. Bei Remote-Branches wird als Präfix das Remote-Repository angegeben, zu dem sie gehören. So ist eine Verwechslung mit lokalen Branches ausgeschlossen. Ebenso wie bei lokalen Branches gibt es in Git Verweise auf Remote-Branches. Diese Remote-Branch-Verweise sind im Verzeichnis ./.git/refs/remotes/ zu finden. Der Codeausschnitt unten beispielsweise zeigt Branches, die beim Abrufen eines Remote-Repositorys mit dem Namen "remote-repo" zurückgegeben würden:

git branch -r
# origin/master
# origin/feature1
# origin/debug2
# remote-repo/master
# remote-repo/other-feature

In dieser Ausgabe sind dieselben lokalen Branches enthalten wie zuvor, nun aber mit dem Präfix origin/. Die Remote-Branches sind jetzt mit dem Präfix remote-repo gekennzeichnet. Genau wie lokale Branches kannst du auch Remote-Branches auschecken. Dadurch wechselst du jedoch in einen Zustand mit losgelöstem HEAD. (Gleiches passiert, wenn du einen alten Commit auscheckst.) Du kannst dir Branches dieses Typs wie schreibgeschützte Branches vorstellen. Wenn du deine Remote-Branches abrufen möchtest, übergib einfach das Flag -r an den Befehl git branch.

Genauer ansehen kannst du dir Remote-Branches mit den regulären Befehlen git checkout und git log. Möchtest du die Änderungen in einem Remote-Branch übernehmen, kannst du den Branch mit dem normalen Befehl git merge mit einem deiner lokalen Branches mergen. Anders als in SVN ist die Synchronisierung eines lokalen Repositorys mit einem Remote-Repository also ein zweistufiger Prozess: Zuerst musst du einen Fetch durchführen, anschließend einen Merge. Abkürzen kannst du das Ganze über den Befehl git pull.

"git fetch" – Befehle und Optionen

git fetch <remote>

Ruft alle Branches vom Repository ab. Dabei werden auch alle erforderlichen Commits und Dateien des anderen Repositorys heruntergeladen.

git fetch <remote> <branch>

Wie der Befehl oben, aber nur der angegebene Branch wird abgerufen

git fetch --all

Ein wichtiger Befehl, mit dem alle registrierten Remote-Repositorys und deren Branches abgerufen werden:

git fetch --dry-run

Mit der Option --dry-run wird die Ausführung des Befehls demonstriert. Die Ausgabe zeigt Beispiele für die Aktionen, die beim Abrufen ausgeführt werden. Diese werden jedoch nicht tatsächlich angewendet.

"git fetch" – Beispiele

"git fetch" bei Remote-Branches

Das nächste Beispiel zeigt, wie du einen Remote-Branch abrufen und deinen lokalen Arbeitsstatus mit den Remote-Inhalten aktualisieren kannst. Für das Beispiel gehen wir davon aus, dass es ein zentrales Repository als Ursprung gibt, aus dem das lokale Repository mit dem Befehl git clone geklont wurde. Außerdem treffen wir die Annahme, dass ein weiteres Remote-Repository namens "coworkers_repo" vorhanden ist, das einen feature_branch enthält, den wir konfigurieren und abrufen möchten. Unter diesen angenommenen Voraussetzungen kommen wir nun zu unserem Beispiel.

Zunächst müssen wir das Remote-Repository konfigurieren. Dazu verwenden wir den Befehl git remote.

git remote add coworkers_repo git@bitbucket.org:coworker/coworkers_repo.git

Hier haben wir mithilfe der Repository-URL einen Verweis auf das coworkers-Repository erstellt. Wir übergeben diesen Remote-Namen nun an git fetch, um die Inhalte herunterzuladen.

git fetch coworkers feature_branch
fetching coworkers/feature_branch

Jetzt liegen uns die Inhalte von coworkers/feature_branch lokal vor, und wir müssen sie in unsere lokale Arbeitskopie integrieren. Im ersten Schritt checken wir den neu heruntergeladenen Remote-Branch mit dem Befehl git checkout aus.

git checkout coworkers/feature_branch
Note: checking out coworkers/feature_branch'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

git checkout -b <new-branch-name>

Die Ausgabe dieses Checkout-Vorgangs zeigt uns, dass wir uns in einem Zustand mit losgelöstem HEAD befinden. Dies entspricht unserer Erwartung und bedeutet, dass der HEAD-Verweis auf einen Verweis zeigt, der nicht mit dem lokalen Verlauf synchron ist. Da HEAD auf coworkers/feature_branch verweist, können wir daraus einen neuen lokalen Branch erstellen. Die Ausgabe mit losgelöstem HEAD zeigt uns, wie wir dies mit dem Befehl git checkout erreichen können:

git checkout -b local_feature_branch

Hier haben wir einen neuen lokalen Branch mit der Bezeichnung "local_feature_branch" erstellt. Auf diese Weise wird HEAD so aktualisiert, dass er auf die aktuellen Remote-Inhalte verweist. An diesem Punkt können wir mit der Entwicklung fortfahren.

Synchronisierung des Ursprungs mit "git fetch"

Im folgenden Beispiel spielen wir den typischen Workflow zur Synchronisierung deines lokalen Repositorys mit dem Master-Branch des zentralen Repositorys durch.

git fetch origin

So können die heruntergeladenen Branches angezeigt werden:

a1e8fb5..45e66a4 master -> origin/master
a1e8fb5..9e8ab1c develop -> origin/develop
* [new branch] some-feature -> origin/some-feature

Die Commits aus diesen neuen Remote-Branches sind im Schaubild als Quadrate statt als Kreise dargestellt. Wie du siehst, hast du über git fetch Zugriff auf die gesamte Branch-Struktur eines anderen Repositorys.

Wenn du herausfinden möchtest, welche Commits zum Upstream-Master hinzugefügt wurden, kannst du git log mit dem Filter origin/master ausführen:

git log --oneline master..origin/master

Führe die folgenden Befehle aus, um die Änderungen zu genehmigen und in deinen lokalen Master-Branch zu mergen:

git checkout master
git log origin/master

Jetzt führst du git merge origin/master aus:

git merge origin/master

Die origin/master- und master-Branches verweisen nun auf denselben Commit und die Synchronisierung mit Upstream-Entwicklungen ist abgeschlossen.

"git fetch" – Zusammenfassung

Zusammenfassend können wir festhalten, dass git fetch ein wichtiger Befehl ist, der zum Herunterladen von Inhalten aus einem Remote-Repository verwendet wird. git fetch wird in Verbindung mit git remote, git branch, git checkout und git reset ausgeführt, um ein lokales Repository mit dem Status eines Remote-Repositorys zu aktualisieren. Der Befehl git fetch ist ein entscheidender Bestandteil von Git-Workflows zur Zusammenarbeit. git fetch verhält sich ähnlich wie git pull, allerdings kann git fetch als die sicherere Version betrachtet werden, bei der nichts verloren geht.