Startseite

Vorwort
1. An wen richtet sich dieses Buch?
2. Wie ist das Buch zu lesen?
3. Konventionen
4. Installation und „das Git-Repository“
5. Dokumentation und Hilfe
6. Downloads und Kontakt
7. Danksagungen
8. Vorwort zur 2. Auflage
9. Vorwort zur CreativeCommons-Ausgabe
1. Einführung und erste Schritte
1.1. Grundbegriffe
1.2. Erste Schritte mit Git
1.3. Git konfigurieren
2. Grundlagen
2.1. Git-Kommandos
2.2. Das Objektmodell
3. Praktische Versionsverwaltung
3.1. Referenzen: Branches und Tags
3.2. Versionen wiederherstellen
3.3. Branches zusammenführen: Merges
3.4. Merge-Konflikte lösen
3.5. Einzelne Commits übernehmen: Cherry-Pick
3.6. Visualisierung von Repositories
3.7. Reflog
4. Fortgeschrittene Konzepte
4.1. Commits verschieben – Rebase
4.2. Die Geschichte umschreiben – Interaktives Rebase
4.3. Wer hat diese Änderungen gemacht? – git blame
4.4. Dateien ignorieren
4.5. Veränderungen auslagern – git stash
4.6. Commits annotieren – git notes
4.7. Mehrere Root-Commits
4.8. Regressionen finden – git bisect
5. Verteiltes Git
5.1. Wie funktioniert verteilte Versionsverwaltung?
5.2. Repositories klonen
5.3. Commits herunterladen
5.4. Commits hochladen: git push
5.5. Remotes untersuchen
5.6. Verteilter Workflow mit mehreren Remotes
5.7. Remotes verwalten
5.8. Tags austauschen
5.9. Patches per E-Mail
5.10. Ein verteilter, hierarchischer Workflow
5.11. Unterprojekte verwalten
6. Workflows
6.1. Anwender
6.2. Ein Branching-Modell
6.3. Releases-Management
7. Git auf dem Server
7.1. Einen Git-Server hosten
7.2. Gitolite: Git einfach hosten
7.3. Git-Daemon: Anonymer, lesender Zugriff
7.4. Gitweb: Das integrierte Web-Frontend
7.5. CGit – CGI for Git
8. Git automatisieren
8.1. Git-Attribute – Dateien gesondert behandeln
8.2. Hooks
8.3. Eigene Git-Kommandos schreiben
8.4. Versionsgeschichte umschreiben
9. Zusammenspiel mit anderen Versionsverwaltungssystemen
9.1. Subversion
9.2. Eigene Importer
10. Shell-Integration
10.1. Git und die Bash
10.2. Git und die Z-Shell
11. Github
A. Installation
A.1. Linux
A.2. Mac OS X
A.3. Windows
B. Struktur eines Repositorys
B.1. Aufräumen
B.2. Performance

Kapitel 6. Workflows

Mit Workflows (dt. Arbeitsabläufe) werden in der Software-Entwicklung in der Regel Strategien bezeichnet, die Arbeitsabläufe im Team definieren (z.B. die Agile Softwareentwicklung). Wir können uns bei diesem Thema allgemein hier nur auf Literaturhinweise beschränken.[88]

In Git kann man „Workflows“ unter zwei Aspekten sehen: Abläufe (Kommandosequenzen), die den einzelnen Nutzer betreffen, sowie projektbezogene Arbeitsabläufe (z.B. Release-Management). Auf beide Aspekte wird im Folgenden eingegangen.

6.1. Anwender

Nachfolgend finden Sie eine Auflistung genereller Entwicklungsstrategien (ohne bestimmte Reihenfolge):

Machen Sie möglichst kleine, eigenständige Commits
Unterteilen Sie Ihre Arbeit in kleine, logische Schritte und tätigen Sie für jeden Schritt einen Commit. Die Commits sollten unabhängig von zukünftigen Commits sein und möglichst alle Tests (sofern vorhanden) bestehen. Das erleichtert es Ihren Kollegen bzw. den Maintainern, nachzuvollziehen, was Sie gemacht haben. Außerdem steigert es den Wirkungsgrad von Kommandos, die die Geschichte untersuchen, bspw. git bisect und git blame. Haben Sie keine Angst, zu kleine Commits zu tätigen. Es ist im Nachhinein einfacher, mehrere kleine Commits mit git rebase --interactive zusammenzufassen als einen großen in mehrere kleine zu teilen.
Entwickeln Sie in Topic-Branches

Branching geht in Git leicht, schnell und intuitiv vonstatten. Anschließendes Mergen funktioniert problemlos, auch wiederholt. Nutzen Sie diese Flexibilität von Git: Entwickeln Sie nicht direkt in master, sondern jedes Feature in seinem eigenen Branch, genannt Topic-Branch.

Dadurch bieten sich einige Vorteile: Sie können Features unabhängig voneinander entwickeln; Sie erhalten einen wohldefinierten Zeitpunkt der Integration (Merge); Sie können die Entwicklung per Rebase „stromlinienförmig“ und übersichtlich gestalten, bevor Sie sie veröffentlichen; Sie erleichtern es anderen Entwicklern, ein neues Feature isoliert zu testen.

Verwenden Sie Namespaces
Sie können durch /-Zeichen im Branch-Namen verschiedene Klassen von Branches kreieren. In einem zentralen Repository können Sie sich durch Ihre Initialen einen eigenen Namensraum schaffen (z.B. jp/refactor-base64) oder Ihre Features je nach Stabilität unter experimental/ oder pu/ (s.u.) ablegen.
Rebase early, Rebase often

Wenn Sie auf Topic-Branches häufig mit Rebase arbeiten, erzeugen Sie eine deutlich lesbarere Versionsgeschichte. Das ist für Sie und andere Entwickler praktisch und hilft, den eigentlichen Programmiervorgang in logische Einheiten aufzuteilen.

Verschmelzen Sie Kleinstcommits, wenn sie zusammengehören. Nehmen Sie sich bei Bedarf die Zeit, große Commits noch einmal sinnvoll aufzuteilen (siehe Abschnitt 4.2.2, „Commits beliebig editieren“).

Verwenden Sie allerdings Rebase nur für eigene Commits: Verändern Sie keinesfalls bereits veröffentlichte Commits oder die Commits anderer Entwickler.

Unterscheiden Sie bewusst zwischen FF- und regulären Merges
Integrieren Sie Änderungen aus dem Upstream immer per Fast-Forward (Sie spulen die lokale Kopie der Branches einfach vor). Integrieren Sie im Gegensatz dazu neue Features durch reguläre Merges. Hilfreich für die Unterscheidung sind auch die in Abschnitt 3.3.2, „Fast-Forward-Merges: Einen Branch vorspulen“ vorgestellten Aliase.
Beachten Sie die Merge-Richtung

Das Kommando git merge zieht einen oder mehrere Branches in den aktuellen hinein. Beachten Sie daher immer die Richtung, in der Sie einen Merge durchführen: Integrieren Sie Topic-Branches in die Mainline (den Branch, auf dem Sie das stabile Release vorbereiten), nicht umgekehrt.[89] Auf diese Weise können Sie auch im Nachhinein noch die Geschichte eines Features von der Mainline isolieren (git log topic listet nur die relevanten Commits auf).

Criss-Cross-Merges (überkreuzte Merges) sind nach Möglichkeit zu vermeiden: Sie entstehen, wenn Sie einen Branch A in einen Branch B und eine ältere Version von B in A integrieren.

Testen Sie die Verträglichkeit von Features per Throw-Away-Integration
Erstellen Sie einen neuen (Wegwerf-)Branch und mergen Sie die Features, deren Kompatibilität Sie testen wollen. Lassen Sie die Testsuite laufen oder testen Sie das Zusammenspiel der neuen Komponenten auf andere Weise. Den Branch können Sie anschließend löschen und die Features weiter getrennt voneinander entwickeln. Solche Throw-Away-Branches werden in der Regel nicht veröffentlicht.

Gewisse Arbeitsschritte tauchen wieder und wieder auf. Im Folgenden ein paar allgemeine Lösungsstrategien:

Einen kleinen Bug fixen
Wenn Sie einen kleinen Bug bemerken, den Sie schnell korrigieren wollen, können Sie das auf zwei Arten tun: vorliegende Änderungen per Stash in den Hintergrund schieben (siehe Abschnitt 4.5, „Veränderungen auslagern – git stash“), den entsprechenden Branch auschecken, den Bug beheben, wieder den Branch wechseln und den Stash anwenden. Die andere Möglichkeit besteht darin, auf dem Branch, auf dem Sie gerade arbeiten, den Fehler zu beheben und nachträglich den/die entsprechenden Commit(s) per Cherry-Pick oder Rebase-Onto (siehe Abschnitt 3.5, „Einzelne Commits übernehmen: Cherry-Pick“ bzw. Abschnitt 4.1.8, „Rebase einschränken mit --onto“) in den dafür vorgesehenen Bugfix- oder Topic-Branch zu übernehmen.
Einen Commit korrigieren

Mit git commit --amend können Sie den letzten Commit anpassen. Die Option --no-edit bewirkt, dass die Beschreibung beibehalten und nicht erneut zur Bearbeitung angeboten wird.

Um tiefer liegende Commits zu korrigieren, verwenden Sie entweder interaktives Rebase und das edit-Keyword (siehe Abschnitt 4.2.2, „Commits beliebig editieren“) oder Sie erstellen für jede Korrektur einen kleinen Commit, ordnen diese schließlich im interaktiven Rebase entsprechend an und versehen sie mit der Aktion fixup, um den ursprünglichen Commit zu korrigieren.

Welche Branches sind noch nicht in master?
Verwenden Sie git branch -vv --no-merged, um herauszufinden, welche Branches noch nicht in den aktuellen Branch integriert sind.
Mehrere Änderungen aus unterschiedlichen Quellen zusammenfassen
Nutzen Sie den Index, um mehrere Änderungen zusammenzufassen, z.B. Änderungen, die einander ergänzen, aber in verschiedenen Branches oder als Patches vorliegen. Die Kommandos git apply, git cherry-pick --no-commit sowie git merge --squash wenden die entsprechenden Änderungen nur auf den Working Tree bzw. Index an, ohne einen Commit zu erzeugen.

6.2. Ein Branching-Modell

Der folgende Abschnitt stellt ein Branching-Modell vor, das an das in der Man-Page gitworkflows(7) beschriebene Modell angelehnt ist. Das Branching-Modell bestimmt, welcher Branch welche Funktionen erfüllt, wann und wie Commits aus einem Branch übernommen werden, welche Commits als Releases getaggt werden sollen usw. Es ist flexibel, skaliert gut und kann bei Bedarf erweitert werden (s.u.).

In seiner Grundform besteht das Modell aus vier Branches: maint, master, next, und pu (Proposed Updates). Der master-Branch dient vor allem der Vorbereitung des nächsten Releases und zum Sammeln trivialer Änderungen. pu-Branch(es) dienen der Feature-Entwicklung (Topic-Branches). In dem Branch next werden halbwegs stabile neue Features gesammelt, im Verbund auf Kompatibilität, Stabilität und Korrektheit getestet und bei Bedarf verbessert. Auf dem maint-Branch werden kritische Bug-Fixes für vorangegangene Versionen gesammelt und als Maintenance-Releases veröffentlicht.

Prinzipiell werden Commits immer durch einen Merge in einen anderen Branch integriert (in Abbildung 6.1, „Branch-Modell gemäß gitworkflows (7) durch Pfeile angedeutet). Im Gegensatz zum Cherry-Picking werden dabei Commits nicht gedoppelt, und Sie können einem Branch leicht ansehen, ob er einen bestimmten Commit schon enthält oder nicht.

Das folgende Diagramm ist eine schematische Darstellung des zehn Punkte umfassenden Workflows, der unten detailliert erläutert wird.

Abbildung 6.1. Branch-Modell gemäß gitworkflows (7)

bilder_ebook/branch-model.png

  1. Neue Topic-Branches entstehen von wohldefinierten Punkten, z.B. getaggten Releases, auf dem master.

    $ git checkout -b pu/cmdline-refactor v0.1
  2. Hinreichend stabile Features werden aus ihrem jeweiligen pu-Branch nach next übernommen (Feature Graduation).

    $ git checkout next
    $ git merge pu/cmdline-refactor
  3. Releasevorbereitung: Wenn sich genügend neue Features in next (featuregetriebene Entwicklung) angesammelt haben, wird next nach master gemergt und ggf. ein Release-Candidate-Tag (RC-Tag) erzeugt (Suffix -rc<n>).

    $ git checkout master
    $ git merge next
    $ git tag -a v0.2-rc1
  4. Von nun an werden nur noch sogenannte Release-Critical Bugs (RC-Bugs) direkt im master korrigiert. Es handelt sich hierbei um „Show-Stopper“, also Bugs, die die Funktionalität der Software maßgeblich einschränken oder neue Features unbenutzbar machen. Gegebenenfalls können Sie Merges von problematischen Branches wieder rückgängig machen (siehe Abschnitt 3.2.2, „Commits rückgängig machen“).

    Was während der Release-Phase mit next passiert, hängt von der Größe des Projekts ab. Sind alle Entwickler damit beschäftigt, die RC-Bugs zu beheben, so bietet sich ein Entwicklungsstopp für next an. Bei größeren Projekten, wo während der Release-Phase schon die Entwicklung für das übernächste Release vorangetrieben wird, kann next weiterhin als Integrations-Branch für neue Features dienen.

  5. Sind alle RC-Bugs getilgt, wird der master als Release getaggt und ggf. als Quellcode-Archiv, Distributions-Paket usw. veröffentlicht. Außerdem wird master nach next gemergt, um alle Fixes für RC-Bugs zu übertragen. Wurden in der Zwischenzeit keine weiteren Commits auf next getätigt, so ist dies ein Fast-Forward-Merge. Nun können auch wieder neue Topic-Branches aufgemacht werden, die auf dem neuen Release basieren.

    $ git tag -a v0.2
    $ git checkout next
    $ git merge master
  6. Feature-Branches, die es nicht ins Release geschafft haben, können nun entweder in den next-Branch gemergt werden, oder aber, falls sie noch nicht fertig sind, per Rebase auf eine neue, wohldefinierte Basis aufgebaut werden.

    $ git checkout pu/numeric-integration
    $ git rebase next
  7. Um Feature-Entwicklung sauber von Bug-Fixes und Maintenance („Instandhaltung“) zu trennen, werden Bug-Fixes, die eine vorangegangene Version betreffen, im Branch maint getätigt. Dieser Maintenance-Branch zweigt, wie die Feature-Branches auch, an wohldefinierten Stellen von master ab.
  8. Haben sich genügend Bug-Fixes angesammelt oder wurde ein kritischer Bug behoben, z.B. ein Security-Bug, wird der aktuelle Commit auf dem maint-Branch als Maintenance-Release getaggt und kann über die gewohnten Kanäle publiziert werden.

    $ git checkout maint
    $ git tag -a v0.1.1

    Manchmal kommt es vor, dass Bug-Fixes, die auf master gemacht wurden, auch in maint gebraucht werden. In diesem Fall ist es in Ordnung, diese per git cherry-pick dorthin zu übertragen. Das sollte aber eher die Ausnahme als die Regel sein.

  9. Damit Bug-Fixes auch künftig verfügbar sind, wird der maint-Branch nach einem Maintenance-Release nach master gemergt.

    $ git checkout master
    $ git merge maint

    Sind die Bug-Fixes sehr dringend, können sie mit git cherry-pick in den entsprechenden Branch (next oder pu/*) übertragen werden. Wie bei einem git cherry-pick nach maint auch, sollte dies nur selten passieren.

  10. Bei einem neuen Release wird der maint-Branch per Fast-Forward auf den Stand von master gebracht, so dass maint nun auch alle Commits enthält, die das neue Release ausmachen. Ist hier kein Fast-Forward möglich, ist das ein Anzeichen dafür, dass sich noch Bug-Fixes in maint befinden, die nicht in master sind (siehe Punkt 9).

    $ git checkout maint
    $ git merge --ff-only master

Das Branching-Modell können Sie beliebig erweitern. Ein Ansatz, den man oft antrifft, ist die Verwendung von Namespaces (siehe Abschnitt 3.1, „Referenzen: Branches und Tags“) im Zusatz zu den pu/*-Branches. Das hat den Vorteil, dass jeder Entwickler einen eigenen Namensraum verwendet, der per Konvention abgegrenzt ist. Eine andere, sehr beliebte Erweiterung ist es, für jede vorangegangene Version einen eigenen maint-Branch zu erhalten. Dadurch wird es möglich, beliebig viele ältere Versionen zu pflegen. Dazu wird vor dem Merge von maint nach master in Punkt 9 ein entsprechender Branch für die Version erstellt.

$ git branch maint-v0.1.2

Bedenken Sie aber, dass diese zusätzlichen Maintenance-Branches einen erhöhten Wartungsaufwand bedeuten, da jeder neue Bug-Fix geprüft werden muss. Ist er auch für eine ältere Version relevant, muss er per git cherry-pick in den Maintenance-Branch für die Version eingebaut werden. Außerdem muss ggf. eine neue Maintenance-Version getaggt und veröffentlicht werden.

6.3. Releases-Management

Sobald ein Projekt mehr als nur ein, zwei Entwickler hat, ist es in der Regel sinnvoll, einen Entwickler mit dem Management der Releases zu beauftragen. Dieser Integration Manager entscheidet nach Rücksprache mit den anderen (z.B. über die Mailingliste), welche Branches integriert und wann neue Releases erstellt werden.

Jedes Projekt hat eigene Anforderungen an den Release-Ablauf. Nachfolgend einige generelle Tipps, wie Sie die Entwicklung überwachen und den Release-Prozess teilweise automatisieren können.[90]

6.3.1. Aufgaben sondieren

Der Maintainer einer Software muss einen guten Überblick über die Features haben, die aktiv entwickelt und bald integriert werden sollen. In den meisten Entwicklungsmodellen graduieren Commits von einem Branch auf den nächsten – im oben vorgestellten Modell zunächst aus den pu-Branches nach next und dann nach master.

Zunächst sollten Sie Ihre lokalen Branches immer aufräumen, um nicht den Überblick zu verlieren. Dabei hilft besonders das Kommando git branch --merged master, das alle Branches auflistet, die schon vollständig in master (oder einen anderen Branch) integriert sind. Diese können Sie in der Regel löschen.

Um einen groben Überblick zu erhalten, welche Aufgaben anstehen, empfiehlt es sich, git show-branch einzusetzen. Ohne weitere Argumente listet es alle lokalen Branches auf, jeden mit einem Ausrufezeichen (!) in eigener Farbe. Der aktuelle Branch erhält einen Stern (*). Unterhalb der Ausgabe werden alle Commits ausgegeben sowie für jeden Branch in der jeweiligen Spalte ein Plus (+) bzw. ein Stern (*), wenn der Commit Teil des Branches ist. Ein Minus (-) signalisiert Merge-Commits.

$ git show-branch
! [for-hjemli] initialize buf2 properly
 * [master] Merge branch 'stable'
  ! [z-custom] silently discard "error opening directory" messages
---
+   [for-hjemli] initialize buf2 properly
--  [master] Merge branch 'stable'
+*  [master^2] Add advice about scan-path in cgitrc.5.txt
+*  [master^2^] fix two encoding bugs
+*  [master^] make enable-log-linecount independent of -filecount
+*  [master~2] new_filter: correctly initialise ... for a new filter
+*  [master~3] source_filter: fix a memory leak
  + [z-custom] silently discard "error opening directory" messages
  + [z-custom^] Highlight odd rows
  + [z-custom~2] print upstream modification time
  + [z-custom~3] make latin1 default charset
+*+ [master~4] CGIT 0.9

Es werden nur so viele Commits gezeigt, bis eine gemeinsame Merge-Basis aller Commits gefunden wird (im Beispiel: master~4). Wollen Sie nicht alle Branches gleichzeitig untersuchen, sondern z.B. nur die Branches unter pu/, dann geben Sie dies explizit als Argument an. --topics <branch> bestimmt <branch> als Integrations-Zweig, dessen Commits nicht explizit angezeigt werden.

Das folgende Kommando zeigt Ihnen also alle Commits aller pu-Branches und deren Relation zu master:

$ git show-branch --topics master "pu/*"

Tipp

Es lohnt sich, die Kommandos, die Sie zum Release-Management verwenden, zu dokumentieren (so dass andere Ihre Aufgaben eventuell weiterführen können). Außerdem sollten Sie gängige Schritte durch Aliase abkürzen.

Das o.g. Kommando könnten Sie wie folgt in ein Alias todo umwandeln:

$ git config --global alias.todo \
  "!git rev-parse --symbolic --branches | \
  xargs git show-branch --topics master"

Das Kommando git show-branch erkennt allerdings nur gleiche, das heißt identische Commits. Wenn Sie einen Commit per git cherry-pick in einen anderen Branch übernehmen, sind die Änderungen fast die gleichen, git show-branch würde dies aber nicht erkennen, da sich die SHA-1-Summe des Commits ändert.

Für diese Fälle ist das Tool git cherry zuständig. Es verwendet intern das kleine Tool git-patch-id, das einen Commit auf seine bloßen Änderungen reduziert. Dabei werden Whitespace-Änderungen sowie die kontextuelle Position der Hunks (Zeilennummern) ignoriert. Das Tool liefert also für Patches, die essentiell die gleiche Änderung einbringen, die gleiche ID.

In der Regel wird git cherry eingesetzt, wenn sich die Frage stellt: Welche Commits wurden schon in den Integrations-Branch übernommen? Dafür wird das Kommando git cherry -v <upstream> <topic> verwendet: Es listet alle Commits auf <topic> auf, und stellt ihnen ein Minus (-) voran, wenn sie schon in <upstream> sind, ansonsten ein Plus (+). Das sieht z.B. so aus:

$ git cherry --abbrev=7 -v master z-custom
+ ae8538e guess default branch from HEAD
- 6f70c3d fix two encoding bugs
- 42a6061 Add advice about scan-path in cgitrc.5.txt
+ cd3cf53 make latin1 default charset
+ 95f7179 Highlight odd rows
+ bbaabe9 silently discard "error opening directory" messages

Zwei der Patches wurden schon nach master übernommen. Das erkennt git cherry, obwohl sich die Commit-IDs dabei geändert haben.

6.3.2. Release erstellen

Git bietet die folgenden zwei nützlichen Werkzeuge, um ein Release vorzubereiten:

git shortlog
Fasst die Ausgabe von git log zusammen.
git archive
Erstellt automatisiert ein Quellcode-Archiv.

Zu einem guten Release gehört ein sogenanntes Changelog, also eine Zusammenfassung der wichtigsten Neuerungen inklusive Danksagungen an Personen, die Hilfe beigesteuert haben. Hier kommt git shortlog zum Einsatz. Das Kommando zeigt die jeweiligen Autoren, wie viele Commits jeder gemacht hat und die Commit-Messages der einzelnen Commits. So ist sehr gut ersichtlich, wer was gemacht hat.

$ git shortlog HEAD~3..
Georges Khaznadar (1):
      bugfix: 3294518

Kai Dietrich (6):
      delete grammar tests in master
      updated changelog and makefile
      in-code version number updated
      version number in README
      version number in distutils setup.py
      Merge branch 'prepare-release-0.9.3'

Valentin Haenel (3):
      test: add trivial test for color transform
      test: expose bug with ID 3294518
      Merge branch 'fix-3294518'

Mit der Option --numbered bzw. -n wird die Ausgabe, statt alphabetisch, nach der Anzahl der Commits sortiert. Mit --summary bzw. -s fallen die Commit-Nachrichten weg.

Sehen Sie aber im Zweifel davon ab, einfach die Ausgabe von git log oder git shortlog in die Datei CHANGELOG zu schreiben. Gerade bei vielen, technischen Commits ist das Changelog dann nicht hilfreich (wen diese Informationen interessieren, der kann immer im Repository nachschauen). Sie können aber die Ausgabe als Grundlage nehmen, unwichtige Änderungen löschen und die restlichen zu sinnvollen Gruppen zusammenfassen.

Tipp

Oft stellt sich für den Maintainer die Frage, was sich seit dem letzten Release verändert hat. Hier hilft git-describe (siehe Abschnitt 3.1.3, „Tags – Wichtige Versionen markieren“), das in Verbindung mit --abbrev=0 das erste erreichbare Tag vom HEAD aus ausgibt:

$ git describe
wiki2beamer-0.9.2-20-g181f09a
$ git describe --abbrev=0
wiki2beamer-0.9.2

In Kombination mit git shortlog lässt sich die gestellte Frage sehr einfach beantworten:

$ git shortlog -sn $(git describe --abbrev=0)..
    15  Kai Dietrich
     4  Valentin Haenel
     1  Georges Khaznadar

Das Kommando git archive hilft beim Erstellen eines Quellcode-Archivs. Das Kommando beherrscht sowohl das Tar- als auch das Zip-Format. Zusätzlich können Sie mit der Option --prefix= ein Präfix für die zu speichernden Dateien setzen. Die oberste Ebene des Repositorys wird dann unterhalb dieses Präfix abgelegt, üblicherweise der Name und die Versionsnummer der Software:

$ git archive --format=zip --prefix=wiki2beamer-0.9.3/ HEAD \
    > wiki2beamer-0.9.3.zip
$ git archive --format=tar --prefix=wiki2beamer-0.9.3/ HEAD \
    | gzip > wiki2beamer-0.9.3.tgz

Als zwingendes Argument erwartet das Kommando einen Commit (bzw. einen Tree), der als Archiv gepackt werden soll. Im o.g. Beispiel ist das HEAD. Es hätte aber auch eine Commit-ID, eine Referenz (Branch oder Tag) oder direkt ein Tree-Objekt sein können.[91]

Auch hier können Sie git describe einsetzen, nachdem Sie einen Release-Commit getaggt haben. Bei einem geeigneten Tag-Schema <name>-<X.Y.Z> wie oben reicht dann folgendes Kommando:

$ version=$(git describe)
$ git archive --format=zip --prefix=$version/ HEAD > $version.zip

Es kann sein, dass nicht alle Dateien, die Sie in Ihrem Git-Repository verwalten, auch in den Quellcode-Archiven vorkommen sollten, z.B. die Projekt-Webseite. Sie können zusätzlich noch Pfade angeben – um also das Archiv auf das Verzeichnis src und die Dateien LICENSE und README zu beschränken, verwenden Sie:

$ version=$(git describe)
$ git archive --format=zip --prefix=$version/ HEAD src LICENSE README \
    > $version.zip

Git speichert, sofern Sie einen Commit als Argument angeben, die SHA-1-Summe mit im Archiv ab. Im Tar-Format wird dies als Pax-Header-Eintrag mit eingespeichert, den Git mit dem Kommando git get-tar-commit-id wieder auslesen kann:

$ zcat wiki2beamer-0.9.3.tgz | git get-tar-commit-id
181f09a469546b4ebdc6f565ac31b3f07a19cecb

In Zip-Dateien speichert Git die SHA-1-Summe einfach im Kommentarfeld:

$ unzip -l wiki2beamer-0.9.3.zip | head -5
Archive:  wiki2beamer-0.9.3.zip
181f09a469546b4ebdc6f565ac31b3f07a19cecb
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  05-06-2011 20:45   wiki2beamer-0.9.3/

Tipp

Ein Problem, das Sie bedenken sollten, ist, dass zum Beispiel .gitignore-Dateien automatisch mit gepackt werden. Da sie aber außerhalb eines Git-Repositorys keine Bedeutung haben, lohnt es sich, sie mit dem Git-Attribut (siehe Abschnitt 8.1, „Git-Attribute – Dateien gesondert behandeln“) export-ignore auszuschließen. Das geschieht durch einen Eintrag .gitignore export-ignore in .git/info/attributes.

Auch können Sie vor dem Einpacken des Archivs automatische Keyword-Ersetzungen vornehmen (siehe Abschnitt 8.1.2, „Keywords in Dateien“).



[88] Zu empfehlen ist u.a. das dritte Kapitel von Open Source Projektmanagement von Michael Prokop (Open Source Press, München, 2010). Auch das Manifesto for Agile Software Development hält unter http://agilemanifesto.org/ aufschlussreiche Hinweise bereit.

[89] Eine Ausnahme besteht, wenn Sie eine neue Entwicklung in der Mainline in Ihrem Topic-Branch benötigen; in dem Fall können Sie allerdings auch überlegen, den Topic-Branch per Rebase neu aufzubauen, so dass er die benötigte Funktionalität schon beinhaltet.

[90] Weitere Anregungen finden Sie im Kapitel 6 des Buches Open Source Projektmanagement von Michael Prokop (Open Source Press, München, 2010).

[91] Jeder Commit referenziert genau einen Tree. Allerdings verhält sich git archive verschieden, je nachdem, ob Sie einen Commit (der einen Tree referenziert) oder einen Tree direkt angeben: Der Zeitpunkt der letzten Modifikation, der im Archiv aufgenommen wird, ist bei Trees die Systemzeit – bei einem Commit allerdings wird der Zeitpunkt des Commits gesetzt.


Creative Commons License
Lizensiert unter der Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.