Inspect Working Tree Changes with git diff-files
You will finish with a reliable way to compare tracked files in the working tree with their staged versions, inspect a patch, check whitespace, and use 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: 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. Do not run 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 it does not show an ordinary untracked file because that file is not in the index:
$ 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. Use the -- separator when a filename could be mistaken for an option:
$ git diff-files -- src/settings.conf
$ git diff-files -- 'notes with spaces.txt'
Expected result: 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 is useful for 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
--patch is also available as -p or -u. --stat reports a summary, while --name-status reports paths and status letters. Use --name-only when the names alone are 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".
Do not resolve a conflict by blindly copying one side. A later git add would change the index and mark 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. For example, 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.
7. Avoid the common traps
git diff-files compares the working tree with the index. Use git diff when you want the unstaged view in the usual porcelain workflow, and use git diff --cached when you want staged changes against HEAD. An empty git diff-files result does not prove that the repository is clean: the index may contain staged changes and untracked files may still exist.
Binary files may not produce a useful text patch. Use --stat, --name-status or 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. A script that needs predictable behaviour should review its Git configuration and consider explicitly disabling external helpers.
No elevated privileges are normally required. If a repository contains files that 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. - You have kept the index, working tree and untracked-file distinctions clear.