This Git error occurs when you try to use `git reset --hard` with a specific file path. Git's design intentionally prevents hard resets on individual files. Use `git checkout HEAD -- <path>` or `git restore` (Git 2.23+) to achieve the same effect of discarding local changes for specific files.
The "Cannot do hard reset with paths" error occurs because Git's `reset` command behaves differently depending on whether you specify a path argument. When you run `git reset` **without a path**, it moves the current branch HEAD to a specified commit and optionally resets the index (staging area) and working tree. The `--hard` flag tells Git to reset both the index and working tree to match that commit. When you run `git reset` **with a path**, Git only updates the index (staging area) with the file contents from a commit. It never touches the working tree. This is essentially the opposite of `git add` - it unstages files. The `--hard` and `--soft` flags are designed for branch-level operations that affect HEAD movement, not for path-specific operations. Git intentionally prevents combining these flags with paths because: 1. **Semantic confusion**: A "hard reset" conceptually means resetting everything (HEAD, index, and working tree). Applying this to a single file doesn't match the intended meaning. 2. **Alternative commands exist**: Git provides `git checkout` and `git restore` specifically for updating working tree files to match a commit. 3. **Safety design**: Separating the commands for branch-level vs file-level operations helps prevent accidental data loss.
The traditional way to reset a specific file to its state in HEAD (discarding local changes) is git checkout:
# Reset a single file to HEAD (discard all local changes)
git checkout HEAD -- path/to/file.txt
# Reset multiple files
git checkout HEAD -- file1.txt file2.txt
# Reset all files in a directory
git checkout HEAD -- src/
# Reset all files in current directory
git checkout HEAD -- .The -- separator tells Git that everything after it is a file path, not a branch name. This prevents ambiguity if you have a branch with the same name as a file.
Important: This overwrites your working tree changes for those files. There's no undo.
Git 2.23 introduced the git restore command specifically for restoring working tree files:
# Restore a file to match HEAD (discard working tree changes)
git restore path/to/file.txt
# Restore and also unstage the file
git restore --staged --worktree path/to/file.txt
# Restore from a specific commit
git restore --source=commit_hash path/to/file.txt
# Restore entire directory
git restore src/
# Restore all files in current directory
git restore .The git restore command was created to make these operations clearer than using git checkout, which has many different modes.
Check your Git version:
git --version
# Needs 2.23 or higher for git restoreIf you need to reset a file to a different commit (not HEAD), use the --source option with git restore or specify the commit with git checkout:
# Using git restore (Git 2.23+)
git restore --source=abc1234 -- path/to/file.txt
# Update both index and working tree
git restore --source=abc1234 --staged --worktree -- path/to/file.txt
# Using git checkout (older method)
git checkout abc1234 -- path/to/file.txtYou can also use branch names, tags, or relative references:
# From a branch
git restore --source=main -- path/to/file.txt
# From a tag
git restore --source=v1.0.0 -- path/to/file.txt
# From previous commit
git restore --source=HEAD~1 -- path/to/file.txtWhen resetting an entire subdirectory, git checkout won't remove files that were deleted in the target commit. Use the diff-apply method for exact matching:
# Method 1: checkout (keeps extra files)
git checkout HEAD -- subdirectory/
# Method 2: diff-apply (exact match, removes deleted files)
git diff --cached HEAD -- subdirectory | git apply -R --index
# Method 3: restore with overlay (Git 2.22+)
git checkout --overlay HEAD -- subdirectory/Understanding the difference:
- git checkout HEAD -- subdir/ updates existing files but won't delete files that don't exist in HEAD
- The diff-apply method creates an exact match by finding differences and applying them in reverse
- --overlay mode in newer Git versions handles deletions properly
Use the right command for each situation:
Use `git reset` (no path) for branch operations:
# Move HEAD and reset index (unstage everything)
git reset HEAD
# Move HEAD back 1 commit, keep changes staged
git reset --soft HEAD~1
# Move HEAD back 1 commit, reset everything
git reset --hard HEAD~1
# Reset index only (unstage)
git resetUse `git reset` (with path) for unstaging:
# Unstage a file (keep working tree changes)
git reset HEAD -- path/to/file.txt
# Unstage all files
git reset HEAD -- .Use `git checkout` or `git restore` for working tree:
# Discard working tree changes
git checkout HEAD -- path/to/file.txt
# or
git restore path/to/file.txtThe key distinction:
- git reset --hard (no path): Resets HEAD position + index + working tree
- git reset <path>: Resets only the index for that path
- git checkout <path>: Resets only the working tree for that path
If you have scripts that fail with this error, update them to use the correct commands:
Before (broken):
# This fails
git reset --hard -- path/to/file.txt
git reset --hard .After (fixed):
# Reset specific file
git checkout HEAD -- path/to/file.txt
# Reset current directory
git checkout HEAD -- .
# Or with git restore (Git 2.23+)
git restore --staged --worktree .For CI/CD pipelines:
# GitHub Actions example
- name: Reset modified files
run: |
git checkout HEAD -- src/generated/
# Or discard all changes
- name: Clean working directory
run: |
git checkout HEAD -- .
git clean -fd### Why Git Designed It This Way
Git's command structure separates operations by scope:
| Command | Scope | What it affects |
|---------|-------|-----------------|
| git reset --hard | Repository | HEAD, index, working tree |
| git reset --soft | Repository | HEAD only |
| git reset <path> | File | Index only |
| git checkout <path> | File | Working tree (and index from commit) |
| git restore | File | Working tree and/or index |
The --hard and --soft modes change how HEAD is moved during a reset. Since path-based resets don't move HEAD, these options are meaningless and rejected.
### Using git diff + apply for Advanced Cases
For complex scenarios where you need to reset files to match a specific state exactly:
# Reset directory to match another branch exactly
git diff HEAD other-branch -- path/to/dir | git apply --index
# Reset to match a commit, including deletions
git diff --cached target-commit -- path/ | git apply -R --index
# Preview what would change
git diff HEAD target-commit -- path/to/dir### Partial Reset via Stash
Another approach is using stash to selectively save and restore:
# Save specific files to stash
git stash push -m "backup" -- path/to/file.txt
# Reset everything
git checkout HEAD -- .
# Restore the stashed file
git stash pop### Interactive Staging After Reset
If you want to reset the index but interactively choose what to re-stage:
# Reset index for files
git reset HEAD -- path/to/
# Interactively stage portions back
git add -p path/to/### Git Worktree Isolation
For situations where you need to compare or work with files from different commits:
# Create a worktree at a specific commit
git worktree add ../temp-worktree abc1234
# Copy files from there
cp ../temp-worktree/path/to/file.txt ./path/to/file.txt
# Clean up
git worktree remove ../temp-worktree### Common Mistake: Tab Characters in Commands
A subtle cause of this error is copying commands from web pages that include tab characters:
# If you see this error unexpectedly, check for hidden characters
git reset --hard # Tab character here could be interpreted as a path
# Retype the command manually to avoid copy-paste issues### The Overlay Mode Solution (Git 2.22+)
Git 2.22 added --overlay and --no-overlay modes to git checkout:
# Default behavior: overlay (doesn't delete extra files)
git checkout HEAD -- subdir/
# New behavior: no-overlay (exact match, deletes extra files)
git checkout --no-overlay HEAD -- subdir/This provides more control over whether files not present in the source should be deleted.
warning: BOM detected in file, this may cause issues
UTF-8 Byte Order Mark (BOM) detected in file
fatal: Server does not support --shallow-exclude
Server does not support --shallow-exclude
warning: filtering out blobs larger than limit
Git partial clone filtering large blobs warning
fatal: Server does not support --shallow-since
Server does not support --shallow-since in Git
kex_exchange_identification: Connection closed by remote host
Connection closed by remote host when connecting to Git server