Git write-tree: Turn the Index into Tree Objects
Convert a fully merged Git index into tree objects while understanding subtrees, object validation, and the index-to-object-database boundary.
Advanced
The direction is index → object database
Git's index is a prepared snapshot. `git write-tree` takes that snapshot and creates the tree object hierarchy that represents it. It prints the object name of the top-level tree.
git write-treeA successful result is a tree object ID. You can inspect that object with `git cat-file` or list its entries with `git ls-tree`. The command does not create a commit and does not move a branch.
The index must be fully merged
The current index cannot contain unresolved merge stages when `git write-tree` runs. A conflicted index can contain stages 1, 2, and 3 for the same path; write-tree refuses to turn that unresolved state into an ordinary tree.
git ls-files --unmerged
git write-treeResolve the conflict and update the index first. Once the index contains one resolved entry per path, `git write-tree` can serialize that state into tree objects.
Keep the working tree and index distinction explicit
`git write-tree` reads the index, not arbitrary bytes currently sitting in the working directory. If the working tree changed after staging, write-tree still describes the staged index state. Update the index first when you intend the tree to reflect newer working-tree contents.
printf 'staged\n' > file.txt
git add file.txt
printf 'unstaged\n' > file.txt
git write-tree
git ls-tree $(git write-tree)The resulting tree records the staged version. This is why the official user manual describes `git update-index` as the working-directory-to-index step and `git write-tree` as the index-to-object-database step.
Inspect the tree you just wrote
tree=$(git write-tree)
git cat-file -t "$tree"
git ls-tree "$tree"The tree can contain blobs for files and nested trees for directories. `git write-tree` recursively creates the necessary tree hierarchy from the index; the returned ID identifies the root tree.
`--prefix=<prefix>/`: write a subtree
The `--prefix` option writes the tree object representing a named subdirectory of the index. This is useful when the index contains a larger project but you need the tree for one subtree, such as when constructing a subproject or another low-level object operation.
git write-tree --prefix=sub/The prefix is interpreted as an index path prefix. The resulting tree represents the contents below that prefix rather than the whole top-level index.
`--missing-ok`: deliberately skip object-existence validation
Normally, write-tree verifies that the objects referenced by the index entries exist in the object database. `--missing-ok` disables that validation. This is a plumbing-level escape hatch; it is not a general way to repair an incomplete repository.
git write-tree --missing-okHow this fits with the other tree plumbing
These commands deliberately own different transitions: `git ls-tree` inspects an existing tree, `git mktree` constructs a tree from formatted input, `git read-tree` reads tree information into the index, and `git write-tree` writes the current index back into tree objects. `git commit-tree` can then use a tree object when constructing a commit.
git ls-tree HEAD^{tree}
git read-tree HEAD^{tree}
git write-tree
git commit-tree <tree>The final `git commit-tree` command above is shown only to illustrate the object flow; this lesson does not teach commit construction. Use the dedicated commit-tree material when working with that command.
A reproducible low-level round trip
A useful laboratory is to read an existing commit's tree into the index, write the index back to a tree, and compare the object IDs. For an unchanged, fully merged index, the tree identity should be preserved because Git's tree object is determined by its entries.
git read-tree HEAD^{tree}
original=$(git rev-parse HEAD^{tree})
rewritten=$(git write-tree)
printf '%s\n' "$original" "$rewritten"
test "$original" = "$rewritten"Practice what you learned
Use the dedicated Git code-completion exercise for this lesson.
Quick checks
1. Which repository state does `git write-tree` serialize? 2. Why does an unresolved merge prevent it from writing an ordinary tree? 3. What does `--prefix=sub/` select? 4. What validation does `--missing-ok` disable? 5. Which command performs the reverse object/index direction?
Answers: the current index; unresolved stages cannot be represented as one ordinary tree entry per path; the index subtree below `sub/`; existence checks for referenced objects; `git read-tree` reads tree information into the index.
Thanks for your feedback.
Mark this learning resource complete to track your learning progress.