A universal approach for managing dotfiles with Git—applicable to anyone's configuration files.
This bare repository methodology uses Git via an alias to track files you specify in $HOME without symlinks or special tools, storing them in a Git bare repository in a "side" folder ($HOME/.dotfiles) using a specially crafted alias so that commands are run against that repository and not the usual .git local folder, which would interfere with any other Git repositories around. Your dotfiles are managed using a dotfiles alias to git that operates on the bare repository. Then managing your dotfiles becomes as simple as dotfiles add myfile, dotfiles commit, and dotfiles push.
Benefits:
- No symlink management
- Files tracked with version control
- Different branches for different computers
- Easy replication to new machines
- Works with any shell or configuration files
Required:
gitrsync(for replication to new machines)
Platform-Specific:
- macOS: Command line tools (comes with git), or you can install Homebrew
- Linux: Your distro's package manager (apt, pacman, dnf, etc.)
The dotfiles alias points to a bare Git repository in $HOME/.dotfiles/ with $HOME as the working tree:
alias dotfiles='git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME'This allows you to run commands like:
dotfiles status- See what config files have changeddotfiles add ~/.vimrc- Track a config filedotfiles commit -m "Update vimrc"- Commit changesdotfiles push- Push to remote repository
The key configuration that makes this work is:
dotfiles config status.showUntrackedFiles noThis prevents dotfiles status from showing every file in $HOME, only showing files you've explicitly added to the repository.
Before adding any files to your dotfiles repository, carefully review them for sensitive information:
- Passwords, API keys, tokens - Never commit these to version control
- Private keys (SSH, GPG, etc.) - Keep these out of your repository
- Personal Identifiable Information (PII) - Email addresses, phone numbers, addresses, etc.
- Work-specific configurations - Company-proprietary information or credentials
- Browser history, cookies, or session data
Best Practices:
- Always review files before running
dotfiles add - Use a
~/.gitignorefile as a safety valve (see below) - Use environment variables or separate credential files (not tracked) for sensitive data
- Consider using tools like
git-secretsor pre-commit hooks to prevent accidental commits - If you accidentally commit sensitive data, you must remove it from git history (see Troubleshooting)
While dotfiles config status.showUntrackedFiles no prevents your entire home directory from appearing in dotfiles status, a ~/.gitignore file provides an additional safety layer by preventing accidental commits of sensitive files.
See the .gitignore file in this repository for an example.
How it helps:
- Prevents
dotfiles add ~/.ssh/id_rsafrom working (git will refuse without--force) - Protects against wildcards like
dotfiles add ~/.config/*accidentally including sensitive subdirs - Self-documents what files should never be tracked
- Test it works:
dotfiles check-ignore ~/.ssh/id_rsa(should output the file path if ignored)
Important: .gitignore is a safety net, not a replacement for careful review. Always inspect files before adding them. Use specific paths (like .config/gcloud/) to avoid blocking your entire .config/ directory.
Common files to avoid:
.env,.env.local- Environment variables often contain secrets.aws/credentials,.ssh/id_*(private keys),.gnupg/.netrc,.password-store/- Shell history files (properly configured dotfiles should move history to XDG paths, which should not be tracked)
Use this approach to adopt the bare repository methodology with your own dotfiles.
git init --bare $HOME/.dotfilesalias dotfiles='git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME'# For bash, add to ~/.bashrc:
echo "alias dotfiles='git --git-dir=\$HOME/.dotfiles/ --work-tree=\$HOME'" >> ~/.bashrc
# For zsh, add to ~/.zshrc:
echo "alias dotfiles='git --git-dir=\$HOME/.dotfiles/ --work-tree=\$HOME'" >> ~/.zshrc# Hide untracked files (required for this methodology)
dotfiles config status.showUntrackedFiles no
# Add your own remote (replace with your username and repo)
# Note: Create your repository on GitHub first before running this command
dotfiles remote add origin [email protected]:YOUR_USERNAME/dotfiles.gitCreate a ~/.gitignore file to prevent accidentally adding sensitive files. This acts as a safety valve alongside status.showUntrackedFiles no.
cat > ~/.gitignore << 'EOF'
# Credentials and secrets
.env
.env.*
.ssh/id_*
.ssh/*.pem
.aws/credentials
.gnupg/
# Shell history
.bash_history
.zsh_history
# Common sensitive files
credentials.json
**/secrets.yaml
*.key
*.pem
EOFYou can customize this file with additional patterns specific to your needs. See the Security Considerations section for more details.
# Review files first
cat ~/.bashrc
cat ~/.vimrc
# If safe, add them (including .gitignore for safety)
dotfiles add ~/.gitignore
dotfiles add ~/.bashrc
dotfiles add ~/.vimrc
dotfiles commit -m "Initial commit: Add gitignore, bashrc and vimrc"
dotfiles push -u origin mainYou're done! Now manage your dotfiles using the dotfiles command instead of git.
Next steps: Continue to Daily Usage below to learn day-to-day workflows.
Applies to everyone using the bare repository methodology, regardless of whose dotfiles you're managing.
Use the dotfiles command exactly like git:
# Check what's changed
dotfiles status
# Add a new dotfile (⚠️ Always review first for sensitive data!)
cat ~/.gitconfig # Review the file first
dotfiles add ~/.gitconfig
# Commit changes
dotfiles commit -m "Update gitconfig with new aliases"
# Get changes from remote
dotfiles pull
# Push your changes
dotfiles push
# View history
dotfiles log
# Create a branch for a specific machine
dotfiles checkout -b laptop-workAdding a new config file:
# Always review before adding
cat ~/.config/alacritty/alacritty.yml
# If it contains no sensitive data, add it
dotfiles add ~/.config/alacritty/alacritty.yml
dotfiles commit -m "Add alacritty config"
dotfiles pushUpdating dotfiles on another machine:
dotfiles pull
dotfiles submodule update --init --recursive # Update submodules if needed
source ~/.bashrc # or source ~/.zshrcUpdating submodules (like Alacritty themes):
# Update to latest theme versions
dotfiles submodule update --remote
dotfiles add .config/alacritty/themes
dotfiles commit -m "Update Alacritty themes"
dotfiles pushExperimenting with changes:
dotfiles checkout -b experimental
# make changes
dotfiles add -u
dotfiles commit -m "Test new prompt settings"
# If you like it:
dotfiles checkout main
dotfiles merge experimentalCommon issues and solutions when using the bare repository methodology.
Problem: Files already exist in $HOME
Solution:
# Backup existing files
mkdir ~/dotfiles-backup
cp ~/.bashrc ~/.zshrc ~/.vimrc ~/dotfiles-backup/
# Then retry clone with force
git clone --separate-git-dir="$HOME/.dotfiles" https://github.com/andersix/dotfiles.git "$HOME/dotfiles-tmp" --forceProblem: Alias not persisted
Solution: The alias is in .shell_aliases which should be sourced by .bashrc/.zshrc. Verify:
grep -r "shell_aliases" ~/.bashrc ~/.zshrcIf missing, add to your shell config:
[ -f ~/.shell_aliases ] && source ~/.shell_aliasesProblem: Missing dependencies (prompt plugins, etc.)
Solution: The shell will work even with missing dependencies. If using someone else's dotfiles, check their documentation for required dependencies.
Problem: Plugins not installed yet
Solution: This is normal. Run :PlugInstall inside vim to install plugins.
Problem: Using HTTPS instead of SSH
Solution: Switch to SSH URLs:
dotfiles remote set-url origin [email protected]:YOUR_USERNAME/dotfiles.gitOr configure Git credential helper for HTTPS.
Problem: Forgot to set status.showUntrackedFiles no
Solution:
dotfiles config status.showUntrackedFiles noThis is required for the bare repository methodology and prevents dotfiles status from listing every file in your home directory. Without this setting, the repository is unusable.
Problem: You committed and pushed a file containing passwords, API keys, or other sensitive information.
Solution: You must remove it from git history immediately, as simply deleting it in a new commit doesn't remove it from the repository history.
# Option 1: Using BFG Repo-Cleaner (easiest)
# Install: https://rtyley.github.io/bfg-repo-cleaner/
bfg --delete-files sensitive-file.txt ~/.dotfiles
cd ~
dotfiles reflog expire --expire=now --all
dotfiles gc --prune=now --aggressive
dotfiles push --force
# Option 2: Using git filter-branch
dotfiles filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch path/to/sensitive-file' \
--prune-empty --tag-name-filter cat -- --all
dotfiles push --forceImportant: After removing sensitive data:
- Rotate any exposed credentials immediately (passwords, API keys, tokens)
- Consider the data compromised if the repository was public
- Review what was exposed and take appropriate security measures