Skip to content
Latchkey

git diff --exit-code: Fail CI on Uncommitted Changes

git diff --exit-code makes git diff return exit status 1 whenever there are differences, so a CI job fails if a generated or formatted file was left uncommitted.

This is the canonical "did you commit the generated output?" gate. Run the generator or formatter, then let git diff --exit-code turn any residual change into a red build.

What it does

git diff normally exits 0 regardless of output. With --exit-code it exits 1 when there are differences and 0 when the tree is clean. Against the working tree it catches unstaged changes; add --cached (or --staged) to check staged changes. The related --quiet implies --exit-code and suppresses output.

Common usage

Terminal
# fail if formatting was not committed
npm run format
git diff --exit-code

# fail if the lockfile is stale after install
npm ci
git diff --exit-code package-lock.json

# quiet gate (no diff printed)
go generate ./... && git diff --quiet || (git diff && exit 1)

Options

FlagWhat it does
--exit-codeExit 1 if there are differences, 0 if none
--quietImplies --exit-code and prints nothing
--cached / --stagedCompare the index to HEAD instead of the working tree
--statAlso print a summary of what changed
-- <path>Limit the check to specific files (e.g. a lockfile)

In CI

The universal recipe: run the tool that should have already been run (formatter, codegen, dependency install), then git diff --exit-code. If the developer forgot to commit the result, the working tree is dirty and the job fails. Untracked new files escape git diff, so add git add -A first or use git status --porcelain to catch them too.

Common errors in CI

A gate that never fails is usually because the change created a new untracked file (git diff ignores those) or the generator wrote outside the repo; run git add -A before the diff. Line-ending churn ("the whole file changed") is a CRLF/autocrlf mismatch, not real drift; set core.autocrlf=false on the runner. --exit-code prints the diff by default; pair it with --stat for a compact failure log.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →