Javaexercise.com

How To Delete Commits In Git?

A Commit is a snapshot of our project at any instant in time. Commits help us to maintain the version history of our projects. We can use them to compare changes and debug solutions. If something goes wrong, we can go back to a commit and restore a previous version of our project.

Sometimes we may commit wrong or irrelevant changes. Git provides a few different methods to delete commits. Let's learn how to delete Git commits.

Deleting the Most Recent Commits using -git reset command

If we need to delete the most recent commits, then the Git Reset command is our best bet. The git reset command helps us restore a previous version of the project.

We will use the --hard option with the Git Reset command. We also need to pass the reference of the commit to which we need to reset. The easiest way is to use the HEAD~N notation. For example, if we need to reset(or delete) the last five commits, we can use HEAD~5.

git reset --hard HEAD~N
git reset --hard <commit-hash>

Note that the --hard option will delete any uncommitted changes. If you want to keep the changes in the working directory and staging area, then use the --soft option.

Example

Consider a feature branch with six commits.

A -- B -- C -- D -- E -- F <- feature <- HEAD

Suppose, we want to delete the most recent commit(commit F). Then we can use the following Git Reset command. HEAD~1 is a reference that points to the second last commit(commit E). We can also use the hash of commit E instead of HEAD~1.

git reset --hard HEAD~1 
git reset --hard <hash-of-commit-E>
A -- B -- C -- D -- E <- feature <- HEAD

The above command takes our HEAD back to commit E.

Now, suppose we want to delete three more commits(commit C, D, and E). Then, we can use HEAD~3 with the Git Reset command. Or we can pass the hash of commit B.

git reset --hard HEAD~3 
git reset --hard <hash-of-commit-B>
A -- B <- feature <- HEAD

As we can see, the HEAD now points to commit B.

Deleting a Specific Commit - Git Rebase

The Git Reset command is perfect for deleting the most recent commits. But we can't use it to delete a commit in the middle of our history.

The Git Rebase command will help us in such scenarios. Git Rebase is used to modify the history of our project.

We will use interactive Git Rebasing to delete commits. We need to pass the reference for the parent of the commit that we want to delete. If you wish to delete multiple commits, then pass the parent commit hash for the commit that occurs first in the history.

git rebase --interactive <parent-commit-hash>
git rebase -i <parent-commit-hash>  # -i short for --interactive

The above code opens a text editor with an entry for each commit. We need to replace pick with drop for the commits that we want to delete.

Example

Consider a feature branch with five commits. We want to delete commits B and D from the history.

A -- B -- C -- D -- E <- feature <- HEAD

Let's first run the Git Rebase command. We need to pass the hash of the parent commit of B(since B occurs first in history). The parent of commit B is commit A. Use the Git Log command to find the commit hash.

git rebase --interactive <hash-of-commit-A>

The above command will open a text editor with an entry for commits B, C, D, and E.

pick fac83f2 Commit B
pick 61040bb Commit C
pick d0b23ea Commit D
pick 08a7ba9 Commit E
​
# Rebase 130dc64..08a7ba9 onto 130dc64 (4 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.

We need to replace pick with drop for commits B and D.

drop fac83f2 Commit B
pick 61040bb Commit C
drop d0b23ea Commit D
pick 08a7ba9 Commit E

Save and close the editor. Commits B and D are deleted from our version history.

A -- C -- E <- feature <- HEAD

Undoing the Effects of a Specific Commits

The Git Rebase command alters the history of our project. If we try to push a modified history to the remote repository, Git will block that push. We can force push the changes(Git Push -f), but it is not recommended.

The Git Revert command will undo the effects of a commit without changing the project history. It adds a new commit that contains the inverse of the changes of the specified commit. The "bad commit" will still exist in the version history, but its changes will be undone. Git Revert is a safe way to undo changes, and we can easily push the changes to the remote.

git revert <hash-of-the-commit-to-revert>

Example

Consider a feature branch with five commits. We want to delete(or undo the effects of) commit C.

A -- B -- C -- D -- E <- feature <- HEAD

We need to pass the hash of the commit that we want to revert. In our case, it would be the hash of commit C.

git revert <hash-of-commit-C>

The above command will open our configured text editor and we can enter the message for the new reverted commit.

The above command adds a new commit(commit C') to the feature branch. This new commit will have the inverse of the changes of commit C and will be its exact opposite.

A -- B -- C -- D -- E -- C' <- feature <- HEAD

Conclusion

Commits help us to store different changes in our repository. There are multiple ways to delete a commit in Git. If we want to remove the most recent commits, the git reset command is the best option. However, if the commit occurs somewhere in the middle of our version history, we can use the git rebase command.

Note that rebasing rewrites the history of our project. If we are working with other collaborators and want to push changes to the remote, then it is better to use the git revert command. It will undo the effects of the specified commit in a forward-moving fashion without affecting the history of our repository.