The fastest way to list the files changed in git is git status -s for a working-tree overview, or git diff --name-only when you want a clean, scriptable list of nothing but paths. Which one you reach for depends on the question you are actually asking: what have I touched right now, what is staged for the next commit, what did the last commit change, or what differs between two branches. Each is a different command, and getting them confused is why people end up grepping output that has the wrong shape.
Here is the short version, then the detail behind each case.
git status -s # working tree, short and human-readable
git diff --name-only # unstaged changes, paths only
git diff --name-only --cached # staged changes, paths only
git diff-tree --no-commit-id --name-only -r HEAD # files in the last commit
git diff --name-only main...feature # changed between two branchesFiles you have changed in the working tree
For a quick look at everything that is different in your working tree, the short status is the one I run dozens of times a day:
git status -sThat prints a two-column code in front of each path. The left column is the staged (index) state, the right column is the working-tree state, so M file.js (M on the left) is staged and M file.js (M on the right) is modified but not staged. It is compact and it tells you both halves at once.
When you want only the paths, with no status codes and nothing else to strip, use git diff with --name-only. This is the form to pipe into other tools:
git diff --name-only # tracked files changed but NOT yet staged
git diff --name-only --cached # tracked files that ARE staged for the next commit--cached and --staged are the same flag (--staged was added later as the readable alias), so use whichever reads better to you. The one thing git diff will not show is brand-new untracked files, because there is nothing in the index to diff against yet. For those, git status -s shows them with ??, or list them on their own:
git ls-files --others --exclude-standard # untracked files, honoring .gitignoreFiles changed in the last commit
To see what a single commit touched, ask git diff-tree for HEAD:
git diff-tree --no-commit-id --name-only -r HEADThe flags matter: -r recurses into subdirectories (without it you get the top-level tree entries, not the actual files), and --no-commit-id suppresses the commit SHA line so the output is paths and nothing else. Swap HEAD for any commit reference to inspect an older commit.
A friendlier equivalent, if you do not mind a slightly less script-pure tool, is git show:
git show --name-only --pretty="" HEADThe empty --pretty="" strips the commit header so you are left with just the changed file names.
Files changed between branches or since a commit
To list what differs between two branches, the three-dot form is almost always what you want:
git diff --name-only main...featureThe three dots (...) compare feature against the point where it branched off main, which answers "what did this feature branch actually change" rather than dragging in every commit that landed on main in the meantime. Two dots (main..feature) compares the branch tips directly, which is occasionally what you want but more often is not. This main...feature form is the backbone of "lint only what this branch changed" in CI.
To list what has changed since a specific point in your own history, diff against a commit reference:
git diff --name-only HEAD~3 # everything that changed across the last 3 commits
git diff --name-only abc1234 # everything changed since commit abc1234Lint or format only the files that changed
This is the payoff. Once the list is just paths, you pipe it into a linter or formatter and check only what changed, instead of walking the whole tree on every commit. The pattern for a pre-commit check, linting only the JavaScript you have staged:
git diff --name-only --cached | grep '\.js$' | xargs eslintThere are two traps in that one-liner worth fixing before you ship it.
First, deletions. If you delete a file and stage the deletion, its path is still in the diff, so xargs eslint tries to lint a file that no longer exists and errors out. Filter the diff down to files that still exist with --diff-filter:
git diff --name-only --cached --diff-filter=ACMR | grep '\.js$' | xargs eslintACMR keeps Added, Copied, Modified, and Renamed files and drops Deleted ones (D). It is the standard filter for any "do something to each changed file" pipeline.
Second, filenames with spaces. A path like my notes.js gets split into two arguments by the default whitespace word-splitting, and both halves fail. The fix is to delimit on NUL bytes instead of newlines, which is the one byte a filename can never contain. git diff emits NUL-delimited output with -z, and xargs reads it with -0:
git diff --name-only -z --diff-filter=ACMR --cached | xargs -0 eslintThat is the robust form to put in a hook. If you want this handled for you across a whole team, a tool like lint-staged wraps exactly this logic, and you wire it in through a git hook so it runs on every commit. The manual pipeline above is what lint-staged is doing under the hood, and it is enough on its own for a personal project or a quick CI step.
One scripting note: when you genuinely need to parse status (not just diff), prefer git status --porcelain over git status -s. The --porcelain format is explicitly guaranteed stable across git versions, so a script built on it will not break when someone upgrades git. -s is for humans; --porcelain is for machines, even though they look nearly identical.
See also
- How to Undo Things in Git: the practical guide to restore, reset, revert, and amend once you have seen what changed.
- A Practical Guide to Git Hooks: wire the "lint only changed files" pipeline into a pre-commit hook so it runs automatically.
- How .gitignore Works in Git: why
--exclude-standardmatters when you list untracked files, and what belongs in your ignore rules. - How to Discard Local Changes in Git: once you have listed what you touched, the commands to throw the unwanted changes away.
Sources
Authoritative references this article was fact-checked against.
- git-diff (official documentation)git-scm.com
- git-status (official documentation)git-scm.com
- git-diff-tree (official documentation)git-scm.com





