Syncing configurations across different computers

This post describes my strategy to sync configuration files (dotfiles) across different computers that I use. I’m almost always using Linux, so I haven’t considered extending this to any other OS type.

Git + GNU stow

I use Git for version control, keeping a public remote repository on SourceHut at https://git.sr.ht/~jayc/dotfiles. Git allows me to use local branches and a private remote for changes that I don’t want to share.

Each individual configuration file is symlinked to a local checkout of my dotfiles git repo. I used to add and remove this manually using the ln command. Now I make use of GNU Stow to manage the symlinks.

From my dotfiles repo, I can simply run stow PACKAGE to create symlinks in the correct place(s). The placement is determined by the --target=~ set in my .stowrc combined with the directory structure of my dotfiles repo.

For example, let’s take a look at my git configuration. In my dotfiles repo it has the following directory structure:

dotfiles$ tree -a git
git
└── .config
    └── git
        ├── config
        └── gitignore_global

3 directories, 2 files

When I run stow git, it will create symlinks:

dotfiles$ stow git
dotfiles$ ls -gGh --time-style='+' ~/.config/git
total 8.0K
lrwxrwxrwx 1 57  config -> ../../src/git.sr.ht/~jayc/dotfiles/git/.config/git/config
lrwxrwxrwx 1 67  gitignore_global -> ../../src/git.sr.ht/~jayc/dotfiles/git/.config/git/gitignore_global

💡 Note: An alternate approach to symbolic links would be to XDG_ environment variables to point to the appropriate dotfiles repository paths. I haven’t experimented with this (yet), but am interested in trying it. Check out this Arch Linux XDG user directories wiki page for more info.


Automated first time setup

I maintain a bash script to automate first time configuration: setup.sh. This sets up my development environment from scratch.


⚠️ Warning: My personal name, username, e-mail, etc. is hard coded in various places. The setup script as-is is intended for my own personal use. (TODO: Set these are global vars at the top of the script 🙂)


The script does the following:

  1. Install software packages.
    • Preference is to install as much as possible in my $HOME directory. This simplifies setup in environments that I don’t have authority to install system level packages.
  2. Clone my dotfiles repo.
  3. Call GNU Stow to create soft links to each configuration file.

I still prefer to configure things like private SSH and GPG keys manually.

Local customizations and overrides

Sometimes I make Git configuration changes that only apply to a local system. For these I keep a local config include in my Git config. I use different PGP signing keys on each computer, so this is a great place to set the signingkey.

[include]
    path = ~/.config/git/local_config_overrides

I also find conditional includes to be very convenient. For example, IBM has a private GitHub Enterprise instance which always requires authentication. I keep a includeIf in my local Git config based on a repository’s path to set a special Git config.

[includeIf "gitdir:~/src/github.ibm.com/"]
    path = ~/.config/git/config-ibm

Post history

DateDescription
2024-01-17Refactored to describe GNU Stow and local Git configs
2023-11-07Fixed typos / added details
2023-09-26Initial publish