Throw away local commits in Git
Categories:
How to Discard Local Commits in Git

Learn various methods to safely and effectively throw away local Git commits, whether they are unpushed, partially staged, or completely unwanted.
Working with Git often involves making local commits that, for various reasons, you might later decide to discard. Perhaps you made a mistake, committed sensitive information, or simply want to re-organize your work before pushing to a remote repository. This article will guide you through different scenarios for throwing away local commits, from simple unstaging to completely rewriting history, ensuring you understand the implications of each action.
Understanding Git's State and Commit History
Before we dive into discarding commits, it's crucial to understand how Git manages your project's state. Git tracks changes in three main areas:
- Working Directory: Your current files and their modifications.
- Staging Area (Index): A snapshot of changes you've marked to be included in the next commit.
- Local Repository (HEAD): The history of commits on your current branch.
Discarding commits often involves manipulating these states. The key is to know which state you want to revert and to what extent.
graph TD A[Working Directory] --> B{git add} B --> C[Staging Area] C --> D{git commit} D --> E[Local Repository (HEAD)] E -- git push --> F[Remote Repository] F -- git pull --> A
Simplified Git Workflow illustrating the three main states.
Scenario 1: Discarding Uncommitted Changes
If you have changes in your working directory that are not yet staged or committed, and you want to completely discard them, Git provides straightforward commands. This is the safest scenario as you're not altering any committed history.
# Discard changes in a specific file
git checkout -- <file>
# Discard all changes in the working directory (untracked files will remain)
git checkout -- .
# Discard all changes and untracked files (use with caution!)
git clean -fd
Commands to discard uncommitted changes.
git clean -fd
command is powerful and irreversible. It will permanently delete untracked files and directories. Always double-check your working directory before executing it.Scenario 2: Unstaging Staged Changes
Sometimes you stage changes with git add
, but then decide you don't want them in the next commit, or you want to modify them further before committing. You can easily unstage these changes without losing your work.
# Unstage a specific file
git reset HEAD <file>
# Unstage all staged changes
git reset HEAD
Commands to unstage changes from the staging area.
git reset HEAD <file>
, the changes for that file will move from the staging area back to your working directory, appearing as unstaged modifications. You can then modify them or discard them using git checkout -- <file>
.Scenario 3: Discarding Local Commits (Unpushed)
This is the most common scenario for 'throwing away' local commits. If you've made one or more commits on your local branch that haven't been pushed to a remote repository, you can safely revert your branch's history to an earlier state using git reset
.
1. Identify the target commit
Use git log
to find the hash of the commit you want to revert to. This is the commit before the ones you want to discard.
2. Perform a soft reset
If you want to keep the changes from the discarded commits in your staging area, use git reset --soft <commit-hash>
. This moves HEAD to the specified commit, but keeps all changes from the discarded commits staged.
3. Perform a mixed reset (default)
If you want to keep the changes in your working directory but unstage them, use git reset --mixed <commit-hash>
(or simply git reset <commit-hash>
). This moves HEAD to the specified commit and moves changes from discarded commits to the working directory as unstaged changes.
4. Perform a hard reset (use with extreme caution)
If you want to completely discard the commits and all their associated changes from your working directory and staging area, use git reset --hard <commit-hash>
. This is irreversible and will delete all work from the discarded commits.
# View commit history to find the target commit hash
git log --oneline
# Example: Reset to the commit before the last two commits
# (HEAD~2 refers to two commits before HEAD)
git reset --soft HEAD~2
# Example: Reset to a specific commit, keeping changes unstaged
git reset --mixed 0a1b2c3d
# Example: Reset to a specific commit, discarding all changes
git reset --hard 0a1b2c3d
Examples of git reset
for discarding unpushed commits.
graph TD A[Commit 1] --> B[Commit 2] B --> C[Commit 3 (HEAD)] subgraph Soft Reset C -- git reset --soft B --> B_soft[Commit 2] B_soft --> D_soft[Changes from C (Staged)] end subgraph Mixed Reset C -- git reset --mixed B --> B_mixed[Commit 2] B_mixed --> D_mixed[Changes from C (Unstaged)] end subgraph Hard Reset C -- git reset --hard B --> B_hard[Commit 2] B_hard --X E_hard[Changes from C (Discarded)] end
Visualizing the effects of git reset --soft
, --mixed
, and --hard
.
git reset --hard
on commits that have already been pushed to a shared remote repository, as it rewrites history and can cause significant problems for collaborators. If you must rewrite pushed history, communicate clearly with your team and use git push --force-with-lease
.Scenario 4: Discarding a Specific Commit (Keeping Others)
If you want to remove a commit from your history but keep subsequent commits, git revert
is the safer option. Instead of rewriting history, git revert
creates a new commit that undoes the changes introduced by a previous commit.
# Revert a specific commit (creates a new commit that undoes the changes)
git revert <commit-hash>
# Revert a range of commits (from older to newer)
git revert <older-commit-hash>..<newer-commit-hash>
Using git revert
to undo specific commits.
git revert
is generally preferred for commits that have already been pushed, as it maintains a linear history and doesn't require force-pushing. It's a non-destructive way to undo changes.Scenario 5: Rewriting History with Interactive Rebase
For more complex scenarios, like removing a commit from the middle of your history, combining multiple commits, or reordering them, git rebase -i
(interactive rebase) is the tool of choice. This is a powerful but advanced operation.
# Start an interactive rebase from a specific commit (or HEAD~N for N commits back)
git rebase -i <commit-hash-before-your-changes>
Initiating an interactive rebase.
When you run git rebase -i
, Git opens an editor with a list of commits. To discard a commit, simply delete its line from the list. You can also use squash
to combine commits, edit
to modify a commit, or reword
to change a commit message.
git reset --hard
, it should be used with extreme caution on shared branches. Always ensure you understand the implications before proceeding.