By admin , 28 April 2026

Introduction

Every Git operation moves data between three areas: the working tree (your files), the index (next commit's draft), and the repository (committed history under .git). Naming what moves where is the single most useful mental model.

The areas

  • Working tree: the directory you edit in.
  • Index: .git/index, the staged tree.
  • Repository: objects in .git/objects plus refs in .git/refs.

Commands by direction

# working tree -> index
git add file
git rm file
git mv old new

# index -> repository
git commit
git write-tree   # plumbing

# repository -> index
git reset <commit>
git read-tree <tree>

# repository -> working tree (and usually index)
git checkout <commit> -- file
git restore --source <commit> file
git switch <branch>

The four diffs

You can compare any two areas:

git diff                  # working tree vs index
git diff --staged         # index vs HEAD
git diff HEAD             # working tree vs HEAD
git diff main feature     # repository vs repository

Status decoded

git status -s
# XY filename
# X = index status, Y = working tree status
# M modified, A added, D deleted, R renamed, ?? untracked

For example MM means modified in both index and working tree (you staged a change and then edited again).

Reset, restore, checkout

Each affects different areas:

  • git reset --soft: only repository (move ref).
  • git reset (mixed): repository + index.
  • git reset --hard: repository + index + working tree.
  • git restore --staged: index from HEAD.
  • git restore: working tree from index.
  • git restore --source=<commit>: working tree (and optionally index) from a specific commit.

An exercise

echo a > f.txt
git add f.txt
git commit -m "v1"
echo b >> f.txt
git add f.txt
echo c >> f.txt
git status
git diff
git diff --staged
git diff HEAD

Read each diff; understanding why they differ cements the model.

Plumbing for each area

Knowing the plumbing for each area demystifies higher-level commands:

  • Working tree: ordinary filesystem operations.
  • Index: git update-index, git ls-files, git read-tree, git write-tree.
  • Object database: git hash-object, git cat-file, git mktree, git commit-tree.
  • Refs: git update-ref, git symbolic-ref, git for-each-ref.
git ls-files --stage              # index
git ls-tree HEAD                  # repo
ls -R                             # working tree

Common mistakes

Trying to memorize commands instead of areas; once you know which area is the source and which is the destination, the right command is obvious. Conflating git restore file with git checkout file; they are equivalent for that case, but checkout's many other modes confuse new users. Using git reset --hard to "clean up" without realizing it nukes the working tree. And finally, expecting git commit to include unstaged edits; it does not (unless you pass -a for tracked files only).