Gitgit restore

git restore

git restore is the modern, single-purpose command for moving content between trees in the safe direction — from the index or repository back into your working directory, or from the repository back into the index. It does not move history; it does not move the branch pointer. It just rewrites files.

What restore actually does

Restore copies content backwards through the trees

Text
Repository (HEAD) ──┐
                    │   --source=HEAD --staged
                    ▼
   Staging area  ──┐
                   │   (default direction)
                   ▼
   Working dir   ◀── what you edit

git restore <file>                         repo/index ─▶ working dir
git restore --staged <file>                repo       ─▶ index (unstage)
git restore --staged --worktree <file>     repo       ─▶ both
Restore the working tree (default)

With no flags, git restore overwrites your working-tree file with whatever is currently in the index (staging area). If you have not staged anything, the index matches HEAD, so this is the same as resetting the file to its last-committed state.

Throw away unstaged edits to a file

Bash
# You edited src/util.js and want your edits gone
git restore src/util.js

# Multiple files
git restore src/util.js src/helpers.js

# Everything in the current directory (and below)
git restore .
Warning
`git restore <file>` **silently discards** your working-tree changes. There is no undo and no reflog entry for working-tree contents — only committed work is recoverable. Stage or stash first if you might want the edits back.
Restore from a specific commit

Use --source to pull the file content from any commit instead of the index. This is how you grab a single file from a previous version without touching the rest of your tree.

Restore from HEAD, a branch, or a SHA

Bash
# Last committed version (overrides index)
git restore --source=HEAD src/util.js

# Version from another branch
git restore --source=main src/config.json

# Version from a specific commit
git restore --source=9c1a2b3 src/util.js

# Version from N commits back
git restore --source=HEAD~3 src/util.js
Unstage a file

--staged flips the target tree from working dir to the index. Restoring the index from HEAD effectively undoes git add — your file is no longer staged, but your edits stay in the working directory.

The unstage recipe

Bash
git add forgotten.txt          # oops, staged by accident

git restore --staged forgotten.txt
# index goes back to HEAD, working dir is untouched

git status
#   Untracked files: forgotten.txt
Restore both at once

Throw away staged + unstaged changes for a file

Bash
git restore --staged --worktree src/broken.js
# Equivalent to: hard reset just this one file back to HEAD
Pattern globs

Restore many files at once

Bash
# All JavaScript files in the project
git restore "*.js"

# All files in a directory
git restore "src/utils/"

# Everything (rarely what you want)
git restore .

# Note: quote globs so your shell does not expand them first
Interactive restore (-p / --patch)

Like git add -p, the patch mode walks you through each chunk of difference and asks whether to restore (throw away) that chunk.

Pick chunks to discard

Bash
git restore -p src/util.js
# Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]?
#   y - discard this hunk
#   n - keep this hunk
#   s - split into smaller hunks
#   q - quit
restore vs the old git checkout

Before Git 2.23 (2019), git checkout did two unrelated things: switch branches and restore files. That was the single most confusing command in Git. The team split it into git switch (branches) and git restore (files). Both spellings still work, but you should prefer the new ones in new code and in tutorials.

Goal

Modern command

Legacy command

Discard unstaged edits

git restore <file>

git checkout -- <file>

Unstage a file

git restore --staged <file>

git reset HEAD <file>

Restore from another commit

git restore --source=<sha> <file>

git checkout <sha> -- <file>

Switch to a branch

git switch <branch>

git checkout <branch>

Restore never touches history
`git restore` only changes file contents in the working directory and/or index. It never moves a branch pointer, never rewrites commits, and never creates new commits. That is what makes it safe.
Tip
Read the command out loud: *“restore (the target) from (the source).”* The default target is the working tree; the default source is the index. Every flag just changes one of those two sides.