Unstaging an accidental add
You staged too many files. Run git restore --staged <file> to reset the index entry to HEAD while keeping your edits in the working tree.
Git · Command
git restore puts selected paths back to the content held in a restore source. It can undo working-tree edits, unstage changes, or bring back a file as it was in an older commit.
Last updated
The command copies content from a source to a location. The location is the working tree (-W/--worktree, used when you give neither flag), the index (-S/--staged), or both. If you don't pass --source, the source is the index when only the working tree is restored and HEAD when --staged is given. --source=<tree> lets you pick any commit, branch or tag instead. Pathspecs choose which files are affected. By default it runs in no-overlay mode, so the result matches the source exactly, and that can mean deleting files.
git restore [<options>] [--source=<tree>] [--staged] [--worktree] [--] <pathspec>…| Name | Type | Description |
|---|---|---|
-s <tree>, --source=<tree> | tree-ish | Tree to take content from. Defaults to HEAD when --staged is given, otherwise the index. |
-W, --worktree / -S, --staged | flag | Where to restore: the working tree (the default), the index, or both. |
-p, --patch | flag | Choose hunks interactively. |
--ours / --theirs | flag | For unmerged paths, take stage #2 or stage #3 from the index. |
-m, --merge / --conflict=<style> | flag / merge|diff3|zdiff3 | Recreate the conflicted merge for unmerged paths, optionally with a specific conflict style. |
--overlay / --no-overlay | flag | Whether tracked files missing from the source are removed (no-overlay is the default). |
--pathspec-from-file=<file>, --pathspec-file-nul | file | Read pathspecs from a file or from stdin (-), optionally separated by NUL characters. |
<pathspec>... | pathspec | Limits which paths are affected. |
set -e
cd "$(mktemp -d)" && git init -q demo && cd demo
git config user.email you@example.com && git config user.name You
echo v1 > app.txt && git add app.txt && git commit -qm v1
echo v2 > app.txt && git commit -qam v2
# Stage an edit, then unstage it (index <- HEAD)
echo draft > app.txt && git add app.txt
git restore --staged app.txt
# Discard the working-tree edit (worktree <- index)
git restore app.txt
# Bring back the v1 content into both index and worktree
git restore --source=HEAD~1 --staged --worktree app.txt
cat app.txt # v1
git status --shortThe script unstages a change, throws away a working-tree edit, and then pulls an older version of the file into both the index and the working tree.
You staged too many files. Run git restore --staged <file> to reset the index entry to HEAD while keeping your edits in the working tree.
A recent commit broke the Makefile. Restore just that file from master~2 without touching the rest of the code.
You got a manual merge resolution wrong. Run git restore --merge (or --conflict=zdiff3) on the file to get the conflict markers back and start over.
Use git restore -p to drop only the debugging hunks and keep the rest of your changes.
Without flags, only the working tree is written, and it is filled from the index, so you lose unstaged edits. With --staged, only the index is written, and the default source becomes HEAD. That unstages the file but leaves its working-tree content alone.
Follow-up: How do you discard both staged and unstaged changes to one file? Use git restore --source=HEAD --staged --worktree <file>, or the short form git restore -s@ -SW <file>.
The docs say git restore --staged <path> does the same as git reset on that path. Restoring the index and working tree from HEAD does the same as git checkout on that path. git restore handles only files, never branches, so it separates out the file-restoring part of checkout.
Follow-up: Why can't you use --ours with --source? Stages #2 and #3 exist only in the index while a merge is unresolved, and a tree-ish passed to --source has no such stages.
No-overlay mode is the default. In that mode, tracked files that are missing from the source tree are removed so that the location matches the source exactly. Pass --overlay if you want files that aren't in the source to stay.
Follow-up: Why quote '*.c' when running git restore? With quotes, Git matches the pattern against index entries, so files you deleted from the working tree are restored too. If the shell expanded the glob, those files would be missed.
git-checkoutgit-resetgit-switchgit-addgit-revertgitglossary