Stage the Right Changes with git add
You will finish with the intended files, or only the intended parts of files, staged for a Git commit. The examples use Git 2.43.0, installed here from the git and git-man packages. Allow about 10 minutes for the first run. You need a Git working tree and ordinary write access to it; none of these commands needs sudo.
The route
Jump straight to the step you need, or tick off Done means at the end.
1. Check where you are and what would change
Run this before staging anything. It separates the working tree from the index, which is Git's staging area.
$ git rev-parse --show-toplevel
/path/to/project
$ git status --short
M src/report.py
?? notes.txt
In the short status format, ?? is an untracked file. A leading M means the index differs from the last commit; a trailing M means the working tree differs from the index. Read both columns rather than assuming that every modified file is already ready to commit.
Checkpoint
Identify the exact path or paths you intend to stage. If git rev-parse says this is not a repository, change to the correct directory or clone the project first. Do not initialise a new repository in a directory that contains the wrong project.
2. Stage one file or a named set of files
Give git add an explicit path when you want a narrow, predictable change. It records the file's content at the moment the command runs; later edits are not automatically included.
$ git add -- src/report.py notes.txt
$ git status --short
M src/report.py
A notes.txt
The double hyphen ends options. It is useful for a filename beginning with a hyphen, and it makes the boundary between options and paths obvious. A staged new file is shown as A in the first status column. If you edit src/report.py again, run git add -- src/report.py again to stage that later version.
For a directory, git add -- path/to/directory updates files below it, including removals. For the whole working tree, git add --all adds, modifies and removes entries everywhere. Treat that command as a broad state change: review the result before committing.
3. Review exactly what is staged
Status tells you which paths changed. The staged diff tells you what the next commit would contain.
$ git diff --cached --stat
src/report.py | 2 +-
notes.txt | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
$ git diff --cached -- src/report.py notes.txt
git diff without --cached compares the working tree with the index instead, so it answers a different question: what have you changed since staging? Use both views when you are preparing a commit with more edits still in progress.
Checkpoint
Stop if the cached diff contains credentials, private data, generated files or unrelated work. Staging does not publish anything, but a later commit or push may make those contents difficult to retract.
4. Stage only selected hunks
Use patch mode when one file contains several unrelated changes. Git presents each hunk and asks whether to stage it.
$ git add --patch -- src/report.py
diff --git a/src/report.py b/src/report.py
@@ ...
Stage this hunk [y,n,q,a,d,s,e,?]?
Use y for this hunk, n to leave it unstaged, s to split a separable hunk, and q to stop. Press ? at the prompt for the complete list. When the command ends, inspect the result:
$ git diff --cached -- src/report.py
$ git diff -- src/report.py
The first command is the proposed commit; the second is the remaining local work. This is a useful stopping point when you need to make a focused commit without hiding unfinished work.
5. Deal with ignored or missing files deliberately
Git ignores files matched by its ignore rules. An explicit ignored path fails rather than silently staging it:
$ git add -- .env
The following paths are ignored by one of your .gitignore files:
.env
Do not use force as a reflex. First check why the file is ignored and whether it contains a secret or machine-specific data. If it is genuinely safe and intentionally versioned, use the narrow command git add --force -- .env.example for the appropriate path, then inspect the cached diff. Never stage a real secret merely to make an error disappear.
To test paths without changing the index, use a dry run:
$ git add --dry-run -- path/to/file
add 'path/to/file'
A dry run is an inspection tool, not a substitute for reviewing content. Use git check-ignore -v -- path/to/file when you need the rule responsible for an ignored path.
6. Undo accidental staging without losing work
If the file is staged but the working copy is correct, remove it from the index while retaining the working-tree changes:
$ git restore --staged -- src/report.py
$ git status --short
M src/report.py
This undo command changes the index, not the file on disk. The older spelling git reset HEAD -- path/to/file is also common, but git restore --staged states the intended operation more clearly. If you need to discard working-tree edits as well, stop and make a backup first: that is a separate, destructive action and is not required to undo staging.
7. Know the less common modes
git add --update -- path/to/filestages modifications and removals for paths already tracked; it does not add new files.git add --intent-to-add -- new-filerecords that a path is intended for a later addition while leaving its content unstaged, which makes the file appear in ordinary diffs.git add --renormalize --allreapplies clean filters to tracked files after changing line-ending configuration. Review the resulting diff carefully.git add --chmod=+x -- script.shchanges the executable bit in the index only; it does not change the file's permissions on disk.
Use git add --sparse only when you understand the sparse-checkout boundary. Without it, Git protects paths outside the sparse-checkout cone from being updated accidentally.
Done means
git status --shortshows the intended paths in the first column.git diff --cachedcontains exactly the change you mean to commit.- Any remaining output from
git diffis unfinished work you have consciously left unstaged. - Ignored files were investigated, not force-added by habit.
- You know that a later edit requires another
git addbefore committing.