Inspect a Git tree with git ls-tree
You will finish with a reliable way to inspect the files recorded in a Git commit, recurse into selected directories, and produce output that scripts can consume. The examples use Git 2.43.0, matching the installed git-ls-tree(1) manual on this machine.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. You need Git and an existing repository with at least one commit. These commands only read objects, except for the temporary repository used in the verification example. They do not alter branches, the index or the working tree. No elevated privileges are required.
1. Check the installed command and choose a tree
Start in the repository you want to inspect. Confirm the version and identify a tree-ish, usually a commit such as HEAD:
$ git --version
git version 2.43.0
$ git rev-parse --show-toplevel
/path/to/repository
$ git rev-parse HEAD
0123456789abcdef0123456789abcdef01234567
The object named by <tree-ish> can be a commit, tag, branch name or other revision that resolves to a tree. A commit is convenient because Git follows it to its top-level tree. Replace the example object ID with output from your own repository; never use the displayed value as a real ID.
Checkpoint: if git rev-parse HEAD fails, stop here and check that you are inside a Git repository with at least one commit. Do not add sudo; privilege does not create repository history.
2. List the top level in the default format
Run git ls-tree with the tree-ish and no path:
$ git ls-tree HEAD
100644 blob 4a58007052a65fbc2fc3f910f2855f45a4058e74 README.md
040000 tree 6f59585c86a39f45a7e2043dd5a218a9740ffcfb docs
040000 tree 01afdf4295719fab3c9b3ebf620f323afc828e5b src
Each line contains the mode, object type, object name, a tab, and the path. The IDs and paths will differ. A regular file is a blob; a directory is a tree. This is the committed snapshot, not a report of uncommitted files in your working directory.
With no path argument, the command lists the root level. It does not recursively expand every directory. That default is useful when you want to understand the shape of a tree before selecting a smaller part of it.
3. Recurse into a directory
Use -r when you need files below directory entries. Add --name-only when object IDs and modes would only distract from the pathname list:
$ git ls-tree -r --name-only HEAD src
src/main.txt
src/nested/detail.txt
Paths are interpreted relative to the current working directory. If you run this from a subdirectory, src means that subdirectory's src, not necessarily the repository root's. Use --full-tree when the current directory should not limit the lookup:
$ (cd src && git ls-tree --full-tree --name-only HEAD docs src)
docs
src
--full-tree also implies --full-name, so matching paths are reported from the repository root. The parentheses keep the directory change inside a subshell. They are not required by Git, but they prevent the shell session from being left in a different directory.
4. Select directories without accidentally expanding them
A path argument is a pattern to match, not exactly the same as a shell directory argument. Without -r, naming a directory reports the directory entry itself:
$ git ls-tree HEAD src
040000 tree 01afdf4295719fab3c9b3ebf620f323afc828e5b src
$ git ls-tree -d HEAD
040000 tree 6f59585c86a39f45a7e2043dd5a218a9740ffcfb docs
040000 tree 01afdf4295719fab3c9b3ebf620f323afc828e5b src
The -d option means show only the named tree entries, not their children. It is a useful check when you want to know whether a directory exists in the snapshot. Conversely, -r descends into sub-trees. The -t option keeps the tree entry in the output while recursing, and -d implies -t.
Checkpoint: decide whether your output is meant to describe containers or their contents. Choosing -d for an inventory of files is a common distraction trap because the command succeeds while returning only directory entries.
5. Make output suitable for a script
Use a narrow output mode when a script needs one field. --object-only prints object names; --name-only prints paths. These modes cannot be combined with one another:
$ git ls-tree -r --object-only HEAD src
65b2df87f7df3aeedef04be96703e55ac19c2cfb
af17f6cc87e4d5e4adec0018cbb73d3e2bd008c8
These IDs come from the small verification repository used for the examples. Your repository will produce different values. For a custom record, use --format:
$ git ls-tree --format='%(objecttype) %(objectname) %(path)' HEAD
blob 4a58007052a65fbc2fc3f910f2855f45a4058e74 README.md
tree 6f59585c86a39f45a7e2043dd5a218a9740ffcfb docs
tree 01afdf4295719fab3c9b3ebf620f323afc828e5b src
Available fields in this installed version are objectmode, objecttype, objectname, objectsize or objectsize:padded, and path. Do not combine --format with -l, --name-only or --object-only. The format string is single-quoted so the shell passes its percent expressions unchanged.
6. Handle names and object IDs carefully
Use -l when you need blob sizes:
$ git ls-tree -l HEAD README.md
100644 blob 4a58007052a65fbc2fc3f910f2855f45a4058e74 6 README.md
The size is in bytes and is shown for blobs. Trees and commits use a dash instead of a blob size. It is not the size of a directory on disk.
For a shorter human-facing ID, use --abbrev=12:
$ git ls-tree --abbrev=12 HEAD README.md
100644 blob 4a58007052a6 README.md
The abbreviation is at least the requested length and remains unique within the object set Git uses for the display. Do not use abbreviated IDs as durable interchange data when a full object name is practical.
Git quotes unusual pathnames according to core.quotePath by default. For machine processing, add -z; paths are emitted verbatim and records are terminated with NUL bytes. A line-oriented tool that cannot handle NUL separators is not a safe consumer for arbitrary Git names.
7. Verify the result and diagnose failures
Compare a pathname-only listing with a known path before building a longer pipeline:
$ git ls-tree -r --name-only HEAD src | grep -F -- 'src/main.txt'
src/main.txt
No output from grep means that exact path was not found in the selected tree; it does not mean that the command failed. To inspect a different snapshot, replace HEAD with a commit or tag and repeat the same check.
If Git reports that an object or path does not exist, check the revision independently with git rev-parse --verify. If a path works from the repository root but not from a subdirectory, use --full-tree or change the path to match the current directory. If a script receives surprising filenames, switch to -z and use a NUL-aware reader.
There is no undo step for the normal commands in this guide because they inspect existing objects only. If you use shell redirection to save output, choose a new destination or verify it first: > will truncate an existing file before git ls-tree runs.
Done means
- You identified a real tree-ish and confirmed the installed Git version.
- You can distinguish top-level, directory-only and recursive listings.
- You know that paths depend on the current directory unless
--full-treeis used. - Your script chooses a single-field mode or an explicit
--format. - You use
-zwhen arbitrary pathnames must survive machine processing. - No branch, index, working-tree file or repository object was changed.