Technology git restore

Learn with diagrams, code, systems and practical examples.

</>
Git · local-state recovery

git restore: decide which local state should change before you touch the file

Restore changes file content in the working tree, the index, or both without moving branch history. The key safety question is not “which undo command?” but “which state do I want this path to match?”

gitversion controlrestoreworking treestaging areaindex
1 · Inspect the state

Separate HEAD, index, and working tree before you restore anything

  • Run git status to identify staged versus unstaged paths.
  • Use git diff for working-tree changes and git diff --staged for index changes before deciding what is disposable.
  • State the desired transition in words: “unstage but keep edits,” “discard unstaged edits,” or “recover this path from commit X.”
  • Use --patch when only some hunks are unwanted; do not replace a whole file just because the command is shorter.
2 · Predict before running

Which layer will change?

Think first

README.md has edits in the working tree and you already staged them. If you then change README.md again and run git restore README.md, which version remains: HEAD, the staged version, or the newest unstaged edit?

Reveal the reasoning

The working-tree copy is restored from the index by default, so it becomes the staged version. The index remains staged. A plain restore does not move HEAD and does not unstage the file.

Restore, revert, or reset?

Choose by the state transition you actually need

restore

Change path content in the working tree, index, or both without moving branch history.

revert

Add a corrective commit when published history should remain intact.

reset

Change the index or move HEAD when private-history state itself needs to change.

3 · Run deliberately

Options that change the destination or source

--staged

Restore the selected path in the index. Without an explicit --source, the source defaults to HEAD.

Unstaging selected changes while keeping the working-tree edits available for further work.
--worktree

Restore the selected path in the working tree. This is the default destination when --staged is not supplied.

Replacing local tracked-file content with the chosen source after you have verified the local edits are disposable.
--source=<tree>

Choose the commit, branch, tag, or other tree whose content should become the restore source.

Recovering a file version from a known commit rather than simply matching the index or HEAD.
-p, --patch

Interactively choose individual hunks to restore instead of replacing every change in the path.

Keeping some local edits while discarding only selected hunks.
--staged --worktree

Restore both the index and working-tree copy of the selected path.

Only when you deliberately want both local states to match the chosen source, typically after inspecting what will be discarded.
Worked examples

Move one layer at a time

Beginner: unstage a file but keep the edits

You staged config/app.yml too early. The edits are still useful, but you do not want them in the next commit yet.

git status
git diff --staged -- config/app.yml
git restore --staged config/app.yml

--staged updates the index entry from HEAD by default. The working-tree copy stays edited, so the change becomes unstaged rather than disappearing.

Expected shape: git status shows config/app.yml under Changes not staged for commit.

Practical: discard one tracked file’s unstaged edits

A generated local edit to src/theme.css is definitely unwanted. You have inspected the diff and want the working copy to match the staged/index version again.

git diff -- src/theme.css
git restore src/theme.css

Without --staged, restore targets the working tree and uses the index as the default source. The unstaged tracked-file edits are replaced, so inspect the diff first.

Advanced: recover one file from a known earlier commit

A refactor changed many files, but you want docs/diagram.md to match commit 4f2c1ab while leaving the branch pointer and other files alone.

git show 4f2c1ab:docs/diagram.md
git restore --source=4f2c1ab --worktree -- docs/diagram.md
git diff -- docs/diagram.md

The explicit source makes the intended file state inspectable. Only the selected working-tree path changes; HEAD and branch history stay where they are.

Selective: discard only some hunks

A file contains one accidental formatting change and one useful bug fix. You want to keep the bug fix.

git diff -- src/parser.ts
git restore -p -- src/parser.ts

Patch mode asks about individual hunks so you can reverse only the unwanted parts instead of replacing the entire file.

4 · Verify and recover

When restore would discard the wrong state, stop before execution

The most important restore recovery skill is prevention. Local edits that were never committed or stashed may not have an easy Git recovery path after they are overwritten.

  1. Read all local layers

    Inspect repository state plus both unstaged and staged diffs before choosing a restore destination.

    git status
    git diff
    git diff --staged
  2. Inspect an explicit historical source

    If you plan to restore from a commit, view that file from the source first so the incoming content is not a surprise.

    git show <commit>:<path>
  3. Prefer the narrowest change

    Restore one path or use patch mode instead of applying a broad worktree/index replacement.

  4. Verify immediately

    After restoring, repeat status and the relevant diff so the result is proven before additional edits hide what happened.

    git status
    git diff
    git diff --staged
  5. Use history-oriented tools for history problems

    If the recovery goal involves a published commit or moving private HEAD, stop using restore and inspect revert or reset instead.

Common mistakes

Failure modes worth recognizing

Running git restore on a tracked file before inspecting the diff

A plain working-tree restore can remove local edits. Git is doing exactly what was requested even if those edits were valuable.

Recovery: Inspect with git diff first. If the discarded content was never committed or stashed, recovery may be difficult or impossible, so treat inspection as the safety step rather than relying on an undo afterward.

Confusing --staged with “delete my changes”

git restore --staged normally changes the index while leaving the working-tree file edited. It is an unstaging operation, not the same as discarding the file edit.

Recovery: Run git status plus git diff and git diff --staged to verify which layer still contains the change.

Using restore when the real problem is branch history

Restore changes paths in the working tree/index; it does not move HEAD, erase commits, or add an auditable inverse commit.

Recovery: If you need to preserve shared history while undoing a published commit, consider git revert. If private branch history itself must move, inspect git reset deliberately.

Restoring both --staged and --worktree without naming the source mentally

Changing both layers can remove both staged and unstaged variants of the selected path. The operation is much easier to reason about when you state the desired source explicitly.

Recovery: Before running the command, say “make both copies match HEAD” or name another source, inspect the existing diffs, then run the exact restore you intend.
Guided practice

Predict the local-state transition before revealing it

You staged src/api.ts, then realized it needs one more edit before the commit. You want to remove it from the index but keep every working-tree change. What should you inspect and run?

Hint

The destination you want to change is the index, not the working tree.

Reveal command and reasoning
git status
git diff --staged -- src/api.ts
git restore --staged src/api.ts
git status

The staged diff proves what is in the index. --staged restores that index entry from HEAD by default while leaving the working-tree content available for continued editing.

Independent practice

Build intuition across HEAD, index, and working tree

In a disposable repository, edit one tracked file and stage it. Edit it again so staged and unstaged versions differ. Predict and test plain git restore, git restore --staged, and git restore --source=HEAD --staged --worktree on separate disposable copies or repeated reset setups. Finish by using git restore -p to discard one hunk while keeping another, and explain which layer changed after each operation.

FAQ

Questions that change the recovery choice

What does plain git restore <file> restore from?

When --staged is not used, the working tree is the default destination and the index is the default source. That means a plain restore usually discards unstaged changes in a tracked file so it matches the staged/index version.

How do I unstage without losing my edits?

Use git restore --staged <path>. By default the index entry is restored from HEAD while the working-tree file remains edited.

How is restore different from reset?

Restore is path-focused and works on the working tree/index without moving branch history. Reset can move HEAD in commit mode and can also update the index. Choose based on the state you intend to change, not on which command sounds like “undo.”

How is restore different from revert?

Restore changes local file/index state and does not create a corrective commit. Revert preserves published history by adding a new commit whose patch reverses an earlier commit.

Can I restore only part of a file?

Yes. Use git restore -p <path> to select hunks interactively. Inspect the diff first so each decision is tied to a known local change.

Next step

Choose undo tools by the state transition, not the word “undo.”

After restore, compare it directly with revert and reset. Restore changes path state, revert adds corrective history, and reset can move history. Being able to name that difference is more valuable than memorizing isolated command recipes.