lab 17 Removing Commits from a Branch

Goals

The revert command of the previous section is a powerful command that lets us undo the effects of any commit in the repository. However, both the original commit and the “undoing” commit are visible in the branch history (using the git log command).

Often we make a commit and immediately realize that it was a mistake. It would be nice to have a “take back” command that would allow us to pretend that the incorrect commit never happened. The “take back” command would even prevent the bad commit from showing up the git log history. It would be as if the bad commit never happened.

The reset command 01

We’ve already seen the reset command and have used it to set the staging area to be consistent with a given commit (we used the HEAD commit in our previous lab).

When given a commit reference (i.e. a hash, branch or tag name), the reset command will …

  1. Rewrite the current branch to point to the specified commit
  2. Optionally reset the staging area to match the specified commit
  3. Optionally reset the working directory to match the specified commit

Check Our History 02

Let’s do a quick check of our commit history.

Execute:

git hist

Output:

$ git hist
* af5da8a 2014-10-25 | Revert "Oops, we didn't want this commit" (HEAD, master) [Jim Weirich]
* 47d0454 2014-10-25 | Oops, we didn't want this commit [Jim Weirich]
* a1189df 2014-10-25 | Added a comment (tag: v1) [Jim Weirich]
* 6083cb8 2014-10-25 | Added a default value (tag: v1-beta) [Jim Weirich]
* b24f3ff 2014-10-25 | Using ARGV [Jim Weirich]
* cf466b4 2014-10-25 | First Commit [Jim Weirich]

We see that we have an “Oops” commit and a “Revert Oops” commit as the last two commits made in this branch. Let’s remove them using reset.

First, Mark this Branch 03

But before we remove the commits, let’s mark the latest commit with a tag so we can find it again.

Execute:

git tag oops

Reset to Before Oops 04

Looking at the log history (above), we see that the commit tagged ‘v1’ is the commit right before the bad commit. Let’s reset the branch to that point. Since that branch is tagged, we can use the tag name in the reset command (if it wasn’t tagged, we could just use the hash value).

Execute:

git reset --hard v1
git hist

Output:

$ git reset --hard v1
HEAD is now at a1189df Added a comment
$ git hist
* a1189df 2014-10-25 | Added a comment (HEAD, tag: v1, master) [Jim Weirich]
* 6083cb8 2014-10-25 | Added a default value (tag: v1-beta) [Jim Weirich]
* b24f3ff 2014-10-25 | Using ARGV [Jim Weirich]
* cf466b4 2014-10-25 | First Commit [Jim Weirich]

Our master branch now points to the v1 commit and the Oops commit and the Revert Oops commit are no longer in the branch. The --hard parameter indicates that the working directory should be updated to be consistent with the new branch head.

Nothing is Ever Lost 05

But what happened to the bad commits? It turns out that the commits are still in the repository. In fact, we can still reference them. Remember that at the beginning of this lab we tagged the reverting commit with the tag “oops”. Let’s look at all the commits.

Execute:

git hist --all

Output:

$ git hist --all
* af5da8a 2014-10-25 | Revert "Oops, we didn't want this commit" (tag: oops) [Jim Weirich]
* 47d0454 2014-10-25 | Oops, we didn't want this commit [Jim Weirich]
* a1189df 2014-10-25 | Added a comment (HEAD, tag: v1, master) [Jim Weirich]
* 6083cb8 2014-10-25 | Added a default value (tag: v1-beta) [Jim Weirich]
* b24f3ff 2014-10-25 | Using ARGV [Jim Weirich]
* cf466b4 2014-10-25 | First Commit [Jim Weirich]

Here we see that the bad commits haven’t disappeared. They are still in the repository. It’s just that they are no longer listed in the master branch. If we hadn’t tagged them, they would still be in the repository, but there would be no way to reference them other than using their hash names. Commits that are unreferenced remain in the repository until the system runs the garbage collection software.

Dangers of Reset 06

Resets on local branches are generally safe. Any “accidents” can usually be recovered from by just resetting again with the desired commit.

However, if the branch is shared on remote repositories, resetting can confuse other users sharing the branch.

Table of Contents