Yet Another "Put your dotfiles on GitHub" Post

By Calum MacRae

April 19, 2014

Yes, I know, the web is littered with posts recommending you manage your dotfiles with version control, specifically - more often than not - with Git & GitHub. I figured I'd do this short write up, as I'd like to detail how I go about achieving what many others have come to find a handy convenience, but I'd like to touch on one or two things others may not have mentioned.


If you're someone who tends to stick to defaults, or perhaps you're not even aware of your system's dotfiles, then of course there's not much for you here.

Though, if you happen to be a member of the humbled 'target audience' of this post, perhaps the question "Why not?" would speak greater volumes. The level of configuration we, as users, are given for most of our utilities, regardless of their size, importance, or purpose, means we can completely shape and mould how they function and appear. Over time, as your collection of dotfiles grow, and perhaps gain complexity, it's only natural that one should want to take care of these configurations in a sane, simple and safe fasion.

Losing these precious files can have quite the impact - keybindings aren't the same, functions behave differently, appearance isn't what you're used to - all things that will likely slow down your workflow. It comes to mind, as I write this, "well, perhaps we have only ourselves to blame for this issue?". It's a sensible argument that if one were to just stick to defaults, they wouldn't be faced with these problems. But, alas, we don't like sticking to defaults, control over every tiny aspect of our systems and their tools is large factor of what attracts us to them.

So, version control?

Yep! Again: "why not?". Using a decent version control system to help manage your dotfiles makes a lot of sense. Not only does it fill the boots of a means of backup, but you can benefit from many useful features; think branching, cherrypicking, commit logs, diffs. These may seem a bit overkill, but I'll talk more about how I use some of these features a little further on.

Enough babbling, get on with it

Okay! I'll first detail my dotfile structure.


Most people are used to their dotfiles simply residing within their $HOME, which is essentially where I keep mine, but I use symlinks. All of my dotfiles actually reside within a subdirectory of my $HOME, here's a tree of my dotfiles directory:


|-- bsd
|   |-- Xdefaults
|   |-- config
|   |-- irssi
|   |-- ncmpcpp
|   |-- symlinker
|   |-- tmux.conf
|   |-- vim
|   |-- vimrc
|   |-- xombrero.conf
|   |-- zsh
|   `-- zshrc
`-- osx
    |-- Xdefaults
    |-- config
    |-- irssi
    |-- symlinker
    |-- tmux.conf
    |-- vim
    |-- vimrc
    |-- xinitrc
    |-- xombrero.conf
    |-- zsh
    `-- zshrc

Each of these files and directories are symlinked to their associated place within $HOME, as shown below:

.Xdefaults -> /home/cmacrae/code/git/dotfiles/bsd/Xdefaults
.tmux.conf -> /home/cmacrae/code/git/dotfiles/bsd/tmux.conf
.vim -> /home/cmacrae/code/git/dotfiles/bsd/vim
.vimrc -> /home/cmacrae/code/git/dotfiles/bsd/vimrc
.xombrero.conf -> /home/cmacrae/code/git/dotfiles/bsd/xombrero.conf
.zsh -> /home/cmacrae/code/git/dotfiles/bsd/zsh
.zshrc -> /home/cmacrae/code/git/dotfiles/bsd/zshrc

Git hosting

So, because I keep all my dotfiles in a single directory, this of course means I can apply source code management to it. Doing so on your home directory would just be, well… stupid. I, like many, choose to stick with GitHub for hosting my dotfiles. I don't have any sensitive data in there (I'll touch on something related to this shortly), so I don't care that it's public. GitHub is easily accessible from anywhere in the world, you could of course set up your own remote repo at home or something, but I like the ability to share my configs, considering GitHub's fancy web front-end.

Use of Git features

While not all specific to Git, I make good use of some great features one has at their disposal when using this excellent VCS.


I use branching to track my different 'sets' of dotfiles. Quite a lot of people nowadays will have more than one system. Sometimes, like me, the varying systems may differ physically, and therefore dictate functional differences. For instance, my particular use of branches for this matter stems from the fact that I have a desktop and a laptop. My desktop has two monitors, whilst I only ever use the built in display with my laptop. As I track my window manager & keyboard daemon's configs in my Git repo, duplicating this configuration between systems would result in some undesired behaviour - I wouldn't want the window manager on my laptop to read its config and try to export certain workspaces and window rules to a non-existant monitor, or for my keyboard daemon to map keybindings for switching to a monitor, which, again, doesn't exist. This shouldn't be thought of as specific to those with multi-head setups - one might find branches useful for any varying systems - think keyboard layouts, screen size, even things like the environment you're in when your using a particular system; this could decide what colours you want to use for your terminal.

If ever the time should come in which I need to set up my configurations on a laptop system, I simply clone my dotfiles repo, checkout the laptop branch, and that's it.

Cherry picking

Now, as I'm using branches to track changes for specific systems, there may be changes that I make on one system which I actually want to apply to all my systems. I may change some keybindings that I feel are more comfortable in a program, or may be messing with my colours. Merging the branches would of course not be an option, as all the differing configurations that are specific to each system's functionality would be merged, causing a mess. Git has a very handy feature called cherry-pick, which allows the user to - as one might expect - "cherry pick" particular commits and merge them into another branch.

Let's play this scenario out.

I have some changes I made to my window manager's configuration on the laptop branch which I want carrying over into the master branch, the branch I use for my desktop.

I first determine the commit ID by taking a look at git log:

commit c131132ddee6c9ef82e43bee8fff8dbc1b4134b1
Author: cmacrae <<redacted>>
Date:   Wed Mar 26 22:10:49 2014 +0000
     Added floating rule for xmessage

Now that I have the commit ID, I take a quick look at git show to ensure I want to merge this change:

$ git show c131132ddee6c9ef82e43bee8fff8dbc1b4134b1

Author: cmacrae <<redacted>>
Date:   Wed Mar 26 22:10:49 2014 +0000

    Added floating rule for xmessage

diff --git a/bsd/config/bspwm/bspwmrc b/bsd/config/bspwm/bspwmrc
index 0ae7b69..0f1c707 100755
--- a/bsd/config/bspwm/bspwmrc
+++ b/bsd/config/bspwm/bspwmrc
@@ -25,3 +25,4 @@ bspc config -m HDMI1 top_padding 22
bspc rule -a xombrero desktop=Two
bspc rule -a MPlayer desktop=Three floating=on focus=on follow=on
+bspc rule -a xmessage floating=on focus=on

Once I'm happy that I want to merge the change, I switch to the master branch and cherry pick the commit:

$ git cherry-pick -x c131132ddee6c9ef82e43bee8fff8dbc1b4134b1

Using -x appends a statement clarifying that this commit was cherry picked, see git cherry-pick --help for more info

And that's it! Of course, I always push my changes to the remote repo once done. The official Git website has a great page on cherry picking, so check that out if you want to read up on this excellent feature.


If you've had a peek at my dotfiles repo, you may have noticed my symlinker script sat amongst the configs. I use this to 'bootstrap' all my configs when doing a fresh install, or, adding some new dotfiles into the mix. It's very simple, but very handy. It does a quick sanity check to ensure you're symlinking the correct dotfiles, by checking uname -s - I track my OpenBSD & OS X dotfiles - just in case it's a particularly bad day, and I'm somehow stupid enough to be sat in the wrong directory when I run the symlinker, that day is yet to come… but, sanity checks are there for sanity. It then proceeds to symlink all the dotfiles & directories, doing checks for the existence of said files & directories, removing them if they exist, creating any directories that may be necessary if not there already (~/.config), then symlinks everything. I've also added a little statement to check to see if I've got all my Vim bundles, and if not, to then go and grab them! I'm in the slow and painful transition of moving over to emacs, so I'll be tackling the equivalent in the near future.

You may have also noticed there's a single read line in my script, which of course requires input. This is to circumvent having to include my irc bouncer's password in my public dotfiles, as I've seen some people do… It copies my irssi config to the correct place, rather than symlinking it, then just uses sed (GNU sed, for in place) and read to replace the string 'XXXX' with watever is entered. Simple, but effective, I think.

Feel free to nab this script and modify it to our needs!

There's not much more to say

Well, if you've got this far, I appreciate you taking the time to read my post in particular. As I mentioned, there are many other posts like this, strewn throughout the vast abyss of nerdy blogs - but I hope I've brought a little perspective to the table, and perhaps even some minor differences in approach.

On another note…

I find it rather difficult to put aside the time to write blog entries nowadays, I do in fact live a rather busy life. And the 'list of things I want to learn/set-up/try' is forever growing. Perhaps I'll be writing about some of it in the near future! On a positive note, it's consoling that this post has turned out much longer than originally planned, as this shows me how much I enjoy writing once I finally get going. I'll make an effort to write more frequently, I certainly have a lot that I want to share…

Posted on:
April 19, 2014
8 minute read, 1680 words
configuration-management git
See Also: