View post history

Not too long ago I had completely different configurations across different computers. Terminal color schemes between computers weren’t consistent. Git was configured slightly differently between all computers. Lucky for me, there’s a program that’s well suited for this task: stow.

Special thanks to Brandon Invergo for his blog post documenting how he uses stow to manage dotfiles.

Git & Stow

Before I found stow I was using a purely git-based workflow. It worked but it was a little clunky keeping a git repo at the root of my home directory. One minor annoyance was that the repo’s README would show up in my home directory whenever I ran ls (minor, I know, but it didn’t feel right to me). I was always a little paranoid that I would accidentally commit some secret inside of ~/.cache too.

My updated workflow still uses git but I no longer maintain a repo at the root of my home folder. Instead, I use stow to manage symlinks for me. My directory structure is cleaner now with a directory for each set of configuration files (below are my git and terminal emulator configurations).

❯ tree -a git alacritty
└── .config
    └── git
        ├── config
        └── global_ignore
└── .config
    └── alacritty
        └── alacritty.yml

4 directories, 3 files

Installing the configurations for those two programs is as easy as running stow -t ~ alacritty && stow -t ~ git.

Handling Plugins (and Plugin Managers)

There are some utilities (vundle, base16-shell, Oh My ZSH, etc) that I want to have available regardless of my underlying system’s environment. I set up submodules in my git repo for these utilities so that I have those utilities available without having to go through my system’s package manager (brew, apt, yay, etc).

As an added bonus, I can rely on plugin managers to pull in the bulk of my dependencies without cluttering up my git repo with a bunch of submodules.

❯ tree -a -L 3 vim
├── .vim
│   ├── bundle
│   │   ├── ale
│   │   ├── base16-vim
│   │   ├── fzf
│   │   ├── fzf.vim
│   │   ├── nerdcommenter
│   │   ├── nerdtree
│   │   ├── tmuxline.vim
│   │   ├── vim-airline
│   │   ├── vim-airline-themes
│   │   ├── vim-devicons
│   │   ├── vim-fugitive
│   │   ├── vim-gitgutter
│   │   ├── vimspector
│   │   ├── vim-tmux-navigator
│   │   ├── vim-toml
│   │   └── Vundle.vim
│   └── ftplugin
│       ├── css.vim
│       ├── go.vim
│       ├── javascript.vim
│       ├── python.vim
│       ├── rust.vim
│       └── yaml.vim
├── .vimrc
└── .vimrc_background

19 directories, 8 files

❯ git ls-files vim/.vim/bundle/

Instead of setting up submodules for each individual vim plugin I only have a submodule for vundle (a vim plugin manager) and then I run vim +PluginInstall +qall to pull in my vim plugins.

Special Snowflake Configurations

There are some cases where I don’t want to use the exact same configuration across all my devices. I’ve found that this situation comes up in one of two cases:

Device-Specific Configurations

I have certain configurations that are device-specific. For example, I have a sway configuration but there are slight differences between my laptop and desktop because the output configuration isn’t the same (one display vs multiple displays). To handle this I have sway-carbon and sway-gospel directories in my dotfiles repo.

❯ tree -a sway*
└── .config
    ├── sway
    │   ├── config
    │   └── status
    └── waybar
        ├── config
        └── style.css
└── .config
    └── sway
        └── includes
            └── carbon
└── .config
    └── sway
        └── includes
            └── gospel

9 directories, 6 files

My main sway configuration has this line include ~/.config/sway/includes/* which loads all files inside of ~/.config/sway/includes/. My sway-carbon and sway-gospel configurations will place the correct device-specific configuration once stowed.

Environment-Specific Configurations

I don’t use the same set of programs on all my devices. Sometimes there’s no need to install something everywhere (I wouldn’t use my sway configuration on a device running OS X). Sometimes I just want to play around with a new program first before deciding it’s something that I want to install everywhere.

For example, I wanted to try out delta for pretty git output on a personal device. The configuration for delta requires changes to git’s configuration file which depend on having delta in $PATH. To prevent breaking things on devices, like my work computer or one of my raspberry pi’s, I updated git’s configuration so that there would be fallback.

    diff = "$(which delta 2>/dev/null) | less"
    log = "$(which delta 2>/dev/null) | less"
    reflog = "$(which delta 2>/dev/null) | less"
    show = "$(which delta 2>/dev/null) | less"

So now on devices with delta installed that’ll be used, otherwise less will be used.