Feeding linters and formatters
A CI job uses git ls-files -z -- '*.ts' to get only the tracked TypeScript files, so build output and other untracked files are skipped, and filenames with spaces still work.
Git · Command
git ls-files is a low-level (plumbing) command that lists files by comparing what's in Git's index with what's in your working directory. Flags pick which groups to show: tracked, modified, deleted, untracked, ignored or unmerged.
Last updated
The command reads the index (the staging area) and can also walk the working tree, then prints the paths that match the selection flags you give. If you pass no selection flag it acts like --cached and lists every tracked path. Other modes compare the index with the filesystem to find deleted, modified, untracked or conflicting paths. By default the output is just paths, relative to the current directory. --stage adds mode, object ID and stage number, and --format lets you build each line yourself from fields. If you list paths after the options, only those paths are shown.
git ls-files [-z] [-t] [-v] [-f] [-c|--cached] [-d|--deleted] [-o|--others] [-i|--ignored] [-s|--stage] [-u|--unmerged] [-k|--killed] [-m|--modified] [--resolve-undo] [--directory [--no-empty-directory]] [--eol] [--deduplicate] [-x <pattern>|--exclude=<pattern>] [-X <file>|--exclude-from=<file>] [--exclude-per-directory=<file>] [--exclude-standard] [--error-unmatch] [--with-tree=<tree-ish>] [--full-name] [--recurse-submodules] [--abbrev[=<n>]] [--format=<format>] [--] [<file>…]| Name | Type | Description |
|---|---|---|
-c, --cached | flag | List every tracked file in the index. This is the default when no other mode is chosen. |
-d, --deleted / -m, --modified | flag | List tracked files that have an unstaged deletion or an unstaged modification. |
-o, --others | flag | List untracked files. |
-i, --ignored | flag | Only list files that match exclude patterns. You must also give -c or -o. |
-s, --stage | flag | Add the mode bits, object name and stage number to each line. |
-u, --unmerged | flag | Only list unmerged (conflicted) entries. Turns on --stage. |
-z | flag | End each entry with a NUL byte and print filenames without quoting. |
--exclude-standard | flag | Use the normal ignore sources: .git/info/exclude, every .gitignore, and the user's global excludes file. |
--error-unmatch | flag | Fail with exit status 1 if any <file> given is not in the index. |
--format=<format> | string | Build each line from %(fieldname) placeholders such as objectname, objectmode, stage and path. |
--full-name | flag | Print paths relative to the repository root instead of the current directory. |
<file> | pathspec | Only show these paths. If none are given, every matching file is shown. |
Writes the selected paths to stdout, one per line by default. With --stage each line is '[<tag> ]<mode> <object> <stage> <file>'. With --error-unmatch the exit status is 1 if any given path is missing from the index.
#!/usr/bin/env bash
set -euo pipefail
# All tracked files, with paths relative to the repo root
git ls-files --full-name
# Untracked files that are not ignored, one entry per untracked directory
git ls-files --others --exclude-standard --directory
# Ignored files currently in the working tree
git ls-files --others --ignored --exclude-standard
# Index entries with object id and stage number
git ls-files --format='%(objectmode) %(objectname) %(stage) %(path)'
# Conflicted entries during a merge (stages 1-3)
git ls-files --unmerged
# Check whether a path is tracked (exit status 1 if not)
if git ls-files --error-unmatch README.md >/dev/null 2>&1; then
echo "README.md is tracked"
fi
# Pass filenames safely to another tool using NUL separators
git ls-files -z -- '*.py' | xargs -0 wc -lThe script lists tracked, untracked and ignored files, shows index entries and merge conflicts, checks whether a file is tracked, and passes tracked filenames safely to another tool.
A CI job uses git ls-files -z -- '*.ts' to get only the tracked TypeScript files, so build output and other untracked files are skipped, and filenames with spaces still work.
Before cutting a release, run git ls-files -o --exclude-standard to spot new files nobody has added yet, while leaving out anything .gitignore covers.
While resolving a conflict, use git ls-files -u to see the base, ours and theirs blob IDs for each conflicted path.
Run git ls-files --eol to find files saved with CRLF or mixed endings and see which text/eol attributes apply to them.
With no mode flag it acts like --cached and prints every tracked path in the index, relative to the current directory. git ls-tree lists the contents of a tree object, such as a commit's tree. ls-files reflects the current index, including staged changes that are not committed yet.
Follow-up: How would you print object IDs along with the paths? Use git ls-files -s (mode, object, stage, path) or --format='%(objectname) %(path)'.
Combine -i with -o (or with -c to find tracked files that match ignore rules), and add an exclude source such as --exclude-standard. -i does not load ignore rules on its own, so leaving out the exclude option gives no useful result.
Follow-up: Which files does --exclude-standard read? .git/info/exclude, the .gitignore in each directory, and the user's global excludes file (core.excludesfile or $XDG_CONFIG_HOME/git/ignore).
Run git ls-files --error-unmatch <path>. It exits with status 1 if the path is not in the index, so the exit code tells you the answer. Send its output to /dev/null if you only care about the status.
Follow-up: Why use -z when you pipe ls-files output to other tools? Without -z, unusual filenames are quoted according to core.quotePath. With -z they are printed as-is and separated by NUL, which works with xargs -0.
git ls-treegit read-treegit update-indexgit statusgit diff-filesgit check-ignoregitignore