git diff-tree compares the contents of two tree objects at the plumbing level.
When a hook or pipeline needs the exact list of files a commit changed, diff-tree is the stable, scriptable answer. It is the engine behind much of git log and is common in post-receive hooks.
What it does
git diff-tree compares two tree objects (or the trees of two commits) and prints the differences. With -r it recurses into subtrees, and its output format is stable enough to parse in scripts.
A root (first) commit prints nothing because it has no parent; pass --root to diff it against the empty tree. Forgetting --no-commit-id leaves the commit SHA as the first output line, which then leaks into file lists when scripts read line by line.
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.
.github/workflows/ci.yml
- uses:actions/checkout@v4with:fetch-depth:0 # history, tags, and git describe all need this- run:|git rev-parse --is-shallow-repository # expect falsegit rev-parse --abbrev-ref HEAD # prints HEAD when detached
Frequently asked questions
git diff-tree: Usage, Options & Common CI Errors?
When a hook or pipeline needs the exact list of files a commit changed, diff-tree is the stable, scriptable answer. It is the engine behind much of git log and is common in post-receive hooks.
What it does?
git diff-tree compares two tree objects (or the trees of two commits) and prints the differences. With -r it recurses into subtrees, and its output format is stable enough to parse in scripts.
Common errors in CI?
A root (first) commit prints nothing because it has no parent; pass --root to diff it against the empty tree. Forgetting --no-commit-id leaves the commit SHA as the first output line, which then leaks into file lists when scripts read line by line.