Learn Git

Die Refspec

In diesem Buch haben wir bisher einfache Zuweisungen von externen Branches auf lokale Referenzen verwendet. Sie können aber auch durchaus komplex sein. Nehmen wir an, Du hast ein Remote-Repository wie folgt definiert:

$ git remote add origin git@github.com:schacon/simplegit-progit.git

Das fügt eine Sektion in Deine .git/config-Datei hinzu, die Deinen lokalen Namen des externen Repositorys (origin), dessen URL und die Refspec spezifiziert, mit der neue Daten heruntergeladen werden.

[remote "origin"]
       url = git@github.com:schacon/simplegit-progit.git
       fetch = +refs/heads/*:refs/remotes/origin/*

Das Format der Refspec besteht aus einem optionalen + gefolgt von <Quelle>:<Ziel>, wobei <Quelle> ein Muster für Referenzen auf der Remote-Seite ist, und <Ziel> angibt, wohin diese Referenzen lokal geschrieben werden. Das + weist Git an, die Referenz zu mergen, wenn sie nicht mit einem Fast-forward aktualisiert werden kann.

Der Standard, der von git remote add automatisch eingerichtet wird, besteht darin, dass Git automatisch alle Referenzen unter refs/heads/ vom Server holt und sie lokal nach refs/remotes/origin speichert. D.h., wenn es auf dem Server einen Branch master gibt, kannst Du auf das Log dieses Branches wie folgt zugreifen:

$ git log origin/master
$ git log remotes/origin/master
$ git log refs/remotes/origin/master

Diese Varianten sind allesamt äquivalent, weil Git sie jeweils zu refs/remotes/origin/master vervollständigt.

Wenn Du stattdessen willst, dass Git jeweils nur den Branch master herunterlädt und andere Branches auf dem Server ignoriert, kannst Du die fetch-Zeile wie folgt ändern:

fetch = +refs/heads/master:refs/remotes/origin/master

Dies ist allerdings lediglich der Standardwert der Refspec und Du kannst ihn auf der Kommandozeile jederzeit überschreiben. Um zum Beispiel nur den Branch master vom Server lokal als origin/mymaster zu speichern, kannst Du Folgendes ausführen:

$ git fetch origin master:refs/remotes/origin/mymaster

Du kannst auch mehrere Refspecs gleichzeitig spezifizieren. Um mehrere Branches zu holen kannst du folgenden Befehl in die Kommandozeile eingeben:

$ git fetch origin master:refs/remotes/origin/mymaster \
   topic:refs/remotes/origin/topic
From git@github.com:schacon/simplegit
 ! [rejected]        master     -> origin/mymaster  (non fast forward)
 * [new branch]      topic      -> origin/topic

In diesem Fall wurde ein Pull zurückgewiesen, weil der Branch nicht mit einem simplen Fast-forward aktualisiert werden konnte. Du kannst einen Merge erzwingen, indem Du der Refspec ein + voranstellst.

Du kannst außerdem natürlich auch mehrere Refspecs in Deiner Konfiguration spezifizieren. Wenn Du z.B. immer die Branches master und experiment holen willst, fügst Du die folgenden Zeilen hinzu:

[remote "origin"]
       url = git@github.com:schacon/simplegit-progit.git
       fetch = +refs/heads/master:refs/remotes/origin/master
       fetch = +refs/heads/experiment:refs/remotes/origin/experiment

Du kannst keine partiellen Glob-Muster verwenden, d.h. Folgendes wäre ungültig:

fetch = +refs/heads/qa*:refs/remotes/origin/qa*

Allerdings kannst Du Namensräume verwenden, um etwas Ähnliches zu erreichen. Nehmen wir an, Du hast ein QA-Team, das regelmäßig verschiedene Branches pusht, und Du willst nun den Branch master und sämtliche Branches des QA-Teams, aber keine anderen Branches haben. Dann kannst Du eine Config-Sektion wie die folgende verwenden:

[remote "origin"]
       url = git@github.com:schacon/simplegit-progit.git
       fetch = +refs/heads/master:refs/remotes/origin/master
       fetch = +refs/heads/qa/*:refs/remotes/origin/qa/*

In einem großen Team mit einem komplexen Workflow, in dem ein QA-Team, Entwickler und ein Integrations-Team jeweils eigene Branches pushen, kann man auf diese Weise Branches einfach in Namensräume einteilen.

Refspecs pushen

Wie aber legt das QA-Team die Branches im qa/ Namensraum ab? Das geht, indem man mit einer Refspec pusht.

Wenn das QA-Team seinen Branch master in einem externen Repository als qa/master speichern will, kann es das wie folgt tun:

$ git push origin master:refs/heads/qa/master

Um Git so zu konfigurieren, dass diese Refspec jedes Mal automatisch für git push origin verwendet wird, kann man den push Wert in der Config-Datei setzen:

[remote "origin"]
       url = git@github.com:schacon/simplegit-progit.git
       fetch = +refs/heads/*:refs/remotes/origin/*
       push = refs/heads/master:refs/heads/qa/master

Auf diese Weise wird git push origin den lokalen Branch master als qa/master auf dem Server origin speichern.

Referenzen löschen

Man kann Refspecs außerdem verwenden, um Referenzen aus einem externen Repository zu löschen:

$ git push origin :topic

Das Refspec Format ist <Quelle>:<Ziel>. Wenn man den Teil <Quelle> weglässt, dann heißt das im obigen Beispiel, dass man den Branch topic auf dem Server origin auf „nichts“ setzt, d.h. also löscht.