Table of Contents

Introduction

If you've used Git for more than a day you've typed git add hundreds of times, probably as git add . without thinking about it. The staging area it feeds is the part of Git that most other version control systems don't have, and it's the reason new users find the add-then-commit dance strange.

In this article, we'll:

  1. Watch git add move two files into the staging area on a small repository
  2. Look at what git status says before and after
  3. Cover what the staging area is actually for, and the forms of add worth knowing

What is git add?

git add <file> takes the current contents of a file from your working directory and records them in the staging area (the index). It also stores that content as a blob in Git's object database right then, which is why a staged file is already safe in .git even before you commit.

The next git commit records whatever the staging area holds. Anything you edited but didn't add stays out of the commit.

Watch it happen

Our sample repo has a modified tracked file and a new untracked file, plus a README.md change that was staged earlier. Here's git add app.py notes.txt:

  1. Before: README.md is already staged, app.py is tracked and modified in the working tree, and notes.txt is untracked.
  2. Git adds app.py and notes.txt to the index, so both are now staged. For notes.txt this is the first time Git has recorded it at all.
  3. README.md stays staged as it was. No commit is created and no branch moves, because nothing has been committed yet.

Before and after

git status --short before the command:

M  README.md
 M app.py
?? notes.txt

and after:

M  README.md
M  app.py
A  notes.txt

The M for app.py jumped from the second column (working directory) to the first (staging area). notes.txt went from ?? to A, for added. The commit graph itself doesn't change, because nothing has been committed yet:

The raw git output, if you want to read along in text

git log --oneline --graph --all

before

* 1117a34 (feature) Add search tests
* e5869f0 Fix typo in search box
* fc19889 Add search box
| * 8c02d5b (HEAD -> main) Update dependencies
| * a0b2db3 Add user settings page
|/  
* 96c4fc2 Fix header layout
* ae65976 Add login page
* 3e1ffe4 Add project skeleton
* 4114b2c Initial commit

after

* 1117a34 (feature) Add search tests
* e5869f0 Fix typo in search box
* fc19889 Add search box
| * 8c02d5b (HEAD -> main) Update dependencies
| * a0b2db3 Add user settings page
|/  
* 96c4fc2 Fix header layout
* ae65976 Add login page
* 3e1ffe4 Add project skeleton
* 4114b2c Initial commit

Why is there a staging area?

The honest answer is that it lets you commit less than everything you've changed. Say you fixed a bug and, while you were in there, also reformatted a file. git add bugfix.py and then git commit gives you a commit with only the fix in it. The reformat waits for its own commit. Without a staging area, you'd have to undo the reformat, commit, and redo it.

The other thing it buys you is git add -p, which walks through each changed hunk in a file and asks whether to stage it. That lets you split even a single file's changes across two commits.

In Git's first version the staging area was called the "directory cache" and the command to add to it was update-cache. Linus built the index on day one, before there was even a commit command in the modern sense. It's one of the few pieces of the original design that's still there in the same shape.

Is it safe?

Safe git-sim pre-flight

'add' stages files; nothing is discarded.

add only writes. It creates blobs in the object database and updates the index. Nothing is removed or overwritten, so there is no version of git add that loses work.

Useful forms

  • git add . stages everything under the current directory, new files included.
  • git add -A stages everything in the whole repository, including deletions.
  • git add -u stages changes to tracked files only, skipping new files.
  • git add -p stages interactively, hunk by hunk. The git add documentation covers its prompts and every other option.

How to undo it

To take a file back out of the staging area and keep your edit in the working directory:

git restore --staged app.py

Here is what that looks like on the same repository:

The older spelling git reset HEAD app.py does the same thing.

Try it on your repository

pip install git-sim
git-sim add app.py notes.txt

git-sim draws your working directory, staging area and last commit as three columns and shows which files would move, so git add . stops being a surprise.

Common questions

What does git add actually do?

It copies the current contents of the named files into the staging area and stores those contents as blobs in the object database. The next commit records what the staging area holds.

What is the difference between git add . and git add -A?

git add . stages changes under the current directory. git add -A stages changes across the whole repository regardless of where you run it. In the repository root, with a modern Git, the two are the same.

Does git add commit my changes?

No. It only stages them. git commit is what records them in history.

How do I unstage a file?

git restore --staged <file>, or the older git reset HEAD <file>. Both leave the edit in your working directory.

Summary

In this article, we watched git add move a modified file and a new file into the staging area, compared git status before and after, and looked at why Git has a staging area in the first place.

Next steps

git commit is the other half of this. And if git add . has ever grabbed something you didn't mean to commit, git restore --staged is the fix.