How do I discard unstaged changes in Git that are in the working directory but not in the staging area?
Brief Answer
To discard unstaged changes in Git that exist in your working directory but haven’t been staged, you can use either git checkout -- <file>
in older Git versions or git restore <file>
in newer Git versions (2.23+). For discarding all unstaged changes across all files, use git checkout .
or git restore .
respectively.
Contents
- Understanding Git’s Working Directory and Staging Area
- Discarding Unstaged Changes with
git checkout
- Discarding Unstaged Changes with
git restore
- Discarding Changes for Specific Files
- Discarding All Unstaged Changes
- Safety Considerations and Best Practices
- Troubleshooting Common Issues
Understanding Git’s Working Directory and Staging Area
Git uses a three-area model for managing files:
- Working Directory: Your actual files on disk where you make changes
- Staging Area (Index): An intermediate area where you prepare changes before committing
- Repository: The committed snapshots of your project
When you make changes to files in your working directory, they exist as unstaged changes until you explicitly add them to the staging area with git add
. The process of discarding unstaged changes means removing those modifications from your working directory while preserving files that have already been staged.
Key distinction: Staged changes are those you’ve added with
git add
but haven’t yet committed. Unstaged changes are everything else that’s been modified but not added.
Here’s a simple workflow visualization:
Modified file → `git add` → Staged changes → `git commit` → Repository Modified file ← `git checkout/restore` ← (changes discarded)
Discarding Unstaged Changes with git checkout
The traditional method for discarding unstaged changes is using git checkout
. This command has been part of Git for a long time but has different behavior depending on the Git version.
For older Git versions (prior to 2.23), to discard unstaged changes for a specific file:
git checkout -- <file>
To discard unstaged changes for all files:
git checkout .
Important note: The git checkout
command has multiple uses (checking out branches, switching files, etc.), and its behavior can be confusing. In older Git versions, when used with --
and a file path, it specifically discards unstaged changes for that file.
Example workflow:
- Make changes to a file:bash
echo "new content" >> README.md
- Check the status to see unstaged changes:bash
git status # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: README.md
- Discard the changes:bash
git checkout -- README.md
Discarding Unstaged Changes with git restore
Starting with Git version 2.23 (released in November 2019), Git introduced a more explicit command for restoring files: git restore
. This command was created to clarify the often-confusing behavior of git checkout
.
To discard unstaged changes for a specific file with git restore
:
git restore <file>
To discard unstaged changes for all files:
git restore .
The git restore
command is more explicit about its purpose and is now the recommended approach for discarding changes. It also offers additional options for more precise control:
# Restore a specific file from the staging area
git restore --staged <file>
# Restore a file to a specific commit
git restore --source=<commit-hash> <file>
# Restore multiple files matching a pattern
git restore *.js
Example workflow:
- Make changes to multiple files:bash
echo "new feature" > feature.js echo "bug fix" > bugfix.md
- Check the status:bash
git status # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git restore <file>..." to discard changes in working directory) # # modified: bugfix.md # modified: feature.js
- Discard changes for specific files:bash
git restore feature.js bugfix.md
Discarding Changes for Specific Files
When you only want to discard changes for specific files while keeping changes to other files, both git checkout
and git restore
allow you to specify one or more file paths:
# With git checkout
git checkout -- file1.txt file2.txt
# With git restore
git restore file1.txt file2.txt
You can also use glob patterns to match multiple files:
# Discard changes to all .js files
git restore *.js
# Discard changes to all files in the docs directory
git restore docs/*
Practical example:
Imagine you’re working on a project with multiple files and made changes to several of them:
# Make changes to multiple files
echo "console.log('hello');" > app.js
echo "new content" > README.md
echo "fix bug" > utils/bugfix.js
# Check status
git status
# You'll see all three files listed as modified
# Discard changes only to app.js and README.md
git restore app.js README.md
# Check status again
git status
# Now only utils/bugfix.js should appear as modified
Discarding All Unstaged Changes
If you want to discard all unstaged changes across your entire working directory, you can use the following commands:
# With git checkout
git checkout .
# With git restore
git restore .
Important warning: These commands will discard all unstaged changes in your working directory. There is no confirmation prompt, so use these commands with caution.
Step-by-step workflow:
- Make changes to multiple files without staging them:bash
# Create or modify several files echo "temporary change 1" > temp1.txt echo "temporary change 2" > temp2.txt echo "modification" > existing.txt
- Verify the changes are unstaged:bash
git status # You should see all three files listed under "Changes not staged for commit"
- Discard all unstaged changes:bash
git restore .
- Verify the changes are discarded:bash
git status # Should show a clean working directory if no files are staged
Safety Considerations and Best Practices
Discarding changes in Git is a powerful operation, but it comes with risks. Here are some important safety considerations:
1. Backup Important Changes
Before discarding changes, especially when using commands that affect multiple files:
# Create a backup of your current changes
git stash push -m "backup before discard"
You can restore these changes later with:
git stash pop
2. Check What You’re About to Discard
Always check git status
and review the changes with git diff
before discarding them:
# View unstaged changes
git diff
# See which files will be affected
git status --short
3. Use --dry-run
When Available
While Git doesn’t have a built-in dry-run option for checkout/restore, you can simulate the effect:
# See what files would be affected
git diff --name-only
4. Avoid Discarding Changes on Shared Branches
If you’re working on a shared branch (like main or develop), be cautious about discarding changes that others might depend on.
5. Use .gitignore
to Prevent Accidental Changes
Create a .gitignore
file to exclude files or directories that shouldn’t be tracked:
# .gitignore example
*.tmp
.DS_Store
node_modules/
Troubleshooting Common Issues
When working with discarding changes, you might encounter some common issues:
1. “fatal: pathspec ‘’ did not match any files”
This error occurs when you try to discard changes for a file that doesn’t exist or isn’t tracked by Git:
# This will cause an error if the file doesn't exist
git restore non-existent-file.txt
Solution: Verify the file exists and is tracked by Git:
git ls-files <file>
2. “error: Your local changes to the following files would be overwritten by checkout”
This error occurs when you try to switch branches or checkout a commit but have unstaged changes:
# You have unstaged changes but try to switch branches
git checkout other-branch
# Error: Your local changes to the following files would be overwritten by checkout:
# modified-file.txt
Solution: Either discard the changes first or stash them:
# Discard changes
git restore modified-file.txt
# OR stash changes
git stash
# Then switch branches
git checkout other-branch
3. “did you mean ‘restore’ (with two dashes)?”
You might see this warning if you’re using an older version of Git with the restore
command:
warning: git restore is experimental
Solution: Use checkout
instead or upgrade Git to a newer version.
4. Mixed Working Directory and Staging Area
Sometimes you might want to keep staged changes but discard unstaged ones:
# This will discard unstaged changes but keep staged changes
git restore --staged . && git restore .
Conclusion
Discarding unstaged changes in Git is a common operation that can be performed using either the traditional git checkout
command or the more modern git restore
command. Key takeaways include:
- For specific files: Use
git checkout -- <file>
(older Git) orgit restore <file>
(newer Git) - For all files: Use
git checkout .
orgit restore .
- Always check
git status
and review changes withgit diff
before discarding - Consider using
git stash
to temporarily save changes before discarding them - The
git restore
command (Git 2.23+) is now the recommended approach for clarity
Remember that discarded changes are typically not recoverable unless you’ve used git stash
or have other backups. Always be cautious when using commands that affect your entire working directory.