Skip to content
masterclass Buddy

Git · Concept

Staging area

The staging area, which Git also calls the index, is one of Git's four core kinds of data. It holds the exact file snapshot your next commit will record, so you can choose what goes into a commit separately from what is in your working directory.

Last updated

How it works

Each index entry has four fields: a file type (regular, executable, symlink or gitlink), the ID of the blob holding the file's contents, a stage number and a path. Running git add stores the file's current content as a blob and points the entry at it. When you commit, Git turns this flat list of paths into nested tree objects and records that tree in the new commit. That means a commit holds whatever is staged, not whatever is on disk. During a merge conflict, one path can have several entries with stage numbers 1 to 3.

Syntax

git add [<options>] [--] [<pathspec>…]

Key points

  • Unlike a tree object, the index has no nested directories. It is a single flat list of paths, and Git only builds the directory trees at commit time.
  • The stage number is normally 0. If a merge has a conflict, the same path can appear several times in the index, once for each competing version.
  • You rarely need to read the raw index. Usually you compare it to HEAD with git status, and you can dump its entries (mode, blob ID, stage, path) with git ls-files --stage.
  • You don't have to stage a whole file. git add -p shows each hunk of the difference between the index and the working tree and lets you choose which ones to stage.
  • git add -N (intent-to-add) creates an index entry with no content. The file then shows up in git diff, and git commit -a will pick it up.
  • Some changes exist only in the index. For example, git add --chmod=+x sets the executable bit on the staged entry and leaves the file on disk unchanged.

Common mistakes

  • Staging copies the file's content at that moment. If you edit the file again before committing, the new edits are not included unless you run git add again.
  • Ignored files are skipped. If a glob matches an ignored file, Git skips it without any message. Use --force to stage it anyway.
  • git add -u updates and removes entries for files Git already tracks, but it never stages new untracked files.
  • If you hand-edit a patch with git add -e, the change is applied only to the index. Your working tree can then look as if it undid the staged change.

Example: Stage part of your work and inspect the index

set -e
mkdir demo && cd demo && git init -q
echo 'print("hi")' > hello.py
echo 'notes' > TODO.txt

# Stage only hello.py
git add hello.py
git status --short        # A  hello.py / ?? TODO.txt

# Look at the raw index entries: mode, blob id, stage, path
git ls-files --stage

# Edit after staging: the new edit is NOT staged
echo 'print("bye")' >> hello.py
git diff                  # working tree vs index
git diff --cached         # index vs HEAD (what will be committed)

# Commit records only the staged snapshot
git commit -qm 'Add hello.py'
git status --short        # ' M hello.py' and '?? TODO.txt' remain

The script stages one file, lists the index entries, then shows that an edit made after staging stays out of the commit until you run git add on that file again.

When to use it

Splitting work into focused commits

You fixed a bug and refactored code in the same file. You use git add -p to stage only the bug-fix hunks, commit them, and then stage and commit the refactor separately.

Resolving merge conflicts

After a conflicted merge, the index holds several stage entries for each conflicted path. Once you have edited a file to remove the conflict markers, you stage it to mark it as resolved, then you commit.

Reviewing exactly what will be committed

Before you commit, git diff --cached shows the difference between HEAD and the index, so you can check that only the intended changes go in.

Interview questions

QWhat is the Git index and what does it actually store?

The index, also called the staging area, is a flat list of entries. Each entry has a file type, a blob ID for the contents, a stage number and a path. git add writes the file's contents as a blob and updates the entry, and git commit converts the list into tree objects for the new commit.

Follow-up: Why is the index a flat list instead of a tree? A flat list of full paths is easy to update one file at a time, and Git only builds the nested trees when it creates a commit.

QIf you run git add on a file, edit it again, and then commit, what gets committed?

The version you staged gets committed. git add records the content at the moment you run it, and git commit with no arguments commits only what is staged. The later edit stays unstaged until you run git add on the file again.

Follow-up: How would you see both sets of changes? git diff --cached shows staged changes (index vs HEAD), and plain git diff shows unstaged edits (working tree vs index).

QHow does the index represent a merge conflict?

Each entry has a stage number. Normally it is 0, but when a merge conflicts, the same path can have several entries with stages 1, 2 and 3 for the different versions. Running git add on the resolved file replaces them with a single entry.

Follow-up: What does git add --resolved do differently? It stages only unmerged paths that no longer contain conflict markers, and if any matching path still has markers, it refuses to stage anything.

  • git-add
  • git-commit
  • git-status
  • git-diff
  • git-restore
  • git-reset
  • git-rm
  • git-ls-files

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