Dotfiles are the configuration files in your home directory that control your terminal, editor, aliases, and tools. When you work across multiple remote servers, a home machine, and a laptop, keeping these in sync manually is tedious and error-prone. A dotfile manager turns your config into a Git repository you can clone anywhere.
This guide covers two approaches: GNU Stow (simple, no dependencies beyond git) and Chezmoi (more powerful, handles secrets and machine-specific config).
The Bare Git Repo Approach (No Extra Tools)
Before reaching for a tool, consider the bare git repo approach. It uses only git — no additional software needed:
# Initialize a bare git repo in ~/.dotfiles
git init --bare $HOME/.dotfiles
# Create an alias to run git against this bare repo
# (using 'dotfiles' instead of 'git')
alias dotfiles='git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME'
# Don't show untracked files (your home dir has thousands)
dotfiles config --local status.showUntrackedFiles no
# Add the alias to your .bashrc/.zshrc
echo "alias dotfiles='git --git-dir=\$HOME/.dotfiles/ --work-tree=\$HOME'" >> ~/.bashrc
# Add remote and push
dotfiles remote add origin git@github.com:yourname/dotfiles.git
dotfiles push -u origin main
Track and commit files:
# Track a config file
dotfiles add ~/.bashrc
dotfiles add ~/.vimrc
dotfiles add ~/.config/nvim/init.lua
dotfiles add ~/.tmux.conf
dotfiles add ~/.gitconfig
dotfiles add ~/.config/alacritty/alacritty.toml
# Commit and push
dotfiles commit -m "dotfiles: initial commit"
dotfiles push
# Check status
dotfiles status
# View diff
dotfiles diff ~/.bashrc
Bootstrap on a new machine:
# On a fresh machine
git clone --bare git@github.com:yourname/dotfiles.git $HOME/.dotfiles
alias dotfiles='git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME'
dotfiles checkout
# If there are conflicts (files already exist), back them up:
# mkdir -p ~/.dotfiles-backup && dotfiles checkout 2>&1 | grep -E "\s+\." | awk {'print $1'} | xargs -I{} mv {} ~/.dotfiles-backup/{}
# Then run dotfiles checkout again
dotfiles config --local status.showUntrackedFiles no
GNU Stow
GNU Stow manages dotfiles by creating symlinks from your home directory to files in a structured ~/dotfiles folder. Each program gets its own subdirectory.
# Install
sudo apt-get install stow # Debian/Ubuntu
brew install stow # macOS
# Create dotfiles repo structure
mkdir -p ~/dotfiles/{bash,zsh,vim,nvim,tmux,git,alacritty}
# Move your config files into the repo
mv ~/.bashrc ~/dotfiles/bash/.bashrc
mv ~/.bash_profile ~/dotfiles/bash/.bash_profile
mv ~/.vimrc ~/dotfiles/vim/.vimrc
mv ~/.tmux.conf ~/dotfiles/tmux/.tmux.conf
mv ~/.gitconfig ~/dotfiles/git/.gitconfig
# For files in subdirectories, mirror the structure
mkdir -p ~/dotfiles/nvim/.config/nvim
mv ~/.config/nvim/init.lua ~/dotfiles/nvim/.config/nvim/init.lua
mkdir -p ~/dotfiles/alacritty/.config/alacritty
mv ~/.config/alacritty/alacritty.toml ~/dotfiles/alacritty/.config/alacritty/
# Stow creates symlinks from ~ back to ~/dotfiles/
cd ~/dotfiles
stow bash # creates ~/.bashrc → ~/dotfiles/bash/.bashrc
stow vim
stow tmux
stow git
stow nvim
stow alacritty
# Verify symlinks
ls -la ~/.bashrc
# ~/.bashrc -> /home/user/dotfiles/bash/.bashrc
Bootstrap script:
#!/bin/bash
# bootstrap.sh — run this on a new machine
set -e
DOTFILES_REPO="git@github.com:yourname/dotfiles.git"
DOTFILES_DIR="$HOME/dotfiles"
# Install stow if missing
if ! command -v stow &> /dev/null; then
sudo apt-get update && sudo apt-get install -y stow
fi
# Clone if not already present
if [ ! -d "$DOTFILES_DIR" ]; then
git clone "$DOTFILES_REPO" "$DOTFILES_DIR"
fi
cd "$DOTFILES_DIR"
# List of packages to stow (directories in dotfiles repo)
PACKAGES=(bash zsh vim nvim tmux git alacritty)
for pkg in "${PACKAGES[@]}"; do
if [ -d "$pkg" ]; then
echo "Stowing $pkg..."
stow --adopt "$pkg" 2>/dev/null || stow "$pkg"
fi
done
echo "Dotfiles installed."
Chezmoi
Chezmoi is a full-featured dotfile manager. It handles secrets (via 1Password, Bitwarden, or age encryption), machine-specific configuration (different settings on Linux vs macOS), and templates.
# Install chezmoi
sh -c "$(curl -fsLS get.chezmoi.io)"
# Or
brew install chezmoi
# Initialize with your repo
chezmoi init git@github.com:yourname/dotfiles.git
# Add files to chezmoi management
chezmoi add ~/.bashrc
chezmoi add ~/.tmux.conf
chezmoi add ~/.gitconfig
chezmoi add ~/.config/nvim/init.lua
# View what chezmoi would change
chezmoi diff
# Apply changes
chezmoi apply
# Edit a managed file (opens in $EDITOR, then applies)
chezmoi edit ~/.bashrc
Machine-specific config with templates:
# ~/.local/share/chezmoi/dot_gitconfig.tmpl
# chezmoi templates use Go template syntax
[user]
name = {{ .name }}
email = {{ .email }}
[core]
editor = {{ if eq .chezmoi.os "darwin" }}code --wait{{ else }}nvim{{ end }}
[credential]
helper = {{ if eq .chezmoi.os "darwin" }}osxkeychain{{ else }}store{{ end }}
Configure the template variables in ~/.config/chezmoi/chezmoi.toml:
[data]
name = "Your Name"
email = "you@example.com"
Secrets with 1Password:
# In a chezmoi template file (.tmpl extension)
# Reference a 1Password secret
[api_credentials]
token = {{ onepasswordRead "op://Personal/GitHub PAT/token" }}
key = {{ onepasswordRead "op://Work/AWS/secret_access_key" }}
Bootstrap on a new machine:
# One-liner: install chezmoi + apply dotfiles
sh -c "$(curl -fsLS get.chezmoi.io)" -- init --apply git@github.com:yourname/dotfiles.git
Handling Machine-Specific Differences
Common differences between machines: work vs personal email in gitconfig, Linux vs macOS paths, work VPN config that shouldn’t be in a public repo.
# Stow: use separate packages per machine type
~/dotfiles/
├── bash/ — shared
├── vim/ — shared
├── git-personal/ — stow on personal machine
├── git-work/ — stow on work machine
└── macos/ — macOS only
# Bootstrap script selects based on hostname or env var
if [[ "$HOSTNAME" == *"work"* ]]; then
stow git-work
else
stow git-personal
fi
# Chezmoi: use .chezmoi.hostname or custom data
# ~/.local/share/chezmoi/dot_gitconfig.tmpl
[user]
{{ if .work_machine }}
email = you@company.com
{{ else }}
email = you@personal.com
{{ end }}
Sync Workflow
# After changing a config file, push the update
# With bare git:
dotfiles add ~/.tmux.conf
dotfiles commit -m "tmux: add popup window keybind"
dotfiles push
# With stow: edit the file in ~/dotfiles/ directly (symlink means changes are immediate)
vim ~/dotfiles/tmux/.tmux.conf
cd ~/dotfiles && git add -A && git commit -m "tmux: add popup keybind" && git push
# With chezmoi:
chezmoi edit ~/.tmux.conf # opens, applies on save
cd $(chezmoi source-path) && git add -A && git commit -m "tmux: add popup keybind" && git push
# On other machines: pull and apply
# bare git: dotfiles pull
# stow: git pull (symlinks already in place)
# chezmoi: chezmoi update
Related Articles
- permission-matrix.yaml
- How to Manage Remote Journalism Team Across International
- How to Manage Remote Team Across More Than 8 Timezones Guide
- How to Manage Remote Team Handoffs Across Time Zones: A
- Best Dotfiles Manager for Remote Developer Setup
Built by theluckystrike — More at zovo.one