How to undo a commit and not screw it up

Alexey Shepelev
3 min readNov 15, 2020

Not only newbie developers, but also experienced professionals sometimes have to undo changes. And then, the first thing that comes to mind is the git revert command, which is the safest way to do that. However, there are some pitfalls I would like to tell you about.

Let’s take a simple situation: a developer decides to implement math functions. But halfway through, he realizes that it would be good to decompose this task, say, into two sub-tasks:

  1. Implement arithmetic operations (addition, subtraction, division, etc.)
  2. Implement numeric operations (maximum value, minimum value, modulus of a number, etc.)

It will be easier to check and test. But he has already begun to implement it. The commits have already been created. So, what to do? He doesn’t want to rewrite it!

Let’s consider a commit tree. We’ll see that our developer has created the functions branch, class Arithmetic responsible for the implementation of arithmetic operations (commit A), and class Numerical responsible for the implementation of numeric operations (commit N). In total, there are two classes and two commits.

So as not to rewrite anything, it is decided to inherit from the functions and create two branches, i.e. numerical and arithmetic. And thus, undo unnecessary commits. That is, to execute git revert N in the arithmetic branch and git revert A in the numerical branch. All ingenious is simple!

The work is in full swing and there is only one thing left to do — to merge these branches into the master.

And what do we get? No class Arithmetic, no class Numerical!

The thing is that the git revert command does not delete commits from history and creates a new commit that removes the changes. In our case, we get 4 commits after merging the branches:

A → N → revert A → revert N

That is, the option to cancel changes using the revert command has backfired.

git reset

And then we remember that there is such a command as reset, which, unlike revert, definitely removes commits from history. But the thing is that it resets all commits to the specified one. This behavior is not good for us, since we want to choose which commits to delete.

git rebase

Another solution is to use the git rebase command to revert the changes. Let’s go back to the moment of creating two branches, i.e. numerical and arithmetic, and execute

git rebase -i -root

Now, let’s replace pick with drop at the level of each commit we want to undo. The commits we’ve selected will be reset from history. For example, in the numerical branch:

Then in history, we will only have the commits we need. Now when merging the branches into the master, we get both classes.

This method is working only in a private branch. If these manipulations are carried out in a shared branch, then when you try to publish (git push), git reports that the branch is outdated, since there are no commits in it, and cancels the publication.

In order not to struggle with git, try to decompose tasks in advance. Otherwise, you may get an unpleasant surprise.

--

--

Alexey Shepelev
Alexey Shepelev

Responses (11)