Git --distributed-even-if-your-workflow-isnt
Chapters ▾

9.5 Git Internas - Die Refspec

Die Refspec

In diesem Buch haben wir bisher einfache Mappings von externen Branches auf lokale Referenzen verwendet. Sie können aber auch durchaus komplex sein. Nehmen wir an, du hast ein externes 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 Repositories (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 Pattern 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, daß Git austomatisch alle Referenzen unter refs/heads/ vom Server holt und sie lokal nach refs/remotes/origin speichert. D.h., wenn es auf dem Server einen master Branch 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 statt dessen willst, daß Git jeweils nur den master Branch 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 Default Refspec Wert und du kannst ihn auf der Kommandozeile jederzeit überschreiben. Z.B. um nur master branch 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. Z.B.:

$ 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

I diesem Fall wurde ein Pull zurückgewiesen (xxx ist das nicht nur ein fetch? xxx), 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 master und experiment Branches 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 Patterns 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 master Branch 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 master Branch 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, daß 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 origin Server 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 <ziel> Teil wegläßt, dann heißt das im obigen Beispiel, daß man den topic Branch auf dem origin Server auf "nichts" setzt, d.h. also löscht.