Git rebase to the rescue

The other day I found myself having serious trouble publishing a new post to my blog. I was able to solve the problem through the use of Git rebase and I thought I would share my experience in case somebody else happens to go through the same thing.

The problem

I host this blog through Github Pages because it’s quick, easy, and free. Although I love the ease-of-use it provides me it is not without its downsides. Recently I recorded a quick screen cast for a friend of mine who needed help solving a problem. I created a unique page on my site to host the video, tested it locally and committed the changes. I’m not the type to read a site’s terms of service so I had no idea that Github Pages has a file site limitation of 100mb. The upload was rejected and I had to find an alternate means of showing the video to my friend. No big deal, I removed the video and related files from my local directory and didn’t think much more about it.

It only became an issue later when I wrote another blog post. I committed the changes, which also included removing the failed video files from the previous commit. At this point my remote repo was now two commits behind my local repository. When I attempted to push my latest commit it pushed both of them. So even though the large video file wasn’t physically present it was still blocking my ability to publish blog posts. Version control’s gotta version, after all. Unless I could figure out a way to get rid of the offending commit I was stuck.

The solution

You can probably tell by now that I am not a Git expert, in fact I would categorize myself as a casual user at best. My initial response was to do a force push. When that didn’t work I tried removing the file directly using git rm --cached filename. It was equally unsuccessful. I really didn’t want to have to do something like flattening all my commits or creating a new branch, and I just knew that there must be a way to remove individual commits. Although I’ve never needed to use it before I remember reading about Git rebase and thought that it might offer me a solution.

Git rebase

You can think of rebase as Git merge on steroids. Its main focus is on altering commit histories and solving complex merge issues that usually stem from team-based workflows. I’m not even going to pretend to act like I know how it works. If you want to learn more about it I highly suggest this article from the book Pro Git by Scott Chacon.

Removing individual commits with rebase

Using the interactive flag you can use rebase to display and edit individual commits, which is exactly what I needed to do. In my terminal window I typed the command

git rebase -i HEAD~2

This tells Git that you want to interact with a number of previous commits. Since I used the number 2 I only wanted to display and edit the previous two commits.

Because I wasn’t smart enough to change my default text editor Git then opened up the following message in Vim.

pick c58c9d3 add video
pick a4945a1 post update

# Rebase bc4a787..a4945a1 onto bc4a787 (2 commands)
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
# 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.
# Note that empty commits are commented out

I used the drop command to remove the first commit, saved the file, and exited Vim. At this point I thought I was home free but I had one more problem to deal with. I had forgotten to add my directory structure files to my .gitignore file and Git warned of a conflict between my local .DS_Store files. Since they are binary files it couldn’t continue with the rebase until I resolved the conflict. I committed the most recent file and completed the rebase by telling Git to continue.

git rebase --continue

After that it was a simple matter of making sure my local repo was current and then pushing the changes to my Github Pages repo. Although I didn’t have to in my case, I read in the Github Pages documentation that you might have to do a force push after a rebase, so be on the lookout for that if you face a similar situation.

Hopefully you won’t ever find yourself in a jam like that, but if you do keep in mind that Git rebase can save a lot of time and trouble if you ever need to make edits to your commit history.

Read more: