Home / Alt manpages / git-diff-files(1)

  • git-diff-files(1)
  • User command
  • linux

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.

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
  • --patch is also available as -p or -u.
  • --stat reports a summary.
  • --name-status reports paths and status letters.
  • --name-only gives 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-files compares the working tree with the index. Use git diff for the unstaged view in the usual porcelain workflow, and git diff --cached for staged changes against HEAD. An empty git diff-files result 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-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.
  • 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 --check for whitespace diagnostics and understand its non-zero result.
  • Your script uses --quiet and distinguishes status 1 from a real failure.
  • You can inspect merge stages without staging or resolving anything.
  • Any raw-output parser uses -z when filenames are not guaranteed to be simple.