My tmux and dotfiles setup, a few years in
I've migrated this setup across three laptops and a handful of servers now. The interesting thing isn't the config — everyone's config is idiosyncratic and mostly uninteresting to anyone else — it's the parts that stuck. Most of what I added over the years I eventually deleted. What's left earns its place.
tmux: the four bindings I'd miss
I remapped the prefix to C-a years ago and never looked back; C-b is a stretch for the left hand. The rest of my .tmux.conf has churned, but these four lines are the ones I'd reach for first on a fresh machine:
# ~/.tmux.conf
set -g prefix C-a
unbind C-b
bind C-a send-prefix
# split panes with the keys that look like the split
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
# reload config without leaving tmux
bind r source-file ~/.tmux.conf \; display "reloaded"
# keep new windows in the directory I'm standing in
bind c new-window -c "#{pane_current_path}"
The #{pane_current_path} on splits and new windows is the one most people miss, and it's the one I'd fight for. Without it, every new pane dumps you back in $HOME and you re-cd into your project for the hundredth time that day.
The thing tmux really buys me, though, isn't any binding — it's that a session survives a disconnect. I start long work inside a named session, and if my SSH connection drops or I close the laptop, the work is still there when I reattach:
tmux new -s work # start, named
tmux ls # list sessions
tmux attach -t work # reattach after a disconnect
dotfiles: a bare repo, not a symlink farm
For years I had a dotfiles/ directory full of symlinks and an install.sh that created them. It worked and it was fiddly, and the install script slowly rotted. The approach I settled on keeps the files in place in $HOME and tracks them with a bare git repo — no symlinks, no bootstrap script:
git init --bare $HOME/.dotfiles
alias dot='git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME'
dot config status.showUntrackedFiles no
The last line is important: without it, dot status tries to show every file in your home directory as untracked, which is unusable. With it, the repo only knows about files you've explicitly added. Day to day it behaves like any git repo, just with dot instead of git:
dot add ~/.tmux.conf ~/.bashrc
dot commit -m "tmux: keep splits in current path"
dot push
On a new machine the entire setup is a clone and a checkout. No install step, because there's nothing to install — the files go straight where they belong.
Keeping it from rotting
Two habits do most of the work here. First, I commit the small changes as I make them, with a real message, the same as I would for code. "fixed prompt" is useless in six months; "bashrc: strip git branch from prompt in large repos, it was slow" tells me why. My shell history isn't version control, but my dotfiles repo is, and I treat it that way.
Second, I periodically delete. Once or twice a year I read through my own config and rip out anything I don't remember adding or can't justify. A plugin I installed to try once, an alias I never type, a clever function that duplicates something the shell already does. Config accretes silently; the only cure is to prune it on purpose. The version that survives that pruning is the version worth carrying to the next laptop.
None of this is clever. That's rather the point — the setup I can explain in one short post is the one that's still running three laptops later, and the elaborate one I built in year one is long gone.