Switch theme in an existing Jekyll installation

This is what I did to change the theme of an existing Jekyll installation. Adjust these instructions to suit your needs.

Pull the new theme

We create a new orphan branch newtheme and ensure it's empty.

git checkout --orphan newtheme
git rm -rf .
git clean -dfx

Then we pull the theme files into it by adding the theme as an upstream remote. In this example I pull John Otander's Pixyll theme's master branch.

git remote add upstream https://github.com/johnotander/pixyll.git
git fetch upstream
git pull upstream master

Build the theme and test it.

bundler install
jekyll serve

Merge your changes

Now we merge our posts, configuration, etc. You can use Git checkout to copy a file or folder from your old Jekyll site. Note that this will overwrite the theme's file if it exists.

git checkout master -- _posts

Alternatively, you can copy a file under a new name, for example to merge it manually.

git show master:_config.yml > _config.yml.old

If you accidently overwrote a theme file, you can restore it.

git checkout upstream/master -- about.md

These are the files I had to copy, merge, adjust or remove:

  • Markdown files in the root folder.
  • Posts in the _posts folder.
  • Drafts in the _drafts folder.
  • The _config.yml configuration file.
  • The Gemfile gem file.
  • The CNAME file (for GitHub pages).
  • The Rakefile (if any).
  • The favicon files (if any).
  • Manual theme changes such as Google Analytics, Disqus, SEO fields (if any).

Commit your changes, and don't forget to test the theme again.

Replace the master branch

Finally we replace our existing master branch with the new newtheme branch. Assuming we're on the newtheme branch:

git checkout newtheme
git merge -s ours master
git checkout master
git merge newtheme

Push the changes.

git push

And clean up the local newtheme branch.

git branch -d newtheme

That's it! You've successfully replaced your theme. If there's anything I missed, or you have anything to add, please leave a comment.


Updating the theme

If at any later point you want to update the theme to include the latest upstream changes, simply:

git pull upstream master

And fix any merge conflicts. Here I assume the upstream remote is still set to the theme's repository (you can check this with git remote -v).


While you could migrate to an existing installation by forking a new theme and then manually copy and pasting over resources like CSS, JS, HTML in the _includes, _layouts and other files you may need, this probably isn't a great idea as you end up having a mash up of old and new resources, which may not be of the same name, but in the scenario that they are (for example you didn't overwrite an old stylesheet that your post references), it will cause mixed up CSS styles that you'll have to debug and slowly fix.

Since I'm assuming you have a Jekyll install with Git (if you don't you really should), you could create a branch called new-theme and switch to that branch from the master as the working branch. (A simpleton way of having something like this is to just copy your entire Jekyll install and paste it elsewhere as old-Jekyll-install if you don't want to deal with Git branches (but really, you should. Here's a tutorial that helped me learn)

  1. Pull down the files for the new theme.
  2. Manually copy over _posts and your customized changes.
  3. Port over your _config.yml by manually comparing them and moving over what is necessary.
  4. Build the site and see what you're missing, what might be messed up (for example in the past you might have added a few <br \> tags for spacing and you don't want that in the new theme).
  5. Merge with master (or push it to production)

That being said all this is fairly manual and a pain, but at least you won't have to deal with conflicts in resources. The downside of doing this though is that your repository won't be synced with the theme repo. So you won't get upstream updates. I would still suggest that you fork the theme repo, port over your personal customizations for your Jekyll site, and then rename that repo for production. (this would of course no longer be using the 'existing' Jekyll installation)


Jekyll v3.2 introduced gem-based themes (for future plans see here):

Gem-based themes make it easy for theme developers to make updates available to anyone who has the theme gem. When there’s an update, theme developers push the update to RubyGems

The goal of gem-based themes is to allow you to get all the benefits of a robust, continually updated theme without having all the theme’s files getting in your way and over-complicating what might be your primary focus: creating content.

Installing a gem-based theme is simple:

  1. Add the theme to your site’s Gemfile: gem "jekyll-theme-awesome"
  2. Install the theme: bundle install.
  3. Add the following to your site’s _config.yml to activate the theme: theme: jekyll-theme-awesome
  4. Build your site: bundle exec jekyll serve

To switch themes, I believe something like this should work:

  1. Change to the new theme in your site’s Gemfile: gem "jekyll-theme-new"
  2. Install the theme: bundle install
  3. Change you site’s _config.yml to reference the new theme: theme: jekyll-theme-new
  4. Build your site: bundle exec jekyll serve
  5. (optional - uninstall the old theme from your machine) Note down the old theme's installation folder (bundle show jekyll-theme-awesome) and uninstall it with gem uninstall jekyll-theme-awesome. To be on the safe side, make sure its folder was indeed deleted.

Updating gem-based themes is easy:

If you have the theme gem, you can (if you desire) run bundle update to update all gems in your project. Or you can run bundle update <THEME>, replacing with the theme name, such as minima, to just update the theme gem. Any new files or updates the theme developer has made (such as to stylesheets or includes) will be pulled into your project automatically.

Important note: at the time of writing, GitHub pages only supports a specific set of gem-based themes: Architect, Cayman, Dinky, Hacker, Leap day, Merlot, Midnight, Minima, Minimal, Modernist, Slate, Tactile, and Time machine. Of those, it seems only Minima is blog-oriented (e.g. it's the only one with built-in Disqus support). However, you should be able to use any theme if you are willing to run the Jekyll build process yourself.

Another alternative is GitLab pages (tutorial, sample site).


With GH-Pages

I tested this, but I did it with a project where I didn't have anything I wanted to save, and with fairly simple themes, so this might not work so well with the increased complexity.

  1. For safety, create a new branch

    git checkout -b newtheme
    
  2. And then add the new theme as a remote

    git remote add new-theme-upstream https://github.com:drjekyllthemes/jekyll-minimal-theme.git
    git pull new-theme-upstream HEAD
    
  3. The messy part, you're going to have a bunch of merge conflicts. Check which files have merge conflicts with git status, hopefully these conflicts should only be in style files that you want to overwrite. If there any files you want to keep you can either edit them with a text editor: git will have labelled the changes in the file
  4. Push to your origin

    git push origin newtheme
    
  5. Go to your project's page on github and you'll notice something like this:
  6. Create a pull-request and merge the new changes in.
  7. Your project is still going to show as being a fork of the first theme, and you won't be able to create pull-requests for the upstream of the new theme. But you can merge in new updates for your new theme by using git pull new-theme-upstream

If you are not using gh-pages or if you are building jekyll locally before pushing to github (I think)

You could keep your themes in git submodules, as separate folders and then symlink the key elements for jekyll. This won't work in gh-pages crude example

blog
|
+-- theme_1/
|
+-- theme_2/
|  |
|  +-- _layouts/
|
+-- _layouts ln - theme_2/_layouts

That way when changing themes the themes don't collide.


The easiest way to switch theme in an existing or new jekyll installation is to use the following plugin: jekyll-remote-theme, which is available since November 2017.

Although it is currently in beta, it works fine and most importantly it is already white-listed on Github Pages, so there is no need to build locally, unless the requested theme includes unsupported Gems.

Therefore, in the case of a simple web site with pages and blog, you can host and edit your content directly on the Github infrastructure and switch your site theme by typing-in the address of the new remote theme. An extra benefit is that you can test your content with several existing themes before committing to one of them.

In addition to easier switching, the jekyll-remote-theme method should automatically bring-in a new version of the remote theme, as soon as you make a change and there is a new version by the maintainer of the theme. If the maintainer of the theme makes a radical change that you don't like then you are always a few keystrokes away from a new theme.

I have several jekyll installations and I am already employing it without intending to switch in the short term, since it is the most elegant and future proof solution, for the time being.

If your existing jekyll installation is pure (i.e., you have edited only pages, posts, configuration) then the switch is seamless. If your existing theme has special layouts (e.g., splash.html and the new one does not have it) then your pages that employ the respective layout become orphans (i.e., basic html with no special formatting). I have switched an existing installation that had been extensively edited, so I got several orphan pages, but I did not get any of the git merge conflicts that are possible with other methods discussed here.