Skip to content

git restore-mtime silently restores nothing in CI: git now refuses whatchanged #74

Description

@ptr727

#65 added git restore-mtime static so the deploy's --link-dest could hard-link the static tree. It has never worked in CI, and the step exits 0.

The VPS agent measured the result and asked us to find out why before the next deploy. They were right to.

The measurement, from the host

20260808-154717 : 3275 files
20260809-030521 : 3275 files
SHARED inodes   : 0     (0.0%)

site/media    in the new release:  778 files, 1 distinct mtime day -> 2026-08-09
site/external in the new release:  270 files, 1 distinct mtime day -> 2026-08-09

Not "fewer than expected" — none. The static trees arrive with build-time mtimes, exactly as before the change.

Root cause, from the production run's log

1,052 files to be processed in work dir
'git whatchanged' is nominated for removal.
...
fatal: refusing to run without --i-still-use-this
1,052 files not found in log, trying merge commits

git-restore-mtime 2022.12, the Ubuntu package, shells out to git whatchanged. Recent git refuses to run it without --i-still-use-this. The tool got no log output, found no commit to date any file from, restored nothing, and exited 0. Git refused 12 times in that one step and the job reported success.

Why the local measurement in #65 was still honest

$ git --version
git version 2.47.3
$ git whatchanged -1 --oneline   ->  ALLOWED

Local git still permits it, so the two-clone test genuinely restored 1052 files. The runner's git does not. The measurement was real; it just did not measure the runner.

What this is an instance of

Two rules already in TODO.md, both of which this walked into:

  • "A query that matches nothing reads as a clean result." The tool reported 1,052 files to be processed, which reads like success, and then processed none of them.
  • "A gate is trusted only after it has been demonstrated failing." Restore file mtimes in CI so the deploy can hard-link static files #65 was demonstrated working locally and never demonstrated failing in CI, which is the half that would have caught this.

The VPS agent's three candidates were all reasonable and none was it: the assembly uses rsync -a and does preserve timestamps, and Hugo does preserve static mtimes into public/.

Fix

Two parts, and the second matters more than the first.

  1. Make it work. Options, roughly in order of preference:
    • Replace the dependency with git log --pretty=%at --name-only --no-merges -- static and set mtimes directly. No deprecated command, nothing to install, and the logic is the few lines that actually matter here.
    • A newer upstream git-restore-mtime if it has dropped whatchanged, pinned by checksum rather than taken from apt.
    • Aliasing whatchanged does not work: git resolves builtins ahead of aliases.
  2. Make it fail loudly. Whatever restores the mtimes, assert afterwards that static/ actually carries more than one distinct mtime day, or that its oldest file predates the checkout. A restore that silently does nothing must red the deploy rather than ship a full copy and report success. Without this, the next tool deprecation reproduces the same silence.

Blocked behind nothing. Until it lands, every release is a full ~586 MB copy, which is the pre-#65 behaviour and is not itself broken — the cost is bandwidth and disk, reclaimed by the host's prune timer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions