About a year and a half ago, I converted to using GNU stow and git for managing my dotfiles. The most recent version of that effort is available here.
The scheme worked well but the OCD part of me grew tired of seeing symbolic links to files instead of the actual files themselves. The symlinks weren't unexpected, after all, the whole point of stow is easily managing lots of links. Then I ran across a post on Hacker News about using a bare git repo to manage dotfiles in place. I very much liked the idea and settled on using vcsh and myrepos to manage my dotfiles going forward.
I should mention that I've known about vcsh for a good while. My impression had been that it was more complicated than necessary for my purposes. I've since changed my mind completely; it's as simple as what I ended up doing with stow, if not simpler. Minor tweaks to dotfiles are a pleasure when using myrepos.
These are my brief notes about the process.
Add Existing Dotfiles to vcsh
Assume you are just getting started with vcsh and wish to control your existing dotfiles. Do the following for each logical group of dotfiles. This example will put my emacs related files in a vcsh controlled repo named emacs. It assumes that I have created an empty repo on Bitbucket named vcsh_emacs, which it will be synced to.
# Not necessary, but it keeps paths in this example clean $ cd ~ $ APP=emacs # Create the repo in vcsh $ vcsh init $APP # Add emacs related configuration and other files $ vcsh $APP add .emacs $ vcsh $APP add .emacs.d/lisp/os-x.el $ vcsh $APP add .emacs.d/lisp/virtualenvwrapper.el $ vcsh $APP add bin/ec # script to call emacsclient $ vcsh $APP add bin/ecw # script to call emacsclient $ vcsh $APP add bin/emacs # script to call emacs # Will be sourced by .bashrc to set env variables $ vcsh $APP add .bash.d/init/90-emacs $ vcsh $APP commit -m 'Initial commit of dotfiles'
If you run vcsh emacs status, you will notice that all files in your home directory will be shown as untracked, except those that were controlled. If you'd like to avoid this, perform the following optional step:
$ vcsh write-gitignore $APP $ vcsh $APP add -f .gitignore.d/$APP $ vcsh write-gitignore $APP $ vcsh $APP add .gitignore.d/$APP $ vcsh $APP commit -m 'Added gitignore for package'
The above isn't a mistake; the write-gitignore and add are run twice. One of the links I provided explains why.
Now it's time to push the repo out to Bitbucket.
# Push the files out to Bitbucket $ vcsh $APP remote add origin email@example.com:MaDeuce/vcsh_emacs.git $ vcsh $APP push -u origin master
Perform the above for each set of dotfiles you wish to control.
Note that w.r.t. vcsh, I have named repos using the application the files are associated with (e.g., 'emacs'). That same name, with 'vcsh_' prepended to it is used for the remote repository name (e.g., 'vcsh_emacs'). This is done to the remote repository names to make it easy to distinguish the vcsh repositories from other repositories I keep on Bitbucket.
All of my vcsh repos on Bitbucket are publicly accessible here.
If you are happy with the above, you can stop reading now. On the other hand, if you have a lot of collections of dotfiles and would like a way to deal with them all at once, keep reading.
Obtain an Initial myrepos Template
myrepos is configured through a set of files. We'll get a template from the author of vcsh and myrepos to use as our starting point. This will also create a vcsh repo named mr for the template.
The template will create the following files (and one symbolic link):
~ ├── .config │ └── mr │ ├── available.d │ │ ├── mr.vcsh │ │ └── zsh.vcsh │ └── config.d │ └── mr.vcsh -> ../available.d/mr.vcsh └── .mrconfig
Create an empty repository named vcsh_mr on Bitbucket where we'll sync our mr repository.
Update the mr repo in vcsh to use my Bitbucket repository:
Update the myrepos Configuration for mr
In the default template, available.d/mr.vcsh will contain:
[$HOME/.config/vcsh/repo.d/mr.git] checkout = vcsh clone git://github.com/RichiH/vcsh_mr_template.git mr
We'll need to update this to use our bitbucket repo for storage. Mine ended up looking like this:
Additionally, you can remove mr/available.d/zsh.vcsh.
Now the changes can be committed and pushed out via:
Everything up to this point need only done once - during the installation and initial configuration of myrepos.
Add vcsh Repositories to myrepos
Each time a new vcsh repository is created, it must be provisioned into myrepos so that myrepos can operate on it. This is done by creating a file in mr/available.d for the repository and, optionally, creating a symbolic link to it under mr/config.d. See this note's links for more info.
To add the vcsh emacs repo to myrepos:
$ cd ~/.config/mr/available.d $ sed 's|mr|emacs|g' mr.vcsh > emacs.vcsh $ cd ~/.config/mr/config.d $ ln -s ../available.d/emacs.vcsh emacs.vcsh
NOTE: The trivial sed substitution above works in my situation, but it's super fragile and could easily go wrong, given difference contents of mr.vcsh.
Commit and push the changes:
Because myrepos is now configured, the commit/push could also have been done using myrepos. See the next step to see what I mean.
Ongoing Use of vcsh and myrepos
What has all this work to setup myrepos bought us? Assume that you've done a fair amount of work on your system and application configurations. The changes comprise a dozen file across five different vcsh repos. Without myrepos, one would have to perform the necessary vcsh commands on each repo individually. With myrepos, things are much simpler:
Using vcsh and myrepos on a New System
Ah, the best for last... You have a fresh install of macOS and you want to bring all your dotfiles over. Here's what to do.
- Install vcsh and myrepos as already described. Ensure your ssh config allows access to your repo (in my case, bitbucket.org).
- Clone the myrepos repository.
Grab a beer and enjoy the fruits of all of your hard work.