Skip to content

Deploying and committing to git are not the same done — the trap of assuming uploaded means synced

Near the end of a release, every file transfer to the production server succeeded, and the version file that triggers distribution was updated too. With that confirmed, the release got reported as complete — except the local git repository never actually had those changes committed.

Note: “Deploying” here means transferring changed files to the production server (via scp, for example) so they’re actually live for users. “git push” is a separate operation that records the change history in a remote repository.

What happened

This release involved transferring seven files to the production server: five landing-page update-notice files, the version file that triggers distribution, and a progress-log file. The transfer itself succeeded completely, and the production site confirmed it was showing the new version number.

The problem: after editing these files locally, the work moved straight to the transfer step without ever committing. The files on the production server were fully up to date, but the local git repository had no record of those changes — and the release got reported as complete in that state.

Why this is easy to miss

Transferring files with scp and recording them in the repository with git commit / git push are completely independent operations, both as commands and as goals. Verifying production (HTTP 200, checking the rendered content) confirms “did the deployment succeed” — a different question from “is the local change history recorded.” Treat the first check as proof of “done,” and the second check quietly never happens.

When both steps get mentally bundled into one “release complete” state, there’s no natural moment to notice that only one of them actually finished. In this case, it surfaced because someone else looking at the repo noticed it hadn’t been committed yet.

The fix — treat “uploaded” and “git synced” as two separate checks

Add a git-sync verification step to the deploy checklist, independent from the file-transfer confirmation.

# Commit before deploying
git add <changed files>
git commit -m "..."
git push origin main

# Transfer to the server via scp
scp <files> user@server:path/

# Verify production
curl -s -o /dev/null -w "%{http_code}" https://example.com/version.json

# Verify git sync (make this its own explicit step)
git status   # confirm "nothing to commit, working tree clean"
git rev-list --left-right --count origin/main...main   # confirm "0 0"

That last git rev-list command counts how many commits differ between the local and remote branches in each direction. Output of 0 0 means local and remote are fully in sync. It turns “I’m pretty sure I pushed” from a subjective memory into something a command output confirms mechanically.

What this incident reveals

The root of this incident was treating two states with different meanings — “transferred via scp” and “committed to git” — as a single mental category called “release complete.” The fix isn’t really a technical mechanism; it’s splitting the checklist into finer granularity. “Reflected in production” and “change history recorded” became two separate, explicit verification steps, and only when both are confirmed does the work count as done.

Summary

Aspect Detail
Problem Transferring files to production (scp) and recording them in git (commit/push) are independent steps, but only one got verified before calling the work “done”
Why it’s easy to miss Verifying production confirms deployment success, not whether local change history was recorded — two different questions
Fix Add git-sync verification as its own explicit item on the deploy checklist
Verification commands git status and git rev-list --left-right --count origin/main...main (expecting 0 0) confirm sync mechanically instead of relying on memory

A word like “done” that can carry multiple meanings is an easy trap for a checklist to fall into at too coarse a granularity. Naming each thing that actually needs to finish, and turning each into its own verification step, is what closes this kind of gap.