fix(zdeploy): sync via explicit fetch + ff-only merge, not git pull

With deploy.gitPull set, Invoke-DeployGitPull ran `git pull --ff-only`.
Pull merges whatever .git/FETCH_HEAD marks "for merge", and a
concurrent fetch in the same repo - an editor's background auto-fetch
racing the deploy - can leave duplicate for-merge lines. Pull then dies
with "Cannot fast-forward to multiple branches" even when both lines
name the same commit. Reproduced live on 2026-08-13: the deploy failed
at step 0, and by inspection time the same pull succeeded, with the
duplicated FETCH_HEAD entries as the only evidence.

Now the function fetches explicitly and fast-forwards against the
remote-tracking ref:

  git fetch origin
  git merge --ff-only origin/$branch

Identical fast-forward-or-refuse semantics, but nothing shared and
mutable in the path. A failed fetch and a failed merge now also throw
distinct messages, so the operator knows which half broke.

CHECKSUMS.txt refreshed alongside, per the manifest rule.

Tested: PS 5.1 parse clean; full Pester suite 222/222 after the
manifest refresh (the 3 pre-refresh failures were the checksum suite
correctly flagging the edited file). The same fix pattern was
exercised against live and scratch repos for the private twin
(evomedia-net/evo.scripts#58): behind -> fast-forwards, diverged ->
refuses and aborts the deploy.

Closes #48
This commit is contained in:
KellyMichels 2026-08-13 19:33:47 -05:00
parent a2fafcc6d0
commit bab21b2b06
2 changed files with 14 additions and 4 deletions

View File

@ -15,7 +15,7 @@ c92343ce16e82210bfbdccd6ea7866ee4f0b2e0f035cf9605aa6bb35c0ba5209 zec2.cmd
af3d16e3f49b61ad1d31130a0d2c8bc2235c0319a4b67585f06a1ca684ecec65 zec2_rotatekeys.ps1
4b5c24e9fdc7963d3ac4bddb69f93850adc5a43d8b18b6e948d7e8a768e2765a zec2online.cmd
9d5cbf647c5e4f49a1fb0a42bd8746ac2e72f3db639ef2d3be31d7c6fe8582ef zec2online.ps1
8b842b31b5f12e2f225480dee904a39d0cc816b1f53c33ef2f14dc0210f8b670 ZHelpers.ps1
8d70ff9d6dd3211461af4e1531c205414972756af44b88cd6c146852a51f82a2 ZHelpers.ps1
0a4ff2f6f220d9bde73ac19c0e19bbf5abf338f11f15bd22b90d788dabd6d9b2 zkill.cmd
8172c4d8d2c64aa1ec4b6a1a4983aece3277e248b510994b116c3024ef661874 zkill.ps1
1b25ce0848d22e1ac579287fac05da21458b59b94e09ed192282ac548516a3ce ZKiller.ps1

View File

@ -194,14 +194,24 @@ function Invoke-DeployGitPull {
Write-Host " gitPull set but '$root' is not a git repo - skipping pull." -ForegroundColor Yellow
return
}
Write-Host "`n--- [0] git pull --ff-only ---" -ForegroundColor Cyan
Write-Host "`n--- [0] git sync (fetch + ff-only merge) ---" -ForegroundColor Cyan
Push-Location -LiteralPath $root
try {
$branch = (git rev-parse --abbrev-ref HEAD)
Write-Host " Branch: $branch" -ForegroundColor DarkGray
git pull --ff-only
# Fetch explicitly, then fast-forward against the remote-tracking ref -
# not `git pull`. Pull merges whatever FETCH_HEAD marks "for merge",
# and a concurrent fetch in the same repo (an editor's background
# auto-fetch racing the deploy) can leave duplicate for-merge lines,
# killing the run with "Cannot fast-forward to multiple branches" even
# when both lines name the same commit. origin/$branch is unambiguous.
git fetch origin
if ($LASTEXITCODE -ne 0) {
throw "git pull --ff-only failed in '$root' (branch '$branch'). Resolve it (commit / stash / reconcile), then re-run - refusing to deploy possibly-stale code."
throw "git fetch failed in '$root'. Check the remote, then re-run - refusing to deploy possibly-stale code."
}
git merge --ff-only "origin/$branch"
if ($LASTEXITCODE -ne 0) {
throw "git merge --ff-only origin/$branch failed in '$root'. Resolve it (commit / stash / reconcile), then re-run - refusing to deploy possibly-stale code."
}
Write-Host " Now at: $(git log -1 --oneline)" -ForegroundColor DarkGray
}