Managing Dotfiles With Git: Get Your Dotfiles Under Control

Update - January 2016:

Since writing this post I've moved to a different method of managing my dotfiles, by forking @holman's popular repository. This method provides an isolated dotfiles directory and a script to symlink files into your home directory. Check out GitHub's dotfiles page for more resources!

As a developer, you’re always on the lookout for the best tools to help you do your job. You learn them inside and out, so that eventually they become extensions of your body. You wield your editor with the might of the blade Andúril, and commands tremble at your chaining deftness in the terminal.

Most of these tools adopt the pragmatic UNIX convention of plain-text configuration files, often prefixed with a period [.] — hence the term dotfiles. Dotfiles allow you to tailor your tools precisely to your liking, whether it be to modify default behavior, or simply tweak appearance. A few lines of configuration up front can save you thousands of keystrokes throughout your lifetime — and heaven knows that taupe color has just got to go.

You invest significant time and energy into getting your development environment just right. It’s only fitting that you should safeguard this sizable investment against loss or utter destruction.

Back it Up

You keep your project work under distributed source control, so that it’s safe if your development machine suffers an untimely end. As an added bonus, you get to use that source control system to go back in time, reliving all the memories you and your codebase have shared, commit by commit.

Why should it be any different with your dotfiles? After all, they’re written in plain text, just like your project code. They’re valuable to your productivity. You’d probably be pretty sad if you lost them, and had to reconfigure your environment from scratch all over again.

Hardware failure happens, as I can attest. I’ve had a MacBook Pro expand the volume of its battery overnight, rendering it unbootable, within the last year. Luckily, getting back to work wasn’t a nightmarishly difficult task, partly because I had my dotfiles under source control.

Git to the Point

Hopefully I’ve convinced you that keeping your system and application configuration files under source control is a good idea. Let’s look at how to keep our dotfiles in Git.

If we want to keep our dotfiles on a remote server for safekeeping (which we do), we’ll need to create a repository within a hosting service. For this post, we’ll be using GitHub. Follow these instructions to create a repo on GitHub. Don’t worry about creating README, gitignore, or license files just yet. Remember the name you gave your repo, or simply keep the confirmation window open for later.

Assuming you already have a bunch of dotfiles in your home directory, the next step is to create a Git repository there. Let’s go home and make a repo.

Great! Wait a second though… we’ve got all kinds of things in our home directory. In fact, it probably contains most of the things you actually care about, including project work, whose directories (hopefully!) already have their own Git repositories. Surely, we don’t want to keep all of those things within our new dotfiles repo.

If this thought crossed your mind, you are absolutely correct. Since we only want dotfiles in our repo, whose enclosing directory also happens to contain heaven-knows-what, we’re going to have to come up with a way to ignore everything but our dotfiles. Luckily, Git has a way to do just that.

Are You Ignoring Me?!

Run the following command to create a .gitignore file containing a single asterisk.

This tells Git to ignore all the files in the repository’s directory. Now you might be thinking, “Well that’s swell, an empty repo! I though we were storing dotfiles here!” And we are. We just need to be a bit forceful.

Forcing the Issue

Just for fun, let’s see what happens if we try to add a file to our repo at this point. For instance, you might happen to have a .bash_profile or .zshrc file in your home directory, where you keep all kinds of shell goodies.

Yeah, sounds about right. We ignored all files in our .gitignore, so Git is like, “Wait, what?” when we try to add anything. Git is pretty helpful though, and our solution is right there in the error message. Run the following command to force adding of the file.

This should go off without a hitch. Now repeat that command for all the files you want to track in your repo. You’ll need to give `git add -f` the full path to any files that are nested within directories. When you’re done, make your first commit.

Feeling Rather Remote

Now all that’s left to do is to get our repo onto GitHub. You’ll need the URL of the repository on GitHub. This can be found on the confirmation page from when you created it, or you can simply fill it in from memory.

Behold! You can now change, track, and push your dotfiles just as you would any other collection of code.

Privacy, Please

A great perk of having your dotfiles on GitHub is that it makes them eminently shareable. You and your colleagues can easily check out each others configuration, exchange tips, and argue over whose Oh-My-Zsh theme is more 1337.

A downside to this is that if your repo is public, the whole world can see it, so you need to be careful about what you put in it. Plenty of your local configuration might be sensitive. If you keep things like server credentials in configuration files, for example .ssh/config, make sure to keep those out of your repo. In this sense, the process of having to force-add each file individually can be a real help.

Despite these warnings, you might still want to keep sensitive information in Git, in order to track changes. You could gain a modicum of security for this use case by making your GitHub repo private. Of course, you would do this with the understanding that any service is potentially susceptible to having its data compromised.

Another option is to separate out sensitive information into new files that you won’t commit to Git. You can then source those files from the files you do have tracked. For example, if you happen to have some passwords stored in your .bash_profile, you can move them out into a new file called .bash_secrets. Then, at the bottom of .bash_profile, put the following.

Then, make sure to only add .bash_profile to your repository, and not .bash_secrets. This way, your sensitive information can’t be seen in your public GitHub repo.

Split Personalities

Another tip concerns those who might desire to maintain more than one set of dotfile configurations. For instance, you might have some configuration that is specific to your place of employment, and another set that you use by night under the obscure handle Neo.

You might accomplish this by maintaining separate branches of your repository, checking out a particular one as the need arises, and merging any common changes back and forth between them. You can also choose which of these branches to push up to your remote, but of course any that you don’t could be totally lost.

In Your Darkest Hour

In the event that your hardware does kick the bucket, or that you simply move on to a newer and faster machine, you might want a little help in getting your files back where they belong. As you wipe back your tears of anguish or joy, clone your repo to the home directory on your new machine.

Now you’ve got your dotfiles in a directory within your home directory. But we actually want those files in your home directory. This includes the .git directory that contains everything Git needs to track your repo. To move your precious files into your home directory and remove the old repo directory, run the following commands.

Now you’re all set up just like when you had originally created your repo. Your dotfiles are in place on your new machine and you’re ready to roll.

One Last Tip

One thing that can be a bit disorienting is not having a clear view of what files are being tracked in your repo. In a typical repository, nearly everything within the directory is tracked, and so you can simply list the directory contents to get a feel for the file structure. Since you likely have lots of other stuff in your home directory, you don’t get this ease of viewing with your dotfiles repo. I’ve found the command below, which lists out the files that are being tracked in the current repo, to be helpful in getting a quick glance at your files. You might consider binding it to a Git alias to make subsequent invocations faster.

To Finally Sum Up in Conclusion

Keeping your dotfiles under source control is well worth the small amount of effort it takes to get set up. You’ll never have to worry about losing your configuration again, and you get all the goodness of tracking changes over time. The idea of keeping a Git repository directly within your home folder can be a bit strange at first, but it’s really no different than any other repo, and you can take advantage of all the Git commands and workflows you’re already used to.

Now that you know how to track your dotfiles in Git, you might be wondering where to go for things to add to them. Check out these resources:

Happy hacking!

Tweet at Jeff

Share this post!