git delete local commits uses git reset --soft or --hard to remove commits from a local branch, preserving or discarding file changes, with recovery via git reflog.
git reset --soft HEAD~1
Syntax
# Delete the most recent commit (keep changes staged)
git reset --soft HEAD~1
# Delete the most recent commit (discard all changes)
git reset --hard HEAD~1
# Delete multiple recent commits (discard)
git reset --hard <commit-hash>
# View commit history to find target hash
git log --oneline
# Recover a deleted commit (if needed)
git reflog
git reset --hard <hash-from-reflog>
# Force-push deleted commits to remote
git push origin HEAD --force
Options and Flags
| Flag | Description |
|---|---|
--soft |
Moves HEAD back and leaves changes staged in the index. Changes remain ready for a new commit. |
--hard |
Moves HEAD back and discards changes from both the index and working directory. This is destructive; recovery requires git reflog. |
--force |
Used with git push to overwrite remote history after a local reset. Only use on private branches or with team consent; prefer --force-with-lease for safety. |
--oneline |
Condenses git log output to one line per commit, showing abbreviated hash and subject. Useful for quickly identifying commit hashes. |
Usage Examples
1. Soft Reset — Keep Changes as Staged Edits
git reset --soft HEAD~1
Context: Undo the last commit but retain all file modifications staged. This is common when you need to amend a commit message or re-split changes. After running, git status shows the files as staged, ready to re-commit.
2. Hard Reset — Discard All Local Commits and Their Changes
git reset --hard HEAD~5
Context: Throw away the last five commits entirely, wiping all associated file changes and directory modifications. Use with caution: the commits are orphaned but recoverable from git reflog for the default 90-day window.
3. Force Push After Local History Rewrite
git reset --hard a1b2c3d
git push origin HEAD --force
Context: After reverting to an earlier commit locally, the remote branch still contains the undesired commits. Force-pushing overwrites the remote history with the local reset state. This is irreversible for collaborators; use only on private branches or with team consensus.
Troubleshooting & Common Errors
| Error Message | Root Cause | Resolution Command |
|---|---|---|
fatal: ambiguous argument 'HEAD~1': unknown revision or path not in the working tree. |
Typo in commit reference or not inside a Git repository. | git status to verify repository; git log --oneline to confirm commit range. |
Updates were rejected because the remote contains work that you do not have locally. |
Remote has diverged after a force-push attempt, or other collaborators pushed changes. | Use git fetch and then git push --force-with-lease instead of --force. |
Cannot reset branch: you have uncommitted changes. |
Working directory is dirty (unstaged or staged changes) while using --hard. |
git stash before reset, then git stash pop after reset. |
fatal: reflog 'HEAD' has no entries. |
Repository is bare or reflog has expired (gc.reflogExpire default 90 days). |
Check git config gc.reflogExpire; recovery from reflog is unavailable if expired. |
Performance Considerations
git reset --soft is the fastest deletion method as it only moves the branch pointer, leaving index and working tree untouched. git reset --hard also resets the index and overwrites working tree files, which adds I/O overhead proportional to file sizes. Deleting multiple commits via git reset --hard <commit_hash> rewrites the commit chain but does not immediately reclaim disk space; orphaned objects persist in git reflog for the default 90-day window. No further tuning knobs appear in the verified contexts; all performance differences derive from the flag choices shown above.
Frequently Asked Questions
What is the difference between git reset --soft and git reset --hard?
Answer: --soft removes commits but keeps changes staged; --hard destroys both commits and all uncommitted changes in the working directory. Use --soft when you need to rework the commit; use --hard to discard work entirely. Both delete local commit history but differ in change preservation.
# Keep changes staged after delete
git reset --soft HEAD~1
# Destroy commits and unstaged changes
git reset --hard HEAD~1
When should I use git reset --mixed to delete local commits?
Answer: Use git reset --mixed (the default mode) when you want to delete commits but keep changes unstaged for review before re-committing. It resets the index but not the working tree, leaving modifications as unstaged changes.
# Delete last commit, unstage changes
git reset --mixed HEAD~1
How do I fix ‘error: Your local changes to the following files would be overwritten by checkout’ when trying to reset?
Answer: Stash your changes before resetting: git stash, then git reset --hard HEAD~1, then git stash pop. This avoids overwriting uncommitted work.
# Stash, reset, then apply
git stash
git reset --hard HEAD~1
git stash pop
Does the git reset command behave identically on CI runners and local machines?
Answer: Yes, git reset is a core Git command that behaves identically across all platforms and CI environments. However, CI environments may have branch protection rules that block force-push after a reset; use --force-with-lease where available.
# Platform-agnostic delete of last commit
git reset --hard HEAD~1
What is the fastest way to delete multiple non-consecutive local commits?
Answer: Use git rebase -i HEAD~N to interactively drop commits; it’s the most efficient for selective history rewrite. Change pick to drop for each unwanted commit. For consecutive deletions, git reset --hard HEAD~N is faster.
# Interactive rebase for selective removal
git rebase -i HEAD~10
# In editor: replace 'pick' with 'drop' for target commits
All commands shown are standard Git operations. Verify behavior on your Git version (≥1.7) and distribution.

Command Line Expert & Software Engineer
Welcome! I’m Thomas Heinrich, a software engineer and system administrator with a deep passion for the Command Line Interface (CLI). With years of experience navigating the terminal, building backend architectures, and automating server deployments, I created this space to share practical, real-world terminal knowledge.
Whether you are a beginner taking your first steps in a Linux environment or a seasoned DevOps engineer looking to optimize your deployment scripts, you will find actionable solutions here. My goal is to help you ditch the mouse, speed up your workflow, and harness the full power of the command line.