Compare Working Tree and Index with git diff-files
git diff-files tells you which tracked files disagree with the index right now, before you even think about staging. You will come away able to read the patch, check whitespace, and use the exit status in a script. The examples match Git 2.43.0 from the installed git-man package, version 1:2.43.0-1ubuntu7.3.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. You need a Git repository with at least one tracked file and ordinary shell access. This command is read-only: it does not stage, discard, commit or otherwise change your files.
1. Confirm the repository and command version
Run these checks from the repository, or replace the directory with an absolute path you trust:
$ git --version
git version 2.43.0
$ git rev-parse --show-toplevel
/path/to/project
$ git diff-files --help
The last command opens the installed manual in your configured pager; press q to return to the shell. If your Git version differs, keep the local manual nearby, because option details and output conventions are version-specific even when the basic comparison is stable.
Checkpoint
git rev-parse should identify the repository you intended to inspect. If it fails, change directory first rather than running the command against a parent directory merely because it is convenient.
2. Show the ordinary patch
With no path, git diff-files compares every index entry with the corresponding file in the working tree. It shows a patch for content or mode changes, but not for an ordinary untracked file, because that file is not in the index yet:
$ git diff-files
diff --git a/settings.conf b/settings.conf
index 5be4a4a..9c6d0e1 100644
--- a/settings.conf
+++ b/settings.conf
@@ -1,2 +1,2 @@
-mode=quiet
+mode=verbose
The exact object IDs and context depend on your repository. A line beginning with - is from the index and a line beginning with + is from the working tree. The comparison is not against the last commit unless the index still matches that commit.
To restrict the result, put a path after the options, using the -- separator when a filename could be mistaken for an option:
$ git diff-files -- src/settings.conf
$ git diff-files -- 'notes with spaces.txt'
Expect either a patch for the named tracked path or no output when its working-tree contents match the index.
3. Choose a useful output format
The default raw format suits scripts and quick status checks. Ask for a human-readable patch explicitly with --patch, or add a compact summary when you only need the shape of the change:
$ git diff-files --patch -- src/settings.conf
$ git diff-files --stat
$ git diff-files --name-status
--patchis also available as-por-u.--statreports a summary.--name-statusreports paths and status letters.--name-onlygives names alone, when that is enough.
If whitespace is the question, use the checking mode:
$ git diff-files --check
$ printf 'check status: %s\n' "$?"
On success, the command prints nothing and the status is 0. It reports conflict markers and whitespace errors as controlled by core.whitespace, including trailing whitespace by default, and exits non-zero when it finds a problem. This is a diagnostic only, it does not repair the file: fix the working file or change the relevant project configuration deliberately, then run the check again.
4. Script on differences without parsing a patch
Use --exit-code when a script needs to distinguish "different" from "the same". Status 0 means no differences and status 1 means differences were found:
if git diff-files --quiet -- path/to/file.conf; then
printf '%s\n' 'working tree matches the index'
else
status=$?
if [ "$status" -eq 1 ]; then
printf '%s\n' 'working tree differs from the index'
else
printf 'git diff-files failed with status %s\n' "$status" >&2
exit "$status"
fi
fi
--quiet suppresses all output and implies --exit-code. Do not write a test that treats every non-zero status as "changed": an error such as a bad repository or path needs different handling. The short -q option has a narrower documented purpose here, remaining silent even for nonexistent files, so use the long form when you want the exit-code contract to be obvious.
5. Check a merge conflict from the relevant stage
During an unresolved merge, the index can hold multiple stages for one path. The default compares the working tree with the "ours" stage and cleanly resolved paths. Select a conflict view explicitly when you need the base, ours or theirs version:
$ git diff-files --base -- path/to/conflicted-file
$ git diff-files --ours -- path/to/conflicted-file
$ git diff-files --theirs -- path/to/conflicted-file
$ git diff-files --cc -- path/to/conflicted-file
These are read-only inspections. --base, --ours and --theirs omit diff output for merged entries, while --cc compares stage 2, stage 3 and the working-tree file in a combined diff. -0 suppresses the diff for unmerged entries and reports them as "Unmerged".
Warning
Do not resolve a conflict by blindly copying one side. A later git add changes the index and marks the path resolved, so review the file and project policy first. If you only wanted to inspect it, stop after the diff command. If you do make a mistaken merge resolution, the recovery path depends on whether you staged or committed it: before staging, restore the working file from your chosen source; after staging, use the normal index recovery procedure for your project. This guide does not run either destructive operation.
6. Use raw output safely
Raw output contains source and destination modes, object IDs, a status and a pathname. A modified path can look like this:
$ git diff-files --raw -- path/to/file.conf
:100644 100644 5be4a4a 0000000 M path/to/file.conf
The all-zero destination ID indicates that the working-tree file is out of sync with the index. Status letters include M for modification, A for addition, D for deletion, T for a type change and U for an unmerged file. Raw pathnames can be quoted according to core.quotePath.
For a machine parser, add -z. It emits pathnames verbatim and terminates fields or records with NUL bytes rather than relying on quoting or newlines:
git diff-files --raw -z -- path/to/file.conf |
while IFS= read -r -d '' record; do
printf 'raw record: %s\n' "$record"
done
Keep the NUL-aware reading logic if filenames may contain spaces, quotes or newlines. Do not pipe ordinary raw output into a parser that assumes one uncomplicated line per pathname.
Common traps
- An empty result proves less than it looks like.
git diff-filescompares the working tree with the index. Usegit difffor the unstaged view in the usual porcelain workflow, andgit diff --cachedfor staged changes againstHEAD. An emptygit diff-filesresult does not prove the repository is clean: the index may hold staged changes and untracked files may still exist. - Binary files may not produce a useful text patch. Use
--stat,--name-statusor the repository's approved binary review process. Do not enable external diff helpers or text conversion filters casually in automation: they can execute configured tooling and change what is being compared. - No elevated privileges are normally required. If a repository contains files your account cannot read, investigate ownership and permissions rather than routinely running Git as root. Running Git with elevated privileges can create root-owned files and may expose credentials or repository hooks to a wider context.
Done means
- You confirmed the repository and installed Git version before interpreting output.
- You can show all changes, a selected path, a patch, a summary or names only.
- You use
--checkfor whitespace diagnostics and understand its non-zero result. - Your script uses
--quietand distinguishes status 1 from a real failure. - You can inspect merge stages without staging or resolving anything.
- Any raw-output parser uses
-zwhen filenames are not guaranteed to be simple.