git rev-parse --show-toplevel and Friends in CI
git rev-parse is the plumbing that answers "where am I": --show-toplevel prints the repo root, --abbrev-ref HEAD the branch name, and --is-shallow-repository whether the clone is shallow.
CI scripts constantly need the repo root, the current branch, or whether the clone is shallow. git rev-parse answers all of these in a scriptable, machine-readable way, no parsing of git status output required.
What it does
git rev-parse converts arguments into the SHAs and paths git uses internally and exposes repository state via flags. It resolves a ref to a full SHA, prints the working-tree root, the .git directory, the current branch short name, and boolean state like shallow or inside-work-tree.
Common usage
git rev-parse --show-toplevel # absolute repo root
git rev-parse --abbrev-ref HEAD # current branch name
git rev-parse HEAD # full commit SHA
git rev-parse --short HEAD # abbreviated SHA
git rev-parse --is-shallow-repository
git rev-parse --verify --quiet refs/heads/mainOptions
| Flag | What it does |
|---|---|
| --show-toplevel | Print the absolute path of the working-tree root |
| --git-dir | Print the path to the .git directory |
| --abbrev-ref <ref> | Print a short ref name (HEAD -> branch name) |
| --short[=<n>] | Abbreviate the SHA to n hex digits |
| --is-shallow-repository | Print true if the clone is shallow |
| --verify --quiet <ref> | Validate a ref, exit nonzero if missing |
In CI
On a detached HEAD (the usual state in CI), git rev-parse --abbrev-ref HEAD prints "HEAD" rather than a branch name, so read the branch from the CI environment (GITHUB_REF_NAME) instead. Use --is-shallow-repository to decide whether to --unshallow before describe or merge-base. --verify --quiet is the clean way to test if a ref exists without erroring the script.
Common errors in CI
"fatal: not a git repository (or any of the parent directories): .git" means the command ran outside the checkout, often the dubious-ownership case: add the path to safe.directory. "fatal: ambiguous argument 'HEAD'" appears in an empty repo with no commits. --abbrev-ref returning "HEAD" is not an error, it is detached HEAD.
Using this in CI
CI checkouts are shallow and detached by default, which changes the answer this command gives you. Commands that read history, branch names, or tags need the checkout configured for it.
- uses: actions/checkout@v4
with:
fetch-depth: 0 # history, tags, and git describe all need this
- run: |
git rev-parse --is-shallow-repository # expect false
git rev-parse --abbrev-ref HEAD # prints HEAD when detached