
Occasionally, you may push unwanted changes or sensitive data to a Git repository, whether local or remote. Git provides flexible tools to rewrite commit history, allowing you to remove sensitive information, undo mistakes, and clean up your commit log. This article demonstrates how to remove commits from your Git history using safe and effective techniques for both local and shared repositories.
The Short Answer Version
# View Git commit history (compact)
$ git log --oneline
# Remove the most recent commit (discard changes)
$ git reset --hard HEAD~1
# Remove a specific commit (interactive rebase)
$ git rebase -i HEAD~N
# Recover a removed commit using reflog
$ git reflog
$ git reset --hard HEAD@{n}
# Permanently remove a file or directory from all commits (recommended)
$ git filter-repo --path <path> --invert-paths
View Git Commit History
You can view the commit history in Git either in a compact single-line format or a detailed full log. This helps you inspect previous commits and decide which ones to remove or recover.
Command Syntax
git log [OPTIONS]
git log
: Displays the full commit history with commit hashes, author, date, and commit message.[OPTIONS]
--oneline
: Condenses each commit to a single line showing the commit hash and commit message.
Command Demonstration
View compact commit history.
console$ git log --oneline
Output:
e2369629 (HEAD -> main, origin/main, origin/HEAD) removed requirement.txt file 2e39f29b Used Poetry for dependency management 2f7490ae modularized my code de4c0fb8 Updated the ReadME file 39b41a37 Concluded unit testing 1acecd8c minor 5a1f681e Added a dockerfile, updated the readme and added a requirements.txt file 97c43fa3 remove comm.md 1f20c89f first commit
View detailed commit history.
console$ git log
Output:
commit e23696290557c029add5490d81bb305dc506f61c (HEAD -> main, origin/main, origin/HEAD) Author: johndoe <johndoe@gmail.com> Date: Sun Sep 1 20:03:36 2024 +0100 removed requirement.txt file commit 2e39f29b49447219bc32a7fbdd6e8a5834b83911 Author: johndoe <johndoe@gmail.com> Date: Sun Sep 1 20:00:50 2024 +0100 Used Poetry for dependency management
Use the arrow keys to scroll through the log and press
q
to quit the view.
Remove the Most Recent Commit
Use the git reset
command to undo your most recent commit by moving HEAD
backward. You can choose whether to keep, unstage, or discard your changes depending on the reset mode you use.
Command Syntax
git reset [--soft | --mixed | --hard] HEAD~N
--soft
: Keep changes staged.--mixed
: Unstage changes, leave them in working directory (default).--hard
: Discard all changes (permanently resets working directory and index).HEAD~N
: MovesHEAD
back byN
commits (e.g.,HEAD~1
targets the last commit).
Command Demonstration
Keep changes staged.
console$ git reset --soft HEAD~1
Unstage changes.
console$ git reset --mixed HEAD~1
Discard changes entirely.
console$ git reset --hard HEAD~1
Remove a Specific Commit History
To remove a specific commit that is not the most recent one, use an interactive rebase. This allows you to review a range of recent commits and selectively remove (drop) individual ones.
Command Syntax
git rebase -i HEAD~N
git rebase -i
: Starts an interactive rebase.HEAD~N
: Specifies how many commits beforeHEAD
to display for editing (for example,HEAD~8
shows the last 8 commits).
Command Breakdown
- The command opens an editor listing the commits in the range.
- You can choose to
drop
any commit you want to remove. - Git will rewrite your history accordingly.
Command Demonstration
Start an interactive rebase to edit the last 8 commits.
console$ git rebase -i HEAD~8
Output.
pick 5fce205e Enhanced the ReadMe pick 8404786f minor pick f5879bb9 minor pick c26abc6b minor pick b1db91c2 minor pick f18e3944 minor pick ba58ebeb Used Poetry for dependency management pick 8169d159 removed requirement.txt file
In the editor:
- Press
i
to enter insert mode. - Change
pick
todrop
for the commit you want to remove:
drop 8169d159 removed requirement.txt file
- Press
To save:
- Press
Esc
to exit insert mode. - Type
:wq
and pressEnter
.
Git will process the rebase:
Successfully rebased and updated refs/heads/main.
- Press
Recover a Removed Commit
If you accidentally remove a commit using git reset
or git rebase
, you can often recover it using the git reflog
command. The reflog records where your HEAD
and branch pointers have been, even after destructive changes.
However, recovery depends on:
- How soon you attempt to recover the commit (reflog entries eventually expire).
- How the commit was removed (soft, mixed, or hard reset).
Recovery Guidelines
If you performed a hard reset, use:
git reset --hard HEAD@{n} # or git reset --hard <commit-hash>
If you performed a mixed reset, use:
git reset --mixed HEAD@{n} # or git reset HEAD@{n} or git reset --mixed <commit-hash>
If you performed a soft reset, use:
git reset --soft HEAD@{n} # or git reset --soft <commit-hash>
Command Demonstration
View the Reflog
First, display your reflog to locate the commit you want to recover.
$ git reflog
Output.
7a9a8b2f (HEAD -> main) HEAD@{0}: rebase (finish): returning to refs/heads/main
7a9a8b2f (HEAD -> main) HEAD@{1}: rebase (pick): Used Poetry for dependency management
59c2d68e HEAD@{2}: rebase (start): checkout HEAD~8
8dbe3b9a HEAD@{3}: reset: moving to HEAD~1
HEAD@{0}
: CurrentHEAD
.HEAD@{1}
,HEAD@{2}
: Prior reflog entries.HEAD@{3}
: Entry representing the state before the hard reset.
You can also preview a reflog entry before recovering:
$ git show HEAD@{3}
Recover Using a Reflog Entry
To reset your branch to a prior reflog state:
$ git reset --hard HEAD@{3}
Output.
HEAD is now at 8dbe3b9a Used Poetry for dependency management
Recover Using a Commit Hash
Alternatively, you can reset using the exact commit hash.
$ git reset --hard 8dbe3b9a
You can preview it first:
$ git show 8dbe3b9a
Remove a File or Directory from Commit History
In Git, you can remove a file or directory from future commits using:
$ git rm --cached <path-to-file>
$ git rm -r --cached <path-to-directory>
However, this does not erase the file or directory from your commit history, it only prevents it from appearing in future commits. To permanently remove a file or directory from all commits in your repository history, you must rewrite your commit history.
Use git filter-repo
git filter-repo
is the modern replacement for git filter-branch
. It is faster, safer, and more reliable for permanently removing files or directories from commit history. It is not included with Git by default but can be installed as a plugin.
Command Demonstration
Install
git filter-repo
.console$ pip3 install git-filter-repo
Back up your repository.
console$ cp -r <your-repository-name> <your-repository-name-backup>
Remove a file from history.
console$ git filter-repo --path <path-to-file> --invert-paths
Verify the file is gone.
console$ git log --all -- <path-to-file>
No output indicates success.
Remove a directory from history.
console$ git filter-repo --path <path-to-directory> --invert-paths
Verify the directory is gone.
console$ git log --all -- <path-to-directory>
No output indicates success.
Conclusion
In this article, you explored multiple ways to remove commits from a Git commit history. You learned how to safely undo recent commits with git reset
, remove specific commits using interactive rebase, and permanently rewrite history with tools like git filter-repo
. You also saw how to recover removed commits using git reflog
.
When working with shared repositories, always prefer git revert
to create a new commit that undoes changes without altering history. Rewriting commit history should be used with caution, especially on branches that have already been pushed and shared with others.
No comments yet.