
Check Git status before an agent handoff
In short: An empty Git diff can miss staged or untracked work; check machine-readable status and distinguish remaining changes from a failed command.
python ▸ import subprocess
import sys
repo = sys.argv[1] if len(sys.argv) > 1 else "."
try:
result = subprocess.run(
["git", "--no-optional-locks", "-C", repo, "status",
"--porcelain=v1", "-z", "--untracked-files=all",
"--ignore-submodules=none"],
check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
)
except (OSError, subprocess.CalledProcessError):
print("Git status failed; cleanliness is unknown.", file=sys.stderr)
raise SystemExit(2)
if result.stdout:
print("Changes remain; inspect git status before handoff.")
raise SystemExit(1)
print("No tracked or non-ignored untracked changes reported.")An untracked file was sitting in the repository, and git diff --exit-code returned zero. After staging that file, the same command still returned zero. Both cases were reproduced with Git 2.50.1 in a disposable repository on 9 October 2026.
Check Git status before an agent handoff, not just the diff. My acceptance rule is narrow: establish whether Git reports remaining changes, and keep a failed inspection separate from a clean result. Neither result proves the code is correct or that anything reached production.
Why an empty Git diff misses unfinished work
The plain form of git diff compares the working tree with the index. Its zero exit code says that comparison found no differences. A staged change belongs to a different comparison; a new untracked file is not included in that ordinary diff.
That is perfectly useful when reviewing unstaged edits. It is insufficient when a worker's final message promises that everything has been committed. The command answered one question, while the handoff claimed another.
Check Git status without parsing filenames
Save this helper outside the repository being checked as check_clean.py. Run python3 /path/to/check_clean.py /path/to/repository with Python 3 and Git installed. It reports state without staging, committing or deleting files:
import subprocess
import sys
repo = sys.argv[1] if len(sys.argv) > 1 else "."
try:
result = subprocess.run(
["git", "--no-optional-locks", "-C", repo, "status",
"--porcelain=v1", "-z", "--untracked-files=all",
"--ignore-submodules=none"],
check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
)
except (OSError, subprocess.CalledProcessError):
print("Git status failed; cleanliness is unknown.", file=sys.stderr)
raise SystemExit(2)
if result.stdout:
print("Changes remain; inspect git status before handoff.")
raise SystemExit(1)
print("No tracked or non-ignored untracked changes reported.")
Git's status documentation defines porcelain v1 as a stable script-facing format. The helper asks explicitly for untracked files, rather than inheriting a setting that hides them. It also requests submodule reporting instead of silently accepting an ignore setting; submodules were not part of the local test fixture.
The NUL-delimited output stays as bytes. For this yes-or-no check, there is no reason to split filenames into lines or decode them. --no-optional-locks avoids the optional index-refresh write documented for background status checks; it is not a lock against another process changing files.
The synthetic Git handoff test
Six states were checked locally, with these helper exit codes:
| Fixture | Exit |
|---|---|
| Clean committed repository | 0 |
| Untracked newline-containing filename, with untracked display disabled in config | 1 |
| Staged-only addition | 1 |
| Modified tracked file | 1 |
| Only an ignored temporary file | 0 |
| Directory outside a repository | 2 |
Synthetic Git 2.50.1 checks; these are outcomes, not performance measurements.
The ignored-file result is intentional. This check does not inventory every artifact on disk. If a generated report or model output is ignored, you need a separate delivery check for that artifact. Do not turn an ignore rule into accidental evidence that the work was delivered.
My judgement for a coding-agent handoff
For a hypothetical code-generation worker, I would capture the starting status, let the worker finish, then inspect the ending status after writers have stopped. A dirty result is a reason to investigate, not permission to delete files or commit everything. Existing user changes must remain distinguishable from the worker's output.
Keep the next checks separate: the intended commit exists, tests passed, the branch was pushed if requested, and the deployment succeeded if required. A clean repository can contain entirely wrong code. It can also contain a correct commit that nobody else can access yet.
This helper assumes the intended repository and ordinary Git executable are being used. It is not an audit of hostile Git configuration, sparse checkouts or concurrent writers. An empty result describes what Git reported at that inspection, not an enduring filesystem guarantee.
What's in it for you
- Catch staged and untracked leftovers before accepting a clean-worktree claim.
- Keep inspection failure, remaining work and successful delivery as different outcomes.
A clean handoff needs a status check; a successful delivery still needs its own evidence.
Sources
- Git — git-status documentation, accessed 9 October 2026.
- Git — git-diff documentation, accessed 9 October 2026.


