Putting my Config Files in Git

Git's been ubiquitous among coder-types for so long now it's almost old hat. This isn't going to be another post detailing its virtues relative to other version control systems (VCS) so much as a report on my experience using it to store my personal configuration—itself hardly a novel idea.

Motivation

The reasons you might want to store config files in Git parallel why you would want to use it for any substantial coding project—and to be clear, if you're not storing your software project in a VCS, you're making a big mistake. Especially on Unix-like systems, where the preponderance of tools and programs you're likely to use are configured via plain-text files and scripts, the line between code and config can get very blurry.

In my case, the principal advantage of moving the configuration of all my command line utilities into Git has been keeping my environment consistent across machines, just as Git can keep a codebase consistent across teams of programmers. For a long while now I've just put up with Vim (itself a program worth its own post) being configured entirely differently on my personal laptop than on my work machine. Similarly, Bash could exhibit considerable discrepancies in behavior across my workstations if I didn't put in the work to manually configure it to my liking everywhere. I switch back and forth between machines frequently, and I found that the lack of consistency in behavior with my tools and utilities contributed to a lack of interest on my part in configuring them to my exact liking. Simply put, I was more likely to just settle for the default settings in frustration.

In some cases, this pushed me to use alternative tools whose default behavior was more agreeable to me. NeoVim, for example, can be rightly considered to have a more sensible default configuration than Vim. But on the whole it meant more frustration and less efficiency on my part: I wasn't productive as I could be, and I knew it.

Details

With a working familiarity with Git (definitely beyond the scope of this post), there's nothing particularly tricky about tracking config files in a repo. You can see my dotfiles here. The tricky part, for me, was simply synchronizing my local Git repo(s) and the various configuration files around my system(s). If I make a change to one of the config files, how do I avoid having to manually add that change to the local Git repo? And if I'm making changes in the Git repo first, how do I insure those changes are reflected in the various files around the filesystem?

Two popular solutions I found for this were:

  1. Replace the config files around your filesystem with symlinks to the "true" copies in the local Git repository.
  2. Locate the Git repo in your home directory. There would be no redirection necessary, because git pull would override the actual configuration files.

I didn't end up going with either of these solutions. I initially tried the first, but ran into issues with how Git[1] stores/updates its configuration,[2] and the practicality of the second option struck me as too contingent on how capable a .gitignore file you could write to insure you didn't include everything else in the repo alongside your config files. Instead, I wrote a simple Python script to copy all the files in the repo out to their respective locations, and vice versa if I provide the --reverse flag. It's a bit of a brute-force solution, so I would welcome any advice on how I can get the symlink approach working.

Outcome

As hinted above, I think the major outcome of tracking all my dotfiles in Git has been a willingness on my part to actually invest in better learning and customizing the utilities I use. I'm using (Neo)Vim plugins again for the first time in months, and finally setting up Git aliases. I initially just copied the default Bash configuration from my Ubuntu machine, but have already added lines to enable auto-completion via Homebrew on MacOS, and automatically authenticate with ssh-agent on initializing a terminal. On the whole, I find myself finally investing in making my machines my own, and conforming my tools to my needs rather than constantly obliging myself to adjust to how these tools function out of the box. I think, ultimately, anything that encourages you to better familiarize yourself with a tool and demystify its inner-workings and behavior is a worthwhile decision.


  1. Yes, I store my configuration for Git itself in a Git repo. ↩︎

  2. In brief, rather than directly writing to the .gitconfig file (which would be redirected appropriately by the symlink), Git will copy it, write its changes to the copy, and then replace the original file with the copy, destroying the symlink. ↩︎