Home / Alt manpages / git-write-tree(1)

  • git-write-tree(1)
  • User command
  • linux

Turn the Git Index into a Tree with git write-tree

You will finish with a tree object ID made from a Git index, know when that ID is stale, and be able to inspect the tree without creating a commit. The examples were tested with Git 2.43.0 from the git-man package version 1:2.43.0-1ubuntu7.3.

Allow about fifteen minutes. You need Git and a repository where you can make a temporary commit-free change. The command is ordinary user-level plumbing: it normally needs no sudo, and it does not publish anything or move a branch.

1. Check the installed command

Start in the repository whose index you want to snapshot. Confirm the executable and version before relying on output in a script:

$ command -v git
/usr/bin/git
$ git --version
git version 2.43.0
$ git write-tree -h
usage: git write-tree [--missing-ok] [--prefix=<prefix>/]

The command reads the index, not an arbitrary scan of the working directory. It prints one tree object name on standard output. A tree is Git's directory-shaped object: it records paths, modes and references to blobs or nested trees. It is not a commit and has no author, message or parent.

2. Put the desired content in the index

Use the normal index workflow first. In this example, only tracked.txt is staged:

$ printf 'one\n' > tracked.txt
$ git add -- tracked.txt
$ git status --short
A  tracked.txt

Checkpoint: the path must appear in the index column of git status --short. An entry shown only in the working-tree column is not part of the tree that git write-tree will create. If this is a real repository, do not run the example blindly over valuable unstaged edits. Stage only the paths you intend to include.

3. Write the tree and capture its ID

Run the command without options:

$ tree_id=$(git write-tree)
$ printf 'tree: %s\n' "$tree_id"
tree: f46a6a9d2d0dfeb46eba9132c1a874fd01cd776f

Your object ID will differ. It is a 40-character SHA-1 name in this repository format. The command may create the tree object in Git's object database, but it does not alter the index, working files, current branch or commit history.

Verify what was written by asking Git to list the tree:

$ git ls-tree "$tree_id"
100644 blob 7f...    tracked.txt

The blob ID and spacing vary. The useful check is that the expected path and file mode are present. To check the tree object type independently, use:

$ git cat-file -t "$tree_id"
tree

4. Understand the index boundary

git write-tree does not notice a file edit that has not been staged. Change the working file, then write another tree without updating the index:

$ printf 'two\n' > tracked.txt
$ stale_id=$(git write-tree)
$ printf '%s\n' "$stale_id"
f46a6a9d2d0dfeb46eba9132c1a874fd01cd776f
$ git diff -- tracked.txt
diff --git a/tracked.txt b/tracked.txt
...

The ID remains the same because the index still contains one. This is the most common distraction trap: the working directory looks current, while the index is the input snapshot. If the tree should contain the new content, update the index and run the command again:

$ git add -- tracked.txt
$ current_id=$(git write-tree)
$ test "$current_id" != "$stale_id" && echo "tree changed"
tree changed

There is no undo operation for writing a tree object. That is normally harmless because unreachable objects can later be collected. To undo the example's file edit, restore it from the index only if you are certain the edit is disposable:

$ git restore --worktree -- tracked.txt

This restore is destructive to the unstaged edit. Do not use it as a routine verification command; copy or commit valuable work first.

5. Stop on an unmerged index

The index must be fully merged. During a conflict, the index can hold stage 1, 2 and 3 entries for one path. In that state, git write-tree refuses to build a normal tree and exits non-zero:

$ git write-tree
conflict.txt: unmerged (...)
fatal: git-write-tree: error building trees

The object IDs in the diagnostic vary. Check the state before investigating anything else:

$ git status
$ git ls-files --unmerged

Resolve the conflict using your normal merge workflow, then stage the resolved file. Confirm that git ls-files --unmerged prints nothing before trying again. Do not bypass a conflict merely to obtain an object ID: the resulting tree would not represent a settled index.

6. Write a subtree with --prefix

Use --prefix=SUBDIRECTORY/ when you need the tree representing one directory rather than the repository root. The prefix must describe the subdirectory in the index:

$ git add -- sub/value
$ subtree_id=$(git write-tree --prefix=sub/)
$ git ls-tree "$subtree_id"
100644 blob ...    value

The resulting tree is useful when a larger process needs the contents of a subproject or directory. It is not a new checkout and it does not remove the prefix from the index. If the path does not exist in the indexed data, expect an error rather than an invented empty directory.

7. Treat --missing-ok as an expert option

By default, Git checks that objects referenced by the index exist in the object database. --missing-ok disables that check. This is for specialised plumbing workflows where an incomplete object database is intentional; it is not a repair switch for an ordinary repository.

Do not add --missing-ok just because the normal command fails. First check the repository and the index, and keep the default integrity check when producing a tree for a commit or another tool. A tree that names missing objects may be unusable to readers that later need those objects.

Done means

  • The intended paths are staged, and you understand that the index is the input.
  • git write-tree returned a tree ID without elevated privileges.
  • git ls-tree shows the expected paths and git cat-file -t reports tree.
  • You checked for unmerged entries before treating the result as valid.
  • You used --prefix only for an indexed subdirectory and left --missing-ok off unless an expert workflow requires it.
  • No commit, branch, working file or remote was changed by the tree-writing step.