Craftsman lavish as much attention on their tools as they do on the craft itself. Product managers (at least the good ones) are craftsman and we care a lot about the tools we use. We can debate endlessly on the merits of analytics or design tools. But for some reason, we don’t give much attention to the tool we spend most of our working days on….our computer.

The software equivalent of a whetting stone for your computer is dotfiles. On UNIX based systems, dotfiles help you customize almost every aspect of your computer from terminal commands, shortcuts, system preferences to display preferences. Customizing your computer is great for your productivity and most importantly – comfort (which in the end should make you more productive). And it’s not just for the software developers!

I’ve been actively customizing my computer using dotfiles for many years now. I’ve spent a lot of hours getting things just right in a way that works for me. I’ve become so used to many of them, that I start to feel lost on other computers.

This is my basic dotfiles setup, that I can quickly pull onto other computers I might use. (I’m also working on bootstrapping my entire MacOS setup but that is for a later post)

While there are loads of examples (including mine) of how people have customized their dotfiles, I would caution against lifting these without a good understanding of what they do. Your dotfiles are meant to be a representation of you. Pick and choose wisely and only keep the settings that work for you.

(My current setup is on MacOS, using ZSH as a shell and iTerm as my main terminal program)

Install Homeshick

I use homeshick to make my dotfiles portable.

You can install homeshick via homebrew

brew install homeshick

or by directly cloning it (see here for further instructions)

git clone git://github.com/andsens/homeshick.git $HOME/.homesick/repos/homeshick

printf '\nsource "$HOME/.homesick/repos/homeshick/homeshick.sh"' >> $HOME/.bashrc

Homeshick works by creating a castle in which you store all your dotfiles. The castle is basically a git repository in which one folder (the home folder is symlinked into your ~ or root folder)

homeshick generate dotfiles

You can track any existing dotfiles using homeshick

homeshick track .zshrc

Then add, commit and push to a remote repository

homeshick cd dotfiles
git commit -m "Initial commit, add .bashrc"
git remote add origin git@bitbucket.com:username/dotfiles.git
git push -u origin master

To have this work on a remote machine, all you have to do is install homeshick and clone this repo. After cloning the repo, homeshick will ask you whether you’d like to symlink all files in the dotfiles home folder to the root folder

Getting Homeshick Working with Prezto

In my case, I was already using Prezto as a framework to help me customize zsh to my liking. Getting Prezto to work with homeshick is not straightforward but this is what you need to do.

  • homeshick cd dotfiles
  • Fork prezto from here to the dotfiles repo
  • Ensure you are already tracking .zshrc and that .zshrc includes the Prezto source lines
  • In the home folder of the dotfiles repo create the following symlinks (for e.g. ln -s ../prezto .zprezto)
.zlogin -> ../prezto/runcoms/zlogin
.zlogout -> ../prezto/runcoms/zlogout
.zprezto -> ../prezto
.zprofile -> ../prezto/runcoms/zprofile

Introducing Abstraction

When I started, my .zshrc contained a lot of my customizations. Everything from sourcing commands, aliases to functions was stored there. But it was getting difficult to manage.

I decided to use homeshick to help me refactor some of this into seperate files.

I created a new shell folder in my dotfiles repository under which I created files like aliases.sh and functions.sh

The idea was to then source these files in the .zshrc file.

source "$HOME/.homesick/repos/dotfiles/shell/aliases.sh"

However, I didn’t want to use absolute filepaths but instead reference these from the .zshrc file in the home folder.

The challenge here is that as .zshrc is symlinked, the running directory is difficult to define inside the file itself. However you can do it using

# Define .zshrc running directory
ZSHDIR="$(dirname "$(greadlink -f "${(%):-%N}")")"

# Source Aliases
source "${ZSHDIR}/../shell/aliases.sh"

# Source Functions
source "${ZSHDIR}/../shell/functions.sh"