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
here's a tree of my dotfiles directory:
|-- README.md |-- 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
$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
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.
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
commit c131132ddee6c9ef82e43bee8fff8dbc1b4134b1 Author: cmacrae <<redacted>@gmail.com> 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>@gmail.com> 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
-x appends a statement clarifying that this commit was cherry
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
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…