Over the past several days, I've been working to migrate my blog from whatever version of Octopress I was on to Octopress 3.0. The process ended up being more involved and taking longer than I expected, but I think now I have a more powerful and maintainable blogging setup.

I think my favorite new feature so far is drafts. Before I would attempted to do these using published: false in the YAML header, but this was a bit clunky. The other big improvement is that now Octopress works seamlessly with the rest of Jekyll, since it's just a plugin. In theory, this means I can pull from the expertise of a bigger pool of users.

There were a couple of challenges in the migration process:

  • Preserving git history from my old posts while getting rid of the unnecessary stuff.
  • Recreating the archive page in a way that was more or less the same as before
  • Creating category pages in the same locations as before, but not cluttering up the navigation bar.
  • Enabling pagination again.

For this post, I'm going to focus on how I imported my old posts without losing commit history. The other issues were mostly a matter of finding the right plugins and tweaking the theme in just the right way.

Originally I had hoped to do an in-place upgrade. That way I could keep all my git history from before. This seems tricky though. Instead, I opted to create a completely new repository and instead do a subtree merge to read in the old posts. Even though I lose the connection to the old repository, this approach seems cleaner overall. For example, the original way to get an Octopress blog was to fork the actual Octopress repository. Upgrades were then done by merging. I find it cleaner to import Octopress as a gem rather than have all of its history in my blog repo.

So, I started by moving my old repo out of the way and creating a new one:

mv octopress octopress.legacy
octopress new octopress
cd octopress
git init .

Initially I tried creating the git repo first and then doing octopress init ., but it turns out this leaves out a lot of the necessary things for Jekyll. The way I've shown here worked much better.

Around this time, I realized I should get a little more familiar with the new system, so I went ahead and created a draft of this post:

bundle exec octopress new draft "Migrating to Octopress 3.0"

I decided to see what this all looked like, so I ran jekyll serve. Here's what I saw:

Blank blog screenshot

So now it was time to import my old posts. I decided to do this as a subtree merge. This is something I do rarely, so I never remember the right incantation. GitHub has some a reasonably clear explanation of it. One thing that made this a little more tricky is that I had a few different paths I needed to import.

Just to be sure I didn't screw up the original, I decided to make a new clone and work there.

cd ..
git clone octopress.legacy/ octopress.filtered
cd octopress.filtered

Now the trick was to prune out the unnecessary files.

git checkout -b filter-blog
git filter-branch --prune-empty --subdirectory-filter source/ filter-blog

That gets rid of most of the extra stuff, but now I use a few more tree filters to get rid of the rest.

git filter-branch \
    --tree-filter 'rm -rf blog atom.xml index.html _layouts blog assets' \
    --prune-empty filter-blog

I did similar steps a few more times until I was satisfied that I only had the parts of posts that needed to be imported. I was careful not to remove too much, but I knew I had backups in case I got too zealous. I figured when I was done, I should only see my own commits in the history and none from Brandon Mathis, the original Octopress author. To accomplish this, I had to look through the history to find files that had been added and deleted before I saw them. gitk was my friend here.

Now back to my new blog to combine it with the old posts. I thought about doing some kind of fancy merge, but ultimately I decided to just rebase my old posts onto my new blog.

git remote add filtered ../octopress.filtered
git fetch filtered
git checkout filter-blog
git rebase master

At this point, I was pretty happy with everything. My timeline was interesting, because some commits are now younger than their children, but it preserves the history of my posts while still fitting neatly into Jekyll and Octopress 3.0.

It was time to merge this into master, and them I was on my way. Now my blog looked like this: Blog with all my old posts imported

Having imported all my posts, all that was left was to update the configuration files, theme, and go through and make sure everything in the old posts transferred alright. One thing that ended up being especially tricky was making sure all the old permalinks, especially for the various category archives, still worked the same. I'm sure I missed something, so let me know if you find any issues I haven't caught yet!