Skip to content
masterclass Buddy

Git · Concept

Working tree

The working tree is the directory of real, checked-out files that you edit. It usually starts from the tree of the HEAD commit and also holds any local changes you have not committed yet.

Last updated

How it works

Git keeps history as compressed objects inside the repository, but you work on ordinary files on disk. When you check out a branch or commit, Git writes that commit's tree into your working directory and records it in the index. After that, you can edit files freely. Git finds your changes by comparing the files on disk with the index and with HEAD. When the files match the commit HEAD points to, the working tree is clean. Once you make edits that are not committed, it is dirty. A non-bare repository has one main working tree. git worktree can attach more working trees, and each one has its own HEAD and index.

Key points

  • The glossary defines the working tree as the set of files that are actually checked out, as opposed to objects stored in the repository database.
  • The index sits between your files on disk and the next commit. It stores a snapshot of the working tree, and during a merge it can hold more than one version of a file.
  • A bare repository has no working tree. It holds only the files Git uses to manage the repository, which is why servers usually host bare repositories.
  • The :/ pathspec magic (top) matches paths from the root of the working tree, even when you run a command from inside a subdirectory.
  • A working tree's top level can contain a plain .git file (a gitfile) that points to the real repository directory instead of a .git folder. Linked worktrees and submodules use this.

Common mistakes

  • By default, checking out files from the index or a tree-ish only adds or updates files. In no-overlay mode, Git also deletes tracked files that are missing from the source, so you can lose files you did not expect to.
  • When an attr: pathspec is matched against a tree object, Git still reads the attributes from the working tree, not from that tree object. Results can change if your local .gitattributes differs.
  • Changes you have made but not committed make the working tree dirty. Some operations refuse to run or need --force when the tree is dirty. For example, git worktree remove only works on clean worktrees unless you force it.

Example: Watching the working tree go from clean to dirty and back

#!/usr/bin/env bash
set -euo pipefail
cd "$(mktemp -d)"
git init -q demo && cd demo
git config user.email you@example.com
git config user.name You

echo 'hello' > greet.txt
git add greet.txt
git commit -qm 'initial'
git status --short   # nothing printed: working tree is clean

echo 'world' >> greet.txt   # edit a file on disk
git status --short          # ' M greet.txt' -> working tree differs from index
git diff                    # shows working tree vs index

git restore greet.txt       # copy the index version back into the working tree
git status --short          # clean again

git rev-parse --show-toplevel   # prints the root of the working tree

The script edits a committed file, uses git status and git diff to show that the working tree is now dirty, and then runs git restore to make it clean again.

When to use it

Checking state before risky commands

Before you rebase, switch branches, or reset, run git status to find out whether the working tree has uncommitted edits. If it does, commit or stash them first so nothing gets overwritten.

Working on two branches at once

An urgent fix comes in while you are halfway through a refactor. Use git worktree add to create a second working tree on another branch, so you do not have to disturb the files you are already editing.

Running commands from a subdirectory in scripts

A build script runs from somewhere deep in the project. It can use git rev-parse --show-toplevel or :/ pathspecs so its paths are resolved from the root of the working tree.

Interview questions

QHow do the working tree, the index and HEAD differ?

HEAD names the commit you are on, usually through the current branch. The index is a stored snapshot that will become the next commit. The working tree holds the editable files on disk. It normally matches HEAD's tree plus any uncommitted edits you have made.

Follow-up: What do git diff, git diff --cached and git diff HEAD each compare? git diff compares the working tree with the index. git diff --cached compares the index with HEAD. git diff HEAD compares the working tree directly with HEAD.

QWhat makes a working tree clean or dirty, and how do you check?

A working tree is clean when its contents match the revision referenced by the current head. It is dirty when it has modifications that have not been committed to the current branch. git status shows this by listing staged changes, unstaged changes and untracked files.

Follow-up: Why can git status look clean even though untracked build files exist? Files that match .gitignore patterns are ignored, so git status does not list them. You can see them with git status --ignored.

QCan a repository have zero working trees, or more than one?

Yes, both. A bare repository has no working tree, and a normal repository has one main working tree. git worktree add can attach more linked worktrees, each with its own HEAD and index, while they all share the same object database and refs.

Follow-up: Why does Git refuse to check out the same branch in two worktrees by default? If two working trees had the same branch checked out, a commit in one would move that branch under the other and leave it out of sync. git worktree add only allows it with --force.

  • index
  • HEAD
  • checkout
  • clean
  • dirty
  • worktree
  • bare repository
  • gitfile

Source: Git - gitglossary Documentation. Checked 2026-11-02.