Developers are very picky about their working environment. We may consolidate various
. files tailed for our tastes over years and track the change in a version control system, preferably
git. Unfortunately, git or other VCS is not designed to maintain multiple working copies in a single directory. We may end up copying or linking the dot files to the home directory, like dfm does. The more external projects are added as submodule or subtree, the harder to manage. The last straw to me is that the monolithic
dotfiles is not portable: not even across my Linux workstation to the VPS.
LinuxJournal has a great tutorial about
vcsh for the rescue. After poking around and some error and trial, it is now dead simple to duplicate the working environment:
brew install vcsh mr vcsh clone firstname.lastname@example.org/kunxi/mrrc.git mr mr update
mr will pull oh-my-zsh, neobundle.vim and my configurations for zsh, git and vim.
The next step is to
chsh -s /bin/zsh; then launch vim. NeoBundle will prompt to download and install the vim plugins, voilà.
Behind the scenes
It is quite impressive how concise vcsh is, mere 462 loc in shell as version 1.20130829 is. It leverages the awesome git to do all the heavy-lifting. When you clone a remote repository
foo, vcsh does the following behind the scene:
- create a folder in
.config/vcsh/repo.d/foo.git, and export it as
$VCSH_BASEdirectory, i.e your home directory by default; and export it as
- Thus the work tree and git meta data, aka .git folder, are separated. We can use
git fetchto pull the remote repository into the
GIT_DIR, and merge the changes back to the
This approach allows us to share the
$HOME across multiple git repositories, a perfect solution to address the dotfiles problem!
With the mechanism in the mind, we can explore other use cases to streamline the dotfiles.
Mount the submodule
If your dotfile depends on an external project, like NeoBundle.vim to .vimrc, you can use mr to mount the external project to the specified destination:
[$HOME/.config/vcsh/repo.d/neobundle.git] checkout = mkdir -p ~/.vim/bundle; VCSH_BASE=~/.vim/bundle/neobundle.vim vcsh clone https://github.com/Shougo/neobundle.vim neobundle
The trick here is to override the
VCSH_BASE environment variable, so the git meta data is cloned in
$HOME/.config/vcsh/repo.d/neobundle.git, but the working copy is merged in the specified bundle directory.
Divide and Merge
As the above examples shows, each git repository is an atomic configuration for a specfic application. We can checkin the screenrc and tmuxrc, and pick whatever available in the target environment.
Some application supports configuration inclusion, then we can leave the personal credentials to a private git repository and pick them with
The separation of the git meta data and working copy solves the dotfiles issues elegantly, just as the FTSE claims:
We can solve any problem by introducing an extra level of indirection.