I use a system I call homegit to manage config files and scripts in my home directory on all my machines. The idea is simple: a Git repository rooted at ~ that I push to GitHub. I’ve used this system for 6 years and like it a lot. See below to set it up for yourself!

The core functionality comes from 3 lines in my ~/.bashrc:

homegit() {
    git --git-dir=$HOME/.homegit --work-tree=$HOME "$@"
}

This defines a command homegit that works like regular git except that it saves its state in ~/.homegit (as opposed to ~/.git). Having a special command helps avoid accidents, like thinking I’m in a project repo, running git clean -dfx, and deleting everything in my home. I also use git_prompt_info in my Zsh PS1 to show my current Git branch, and by using --git-dir=$HOME/.homegit I avoid seeing branch information all the time.

I also define this command:

homegit-private() {
    git --git-dir=$HOME/.homegit-private --work-tree=$HOME "$@"
}

homegit-private works just like homegit, with the same Git toplevel dir (!) The difference is that I push the contents to a private repo. This allows me to version things like my SSH config and easily keep it in sync across devices. It’s also where I put anything that isn’t the same between my home and work setups.

When I want to pull my dotfiles onto a new device, I run these commands:

git clone git@github.com:kerrickstaley/homedir
mv homedir/.git ~/.homegit
git --git-dir=$HOME/.homegit diff  # check that the next command won't overwrite anything
git --git-dir=$HOME/.homegit reset --hard HEAD

The last piece that helps with all this is the runningon command. This allows me to put conditional blocks in my rc files like this:

# Default to Gnu binaries on macOS.
if runningon macos; then
    export PATH="/opt/homebrew/opt/coreutils/libexec/gnubin:$PATH"  # coreutils
    export PATH="/opt/homebrew/opt/grep/libexec/gnubin:$PATH"       # grep
    export PATH="/opt/homebrew/opt/gnu-sed/libexec/gnubin:$PATH"    # sed
    export PATH="/opt/homebrew/opt/gnu-tar/libexec/gnubin:$PATH"    # tar
fi

That way, I can use the same rc files on both macOS and Linux, at both home and work.

If you want to use this system yourself, you just need to copy these 7 lines into your .bashrc or .zshrc, and copy the runningon script into your ~/bin and modify the list of hostnames.

Update 2023-11-25:

The vcs-home wiki page links to many other approaches to this idea.

To avoid messy git status output, I’ve run

homegit config status.showUntrackedFiles no
homegit-private config status.showUntrackedFiles no

on all my machines as suggested in this HN post.