Skip to content

archive step: mtime git/epoch silently stamp 1980-01-01 in linked git worktrees #2823

Description

The archive step's promise is that identical committed sources yield byte-identical archives on any machine. In a linked worktree (git worktree add) the promise quietly inverts: the same commit produces different bytes than a plain checkout, with no warning that anything degraded.

Describe the Bug

With mtime: git (or epoch), building from a plain checkout stamps entries with real commit timestamps. Building the same commit from a linked worktree stamps every entry with the 1980-01-01 fallback, so the two archives differ byte-for-byte and any hash-based consumer (S3 etags, SSM package manifests, lockfiles) sees a phantom change.

Expected Behavior

The docs scope the fallback to operating "outside a Git repository" or untracked paths. A linked worktree is inside a git repository (git log works normally there), so I expected commit timestamps, matching the plain checkout.

Actual Behavior

Every entry gets the fallback. unzip -l on two builds of the same commit:

=== control: plain checkout ===
        6  07-28-2026 17:48   a.sh
=== trial: linked worktree of the same commit ===
        6  12-31-1979 18:00   a.sh

(The trial row is 1980-01-01 00:00 UTC rendered in local time.)

Steps to Reproduce

Self-contained script and one fresh run (Atmos 1.224.1, darwin/arm64)
#!/usr/bin/env bash
# Repro: archive step mtime git/epoch silently fall back to 1980-01-01
# inside a linked git worktree, while a plain checkout of the same commit
# resolves real commit timestamps.
set -euo pipefail

ATMOS="${ATMOS:-atmos}"
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
cd "$tmp"

"$ATMOS" version

git init -q repo
cd repo
mkdir src
printf 'hello\n' > src/a.sh
git add src/a.sh
git -c user.name=repro -c user.email=repro@example.invalid -c commit.gpgsign=false \
  commit -qm 'add a.sh'
git log -1 --format='committed: %cI'

cat > atmos.yaml <<'YAML'
base_path: ""
components: { terraform: { base_path: "components" } }
stacks: { base_path: "stacks", included_paths: ["**/*"], name_pattern: "{stage}" }
workflows: { base_path: "workflows" }
YAML
mkdir -p workflows stacks
cat > workflows/repro.yaml <<'YAML'
workflows:
  build:
    steps:
      - name: pkg
        type: archive
        source: src
        destination: out.zip
        format: zip
        action: replace
        mtime: git
YAML

echo "=== control: plain checkout ==="
"$ATMOS" workflow build -f repro
unzip -l out.zip | grep 'a.sh'

echo "=== trial: linked worktree of the same commit ==="
git worktree add -q ../wt HEAD
cp atmos.yaml ../wt/
cp -R workflows ../wt/
mkdir -p ../wt/stacks
cd ../wt
"$ATMOS" workflow build -f repro
unzip -l out.zip | grep 'a.sh'

Transcript:

👽 Atmos 1.224.1 on darwin/arm64

committed: 2026-07-28T17:48:06-05:00
=== control: plain checkout ===
        6  07-28-2026 17:48   a.sh
=== trial: linked worktree of the same commit ===
        6  12-31-1979 18:00   a.sh

Mechanism

newMtimeConfig is deliberately fail-open: any error locating the repository or its history falls back to mtimeFallbackEpoch, which is the right call for temp build dirs and untracked files but also swallows this case. In a linked worktree .git is a gitdir pointer file rather than a directory; go-git's linked-worktree support looks partial (go-git/go-git#1812 reviewed the API for opening them), and somewhere along PlainOpenWithOptions(DetectDotGit) / Worktree() / Head() the resolution fails, so the fallback engages with no signal. This may be the archive-step sibling of the worktree gaps #1509 addresses for describe affected.

Relevant paths: pkg/archive/mtime.go (newMtimeConfig, modTimeFor, mtimeFallbackEpoch).

Ask

Could newMtimeConfig resolve the gitdir pointer for linked worktrees, or at least log a warning when a .git entry exists but git resolution falls back to the epoch? The silent divergence is the painful part; a build that warns is easy to live with. Happy to follow up with a PR.

Environment: Atmos 1.224.1 (pkg/archive/mtime.go is unchanged on main), darwin/arm64, git version 2.55.0.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions