git update-ref: Usage, Options & Common CI Errors
git update-ref is the low-level way to point a ref at a commit, with optional safety checks.
Automation that moves branches or custom refs should use update-ref rather than writing files under .git/refs by hand - it handles packed-refs, reflogs, and compare-and-swap correctly.
What it does
git update-ref sets a reference to a new object id, optionally only if its current value matches an expected old value (compare-and-swap), and can delete a ref or process a batch of updates from standard input.
Common usage
git update-ref refs/heads/main <new-sha>
git update-ref refs/heads/main <new-sha> <old-sha> # CAS guard
git update-ref -d refs/heads/stale
git update-ref --stdin < updates.txtOptions
| Flag | What it does |
|---|---|
| <ref> <newvalue> [<oldvalue>] | Set ref, optionally guarded by old value |
| -d <ref> [<oldvalue>] | Delete a ref |
| --stdin | Read a batch of commands |
| --create-reflog | Force a reflog entry |
| -z | NUL-terminate stdin records |
Common errors in CI
fatal: Cannot lock ref ‘refs/heads/main’: is at <X> but expected <Y> - the compare-and-swap old value did not match; another job moved the ref. Re-read the current value and retry. "unable to create ‘.git/refs/...’.lock: File exists" means a stale lock from a killed process; remove it only when sure no other git is running.