I use a Git repository to maintain my dotfiles (vimrc, zshrc, tmux.conf, etc.). As I've two different operating systems (OSX at home and Ubuntu at work) I've dedicated a branch for each system. This results in different versions of dotfiles as OSs are not used to use the same tools/libraries to do a job. This makes the maintenance of dotfiles hard for all the branches (diverged dotfiles). I was thinking if there could be a better strategy for this. Maybe to include system specific dotfiles in another file and include them in dotfiles.

In other words, I'm looking for a cross-platform strategy for maintaining dotfiles for computers with different OS.

Thanks in advance for any help


4 Answers 4


For shell scripts like .zshrc you can use an environment variable or the answer to some command like uname. But for non-shell dotfiles like .vimrc you should do the manual work of commiting patches from one branch to another (from one OS to another).


In addition to Envite's answer: I use one common .zshrc file, where all ,,portable'' stuff (like shell function definitions etc.) is included. Additionally, I have an extra file .zshrc-MACHINE_A etc. for every computer where I'm using the shared config. Here I define e.g. the PATH, some alias reflecting the current installed programs and so on.

The last part of my common .zshrc file reads

# load $HOST specific setting

if [[ -f ~/.zshrc-$HOST ]]; then
   [[ ! -f ~/.zshrc-$HOST.zwc || ~/.zshrc-$HOST -nt ~/.zshrc-$HOST.zwc ]] && { zcompile ~/.zshrc-$HOST; print - compiled \~/.zshrc-$HOST. }
   source ~/.zshrc-$HOST

According to man zshparam the parameter $HOST contains the current host name, hence should be portable and saves an external program call. And every time the according .zshrc-$HOST file is changed it'll get compiled (via zcompile). The compilation serves the purpose of (I quote man zshbuiltins):

(...) faster autoloading of functions and execution of scripts by avoiding parsing of the text when the files are read.

Probably nowadays you won't notice any difference(?), but it won't hurt either. Btw. the compiles *.zwc files are architecture dependent and cannot be exchanges between different systems.


Here is the best solution I've come across. I recommend clicking the link rather than reading about it here:


I've adapted @holman's ideia of symlinking files whose filename ends with ".symlink", and instead I'm symlinking files whose filename matches the regular expression \.(<os>-)?symlink$. By doing that, I can have files that are always symlinked, and files that are symlinked just in a specific environment.

For example, in my ~/.gitconfig I include ~/.gitconfig_include, which contains OS-specific configurations.

    path = ~/.gitconfig_include

Then I have two .gitconfig_include files: one for Linux and another one for Windows.

|-- git
    |-- .gitconfig.symlink
    |-- .gitconfig_include.linux-symlink
    |-- .gitconfig_include.windows-symlink

This allows a symlink to have the same name, but different targets, depending on the OS.

Unfortunatelly, this strategy wasn't enough to handle all the requirements for my cross-platform dotfiles.

Vim's bad decision on Windows

For some reason, Vim looks for its files in ~/vimfiles instead of ~/.vim on Windows. This means that, if I wanted to maintain the same strategy, I would have to duplicate the files folder—which I didn't want to do, for obvious reasons.

|-- vim
    |-- .vim.linux-symlink
    |-- vimfiles.windows-symlink

Instead of duplicating the files folder, I've created a file matching the folder's name, with the ".symlinks" extension.

|-- vim
    |-- .vim
    |-- .vim.symlinks

The .vim.symlinks file contains the symlink name for each environment.

linux: .vim
windows: vimfiles

This allows a symlink to have different names, but the same target, depending on the OS.


If you want to check how everything ended up, please visit my dotfiles on GitHub.

  • 2
    Cool that you copied the solution here, that link is dead now.
    – chmac
    Sep 6, 2021 at 20:49

My solution is to have a separate repositories for each machine.

Since git doesn't follow symlinks (it just stores them), and hard links don't work either, I have written a script that contains a list of files that are the same on both machines. After I've made changes in one of the repositories, I run the script.

If it detects (my computing a checksum) that any of the shared files have changed in this repository, it copies them to the other repository. Then I change to that repository and commit the changes there are well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.