How can I delete a Git commit while preserving the changes?
I made some changes to my codebase in a development branch but needed to switch to master for a demo before completing the features. When I used “git checkout master”, the changes from my development branch were preserved, which broke some functionality in master. To resolve this, I committed the changes with the message “temporary commit” and then checked out master.
Now that I’m back working on the development branch, I want to remove the “temporary commit” while keeping the actual changes. Is there a way to undo a Git commit but maintain the changes?
To undo a Git commit while preserving your changes, you can use git reset --soft HEAD~1. This command removes the most recent commit but keeps your changes staged, allowing you to commit again with a better message or reorganize your work.
Contents
- Understanding Git Reset Options
- Step-by-Step Guide to Undo Commit
- Alternative Approaches
- Handling Remote Repositories
- Best Practices
Understanding Git Reset Options
Git’s reset command offers three main modes that determine what happens to your changes when you undo a commit:
--soft: Removes the commit but keeps changes staged (in the index)--mixed: Removes the commit and unstagges changes (back to working directory)--hard: Removes the commit and discards changes permanently
For your situation of wanting to keep the changes, --soft is the perfect choice, as it preserves all your work while just removing the commit itself.
Step-by-Step Guide to Undo Commit
Follow these steps to safely remove your “temporary commit” while keeping the changes:
-
Verify you’re on the correct branch:
bashgit branch
Make sure you’re on your development branch where the temporary commit exists.
-
Check the commit history:
bashgit log --oneline -5Confirm the “temporary commit” is the most recent commit.
-
Perform a soft reset:
bashgit reset --soft HEAD~1
This command removes the last commit while keeping all changes staged.
-
Verify the changes are preserved:
bashgit status
You should see that your files are listed under “Changes to be committed” (staged area).
-
Commit with a proper message (optional):
bashgit commit -m "your meaningful commit message"
Example of the process:
$ git log --oneline
a1b2c3d (HEAD -> feature-branch) temporary commit
e4f5g6h previous commit
$ git reset --soft HEAD~1
$ git status
On branch feature-branch
Changes to be committed:
modified: src/main.js
modified: tests/test.js
$ git commit -m "Add new feature implementation"
[feature-branch a7b8c9d] Add new feature implementation
2 files changed, 15 insertions(+), 3 deletions(-)
Alternative Approaches
Using git commit --amend
If you just want to change the commit message without removing the commit entirely:
git commit --amend -m "your better commit message"
This keeps the same commit but allows you to edit the message and even add more staged changes.
Using Interactive Rebase
For more complex scenarios where you might want to reorder or squash commits:
git rebase -i HEAD~3
This opens an editor where you can mark commits for editing, deletion, or squashing.
Using git revert
If you’ve already pushed the commit to a remote repository and want to undo it publicly:
git revert HEAD
This creates a new commit that undoes the changes, rather than removing the original commit.
Handling Remote Repositories
If you’ve already pushed the temporary commit to a remote repository, you need to be more careful:
For local-only commits (not pushed yet):
- Use
git reset --soft HEAD~1as described above - Push normally with
git push
For already pushed commits:
- Never use
git reseton pushed commits - this can cause issues for other team members - Use
git revertinstead:bashgit revert HEAD
- If you must remove the commit from the remote history (advanced):bash
git reset --soft HEAD~1 git push --force-with-lease origin your-branch
Warning: Force pushing rewrites history and can cause problems for collaborators. Use with caution and only when absolutely necessary.
Best Practices
Preventing Temporary Commits in the Future
-
Use stash instead of commit:
bashgit stash git checkout master # ... do demo ... git checkout feature-branch git stash pop -
Create feature branches properly:
bashgit checkout -b feature-branch # Make changes git add . git commit -m "WIP: In progress feature" -
Use worktrees for multiple branch work:
bashgit worktree add ../demo-branch master
Safety Checks
Always run these commands before making irreversible changes:
# Check what will be affected
git show HEAD --stat
# Create a backup branch
git branch backup-before-reset
# Verify changes are staged correctly
git diff --cached
Understanding Git’s Three States
Remember that Git has three main areas where changes can exist:
- Working Directory: Your actual files on disk
- Staging Area (Index): Files added with
git add - Repository: Files committed with
git commit
The --soft reset moves changes from the repository back to the staging area, keeping everything intact.
Conclusion
To undo a Git commit while preserving your changes, use git reset --soft HEAD~1 to remove the most recent commit while keeping your work staged. This approach is perfect for fixing commit messages or reorganizing your workflow without losing any code changes.
Key takeaways:
- Use
git reset --softto remove commits but keep changes staged - Always verify you’re on the correct branch before resetting
- Check
git statusto confirm changes are preserved - Use
git revertinstead of reset for already pushed commits - Consider using
git stashfor temporary changes that need to be preserved across branch switches
By understanding these Git operations, you can maintain a clean commit history while preserving all your valuable work. Remember to always create backups and verify changes before performing destructive operations.