Skip to content

Git archive and deterministic packaging quick reference

Basic archive commands

Goal Command
Tar archive of HEAD git archive --format=tar -o release.tar HEAD
Tar.gz with prefix directory git archive --prefix=app-1.0.0/ -o app-1.0.0.tar.gz v1.0.0
Zip archive of branch git archive --format=zip --prefix=pkg/ -o pkg.zip main
Subdirectory archive git archive --prefix=api/ -o api.tar.gz HEAD:services/api
Specific files only git archive -o bundle.tar.gz HEAD src/ package.json

.gitattributes configuration

Add to .gitattributes in the repository root:

# Exclude from release archives
.github/            export-ignore
.forgejo/           export-ignore
tests/              export-ignore
Dockerfile*         export-ignore
.gitattributes      export-ignore
.gitignore          export-ignore

# Substitute commit metadata
src/version.json    export-subst
src/version.py      export-subst
src/build_info.go   export-subst

Metadata placeholder reference (export-subst)

Placeholder Expands to
$Format:%H$ Full commit hash
$Format:%h$ Short commit hash
$Format:%D$ Ref names and tags
$Format:%cI$ Committer date (ISO 8601 strict)
$Format:%an$ Author name
$Format:%ae$ Author email
$Format:%s$ Commit subject

Essential recipes

Deterministic tarball with fixed timestamp

REF="v1.4.0"
COMMIT_DATE=$(git log -1 --format=%cI "$REF")

git archive --format=tar \
  --prefix="${REF}/" \
  --mtime="$COMMIT_DATE" \
  "$REF" | gzip -n -9 > "${REF}.tar.gz"

sha256sum "${REF}.tar.gz" > "${REF}.tar.gz.sha256"

Stream archive directly into Docker build

git archive HEAD | docker build -t myapp:latest -

Inspect file inside archive without extraction

# Tar archive
tar -xOf release.tar.gz app-1.0.0/src/version.json

# Zip archive
unzip -p release.zip pkg/src/version.json

Verify excluded files are absent

git archive HEAD | tar -tf - | grep -E '(\.github|tests|Dockerfile)' || echo "Clean archive"