Managing dotfiles with git, continued

Previously, I commented on my setup for keeping my dotfiles (.emacs, .bashrc, etc.) synchronized using git. Here is one refinement I've made to this process in the meantime.

Allowing local customizations

Occasionally there are changes I'd like to keep local to one machine. These may be on a permanent basis (for example, if there are certain things I'd like to happen, or not happen, on my laptop but not my desktop) or on a temporary basis (if I want to test out some change locally for some time before pushing it to my canonical repo). In version control a setup like this is best represented using branches. Here's how I've done this:

The master branch contains customizations that are supposed to be common to all machines and are appropriate to apply everywhere. Most changes are of this form. But on each machine I maintain a local branch named, for example, laptop-custom. This branch contains all the changes in master, plus usually no more than a couple of changes specific to that machine.

To initially set this up, after making a clone, I create a new branch and switch to it. Most of the time I stay on this branch.

git checkout -b laptop-custom

When I make changes, they initially go in to laptop-custom as local changes:

emacs # make some changes...
git add ...
git commit

If I decide a change is appropriate to apply everywhere, I put it on the master branch by using git-cherry-pick. I then rebase the local branch so the local patches always are at the "end". When you cherry-pick a patch to master and then rebase the other branch, git recognizes that the patch has already been applied on master and does not attempt to apply it again. So as you move changes over, the number of patches which are exclusive to the local branch decreases.

git checkout master
git cherry-pick ccddeef
git checkout laptop-custom
git rebase master

Pushing and pulling the master branch (containing the common customizations) is done in the same way as before, except that I always rebase the local branch afterwards.

git checkout master
git pull
git push
git checkout laptop-custom
git rebase master

4 comments:

  1. Great idea on handling branches for several machines. Helped me.

    ReplyDelete
  2. Nice post, made me finally try using git for my dotfiles too :)

    Is there a way to push the per-machine branches to a central repository (as backup or whatever), without having the rebasing break things?

    ReplyDelete
  3. "git push --force" does not do the usual check that requires the ref being pushed to be a descendant of the one being replaced. So you can use it to push a branch that has just been rebased.

    ReplyDelete
  4. I don't know. I don't feel too well about the thought of pushing a branch with rewritten history onto my server, especially not when it might be the case I already pulled it on a different machine (for some cherry-picking/merging into master or whatever).

    Currently instead of rebasing I just put everything I do on the machine onto the machine branch (avoids switching branches on my "running" home directory) and from time to time cherry-pick the "public" changes into the master branch (at a "save" checkout).

    However that leads to commit duplication and unecessary merge conflicts when merging master into the machine branches.... any ideas?

    ReplyDelete