saubere Release-Exporte ohne .git-Verzeichnis
git archive erzeugt aus einem beliebigen Commit, Tag oder Tree einen reinen Datei-Snapshot als zip- oder tar-Archiv, komplett ohne Commit-Historie und ohne .git-Verzeichnis. Wer Release-Pakete bisher per Hand aus einem Checkout zusammenkopiert, findet hier ein deterministisches, direkt in CI-Pipelines einsetzbares Werkzeug, das Git bereits mitbringt.
Inhaltsverzeichnis
- 1. Was git archive vom normalen Checkout unterscheidet
- 2. Ausgabeformate: zip, tar und komprimiertes tar.gz
- 3. Saubere Verzeichnisstruktur mit --prefix
- 4. Dateien gezielt ausschließen mit .gitattributes
- 5. Archive von einem entfernten Repository ohne lokalen Checkout
- 6. Archive an Git-Tags koppeln für nachvollziehbare Releases
- 7. Reproduzierbarkeit und Prüfsummen für Release-Artefakte
- 8. Einsatz von git archive in CI/CD-Pipelines
- 9. Grenzen von git archive: Submodule und generierte Dateien
- 10. Zusammenfassung
- 11. FAQ
1. Was git archive vom normalen Checkout unterscheidet
Ein gewöhnlicher git clone bringt zwangsläufig das komplette .git-Verzeichnis mit, also die vollständige Commit-Historie, alle Branches und alle jemals erstellten Objekte. Für ein Release-Artefakt, das an Kunden ausgeliefert oder in ein Deployment-Paket verpackt wird, ist das in aller Regel unerwünschter Ballast und je nach Historie sogar ein Datenschutzrisiko, wenn frühere Commits sensible Inhalte enthielten, die später zwar entfernt, aber nie aus der Historie getilgt wurden.
git archive löst genau dieses Problem, indem es direkt auf Basis der Objektdatenbank arbeitet und ausschließlich den Dateiinhalt eines einzelnen, exakt bestimmten Commits, Tags oder Trees in ein Archiv schreibt. Es liest dazu intern denselben Baum, den auch git ls-tree anzeigen würde, und benötigt dafür weder ein Working Directory noch überhaupt einen lokalen Checkout, ein bare Repository reicht vollkommen aus.
Das Ergebnis ist deterministisch im Sinne des Dateiinhalts: Derselbe Commit liefert bei jedem Aufruf exakt dieselbe Dateiliste mit demselben Inhalt, unabhängig davon, welcher Branch gerade ausgecheckt ist oder was im Arbeitsverzeichnis sonst noch herumliegt.
# Minimalbeispiel: aktuellen Stand als zip-Archiv exportieren
git archive --format=zip HEAD -o release.zip
# Denselben Snapshot als tar-Archiv aus einem bare Repository heraus
git --git-dir=/pfad/zum/bare-repo.git archive HEAD -o release.tar
2. Ausgabeformate: zip, tar und komprimiertes tar.gz
Über die Option --format unterstützt git archive mindestens zip und tar als Standardformate, wobei sich zip vor allem für Windows-Empfänger anbietet, während tar im Linux- und Container-Umfeld die gebräuchlichere Wahl ist. Wird der Zieldateiname stattdessen über -o mit einer erkennbaren Endung wie .zip angegeben, leitet Git das Format automatisch aus der Endung ab, sodass die explizite --format-Angabe entfallen kann.
Für komprimierte tar-Archive lässt sich das Format tar.gz direkt angeben, Git nutzt dafür die eingebaute Zlib-Kompression, sodass kein externes gzip-Binary erforderlich ist. Wer die Kompressionsstufe steuern möchte, kann eine Zahl von -1 bis -9 anhängen, wobei höhere Werte mehr Rechenzeit gegen eine kleinere Ausgabedatei tauschen und sich für einmalige Release-Builds in der Regel die höchste Stufe lohnt.
# Komprimiertes tar.gz mit maximaler Kompressionsstufe
git archive --format=tar.gz -9 HEAD -o release.tar.gz
# Format wird automatisch aus der Dateiendung erkannt
git archive HEAD -o release.zip
3. Saubere Verzeichnisstruktur mit --prefix
Ohne weitere Angaben landen die Dateien eines Archivs direkt auf der obersten Ebene, was beim Entpacken schnell zu einem unübersichtlichen Verzeichnis führt, in dem sich Release-Dateien mit bereits vorhandenen Dateien im Zielordner vermischen. Die Option --prefix fügt jedem Eintrag im Archiv einen führenden Pfad hinzu, sodass beim Auspacken automatisch ein eigener Wurzelordner entsteht.
Üblich ist ein Präfix, das Projektname und Version enthält, etwa meinshop-2.4.1/, damit beim Entpacken mehrerer Releases nebeneinander keine Dateien überschrieben werden und auf einen Blick erkennbar bleibt, welche Version in welchem Ordner liegt.
# Archiv mit eigenem Wurzelverzeichnis erzeugen
git archive --format=tar.gz --prefix=meinshop-2.4.1/ v2.4.1 -o meinshop-2.4.1.tar.gz
4. Dateien gezielt ausschließen mit .gitattributes
Nicht jede Datei im Repository gehört in ein Release-Archiv. Testverzeichnisse, interne Dokumentation, CI-Konfigurationsdateien oder Entwickler-Tooling sollen häufig zwar versioniert, aber nicht ausgeliefert werden. Genau dafür bietet Git das Attribut export-ignore, das in einer .gitattributes-Datei gesetzt wird und ausschließlich beim Archivieren wirkt, den normalen Checkout aber unangetastet lässt.
Ein ergänzendes Attribut ist export-subst: Es aktiviert die Ersetzung von Platzhaltern wie $Format:%H$ innerhalb einer markierten Datei durch den tatsächlichen Commit-Hash zum Zeitpunkt des Archivierens, was sich hervorragend eignet, um eine Versionsdatei ohne .git-Zugriff nachvollziehbar zu halten.
# .gitattributes im Projekt-Root
tests/ export-ignore
docs-intern/ export-ignore
.gitlab-ci.yml export-ignore
VERSION export-subst
5. Archive von einem entfernten Repository ohne lokalen Checkout
Mit der Option --remote lässt sich ein Archiv theoretisch direkt von einem entfernten Repository anfordern, ohne dass zuvor ein lokaler Clone nötig ist. Der Server erzeugt das Archiv dabei selbst und überträgt nur das fertige Paket, was bei sehr großen Repositories mit langer Historie spürbar Bandbreite und Zeit sparen kann.
In der Praxis deaktivieren die meisten gehosteten Plattformen wie GitHub und GitLab diese Funktion serverseitig standardmäßig aus Sicherheitsgründen, da sie einem Angreifer sonst erlauben würde, beliebige Commits abzufragen, ohne dass dies im Zugriffsprotokoll klar sichtbar wäre. Für den praktischen Alltag bedeutet das: Ein lokaler Checkout mit anschließendem lokalem git archive bleibt der zuverlässigere Weg.
# Funktioniert nur, wenn der Server uploadarchive explizit erlaubt
git archive --remote=ssh://git@server/projekt.git --format=tar HEAD | tar -x
6. Archive an Git-Tags koppeln für nachvollziehbare Releases
Statt immer den aktuellen Stand von HEAD zu archivieren, sollte ein Release-Artefakt an einen konkreten, unveränderlichen Tag gebunden werden. Ein annotiertes Tag markiert einen Commit dauerhaft mit einer Versionsnummer, und git archive akzeptiert diesen Tag-Namen anstelle eines Commit-Hashes an genau derselben Stelle im Befehl.
Damit lässt sich ein einfacher, wiederholbarer Ablauf etablieren: Sobald ein Tag wie v2.4.1 gepusht wird, erzeugt ein Pipeline-Job daraus automatisch das passende Archiv und lädt es als benanntes Release-Artefakt hoch, ohne dass jemand manuell nachschauen muss, welcher Commit gerade der aktuelle Release-Stand ist.
# Release-Archiv direkt aus einem Tag erzeugen
git archive --format=tar.gz --prefix=meinshop-2.4.1/ tags/v2.4.1 \
-o meinshop-2.4.1.tar.gz
7. Reproduzierbarkeit und Prüfsummen für Release-Artefakte
Da der Dateiinhalt eines Archivs eindeutig aus dem gewählten Commit abgeleitet wird, lässt sich für jedes erzeugte Release-Paket eine Prüfsumme berechnen, die als verlässlicher Nachweis dient, dass ein heruntergeladenes Archiv wirklich unverändert dem markierten Commit entspricht. Bei gleicher Git-Version und identischen Optionen bleibt der Dateiinhalt über wiederholte Läufe hinweg stabil.
Kleinere Unterschiede in reinen Archivformat-Metadaten wie Zeitstempeln in der zip-Struktur sind je nach eingesetzter Git-Version zwar möglich, betreffen aber nicht den eigentlichen Dateiinhalt und damit auch nicht die Integrität des Release-Pakets. Eine begleitende sha256sum-Datei neben dem Archiv gehört in eine seriöse Release-Pipeline dazu.
# Prüfsumme neben dem Release-Archiv ablegen
sha256sum meinshop-2.4.1.tar.gz > meinshop-2.4.1.tar.gz.sha256
8. Einsatz von git archive in CI/CD-Pipelines
In einer Pipeline ersetzt ein einzelner git archive-Aufruf oft mehrere Zeilen manueller Kopierlogik, die zuvor bestimmte Verzeichnisse ausschloss und den Rest in ein Archiv packte. Da der Checkout in CI-Runnern ohnehin bereits vorliegt, genügt ein Job-Schritt, der das fertige Artefakt erzeugt und anschließend als Build-Artefakt hochlädt oder in einen Artefakt-Speicher überträgt.
Ein wichtiger Nebeneffekt: Da das Archiv kein .git-Verzeichnis enthält, gelangt auch keine komplette Commit-Historie versehentlich in ein öffentlich zugängliches Release-Paket, was insbesondere bei Open-Source-Downloads oder Kunden-Deployments ein reales Risiko reduziert.
# Beispiel-Job-Schritt in einer CI-Pipeline
build-release:
script:
- git archive --format=tar.gz --prefix=app-${CI_COMMIT_TAG}/ \
${CI_COMMIT_TAG} -o app-${CI_COMMIT_TAG}.tar.gz
artifacts:
paths:
- app-*.tar.gz
9. Grenzen von git archive: Submodule und generierte Dateien
Zwei Einschränkungen sollten vor dem produktiven Einsatz bekannt sein. Erstens werden Submodule von git archive nicht automatisch mit ausgepackt, im Archiv landet lediglich der Verweis auf den referenzierten Commit des Submoduls, nicht dessen tatsächlicher Inhalt. Für Projekte mit Submodulen sind zusätzliche Skripte wie das bekannte git-archive-all nötig, die rekursiv durch alle Submodule laufen und deren Inhalte anschließend zusammenführen.
Zweitens enthält das Archiv ausschließlich versionierte Dateien. Generierte oder installierte Abhängigkeiten wie Verzeichnisse für Composer- oder npm-Pakete sind üblicherweise nicht Teil des Repositories und müssen dementsprechend in einem separaten Build-Schritt nach dem Archivieren erzeugt werden, bevor das fertige Paket tatsächlich lauffähig ist.
| Kriterium | git archive | git clone --depth 1 | Manuelles zip/tar |
|---|---|---|---|
| Enthält .git-Verzeichnis | Nein | Ja, wenn auch verkleinert | Abhängig vom Skript |
| Deterministischer Inhalt | Ja, exakt zum Commit | Ja, aber inklusive Metadaten | Nein, fehleranfällig |
| Serverseitig ohne Checkout möglich | Ja, bei erlaubtem Remote | Nein | Nein |
| Dateien gezielt ausschließen | Ja, über .gitattributes | Nein, nur nachträgliches Löschen | Ja, aber manuell gepflegt |
| Geeignet für automatisierte Pipelines | Ja, ein einzelner Befehl | Bedingt, zusätzlicher Aufräumschritt nötig | Nein, wartungsintensiv |
Mironsoft
Git-Workflows, Branching-Strategien und CI-Hooks
Chaotische Git-Historie und unklare Branching-Regeln im Team?
Wir richten saubere Git-Workflows ein, klären Branching-Strategien fürs Team und automatisieren Qualitätschecks über Git-Hooks und CI-Pipelines, damit die Historie nachvollziehbar bleibt.
Workflow-Audit
Bestehende Branching-Strategie und Merge-Praxis auf Schwachstellen prüfen.
Hook-Automatisierung
Pre-Commit- und Pre-Push-Hooks für Linting, Tests und Commit-Konventionen einrichten.
Team-Schulung
Rebase, Cherry-Pick und Konfliktauflösung im Team praxisnah vermitteln.
10. Zusammenfassung
Git Archive
Kernidee
git archive erzeugt einen reinen Datei-Snapshot eines Commits als zip oder tar, ganz ohne .git-Verzeichnis und ohne Historie.
Saubere Struktur
--prefix sorgt für einen eigenen Wurzelordner im Archiv, .gitattributes mit export-ignore schließt gezielt Dateien aus.
Typischer Einsatz
Ein CI-Job erzeugt bei jedem Tag automatisch ein benanntes, geprüftes Release-Artefakt aus dem markierten Commit.
Bekannte Grenze
Submodule und generierte Abhängigkeiten wie vendor- oder node_modules-Verzeichnisse werden nicht automatisch mit archiviert.