Skip to content
Foxipa

Suggest an edit

Tell us what should be corrected, clarified, or improved. Submission will be connected to Foxipa’s contribution service later.

No information is sent anywhere yet. Your suggestion is only prepared in your browser.

Learning

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.

Levels: Advanced ~30 min read

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.

bash
git write-tree

A 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.

bash
git ls-files --unmerged
git write-tree

Resolve 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.

bash
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

bash
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.

bash
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.

bash
git write-tree --missing-ok

How 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.

bash
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.

bash
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.

Was this page helpful?

Mark this learning resource complete to track your learning progress.