My files live in two places:
- Some in ~/.config directories (like nvim, alacritty)
- Others directly in my home folder (like .gitconfig, .zshrc)
But I want to track all of them in git so I can have version control over them (and easily share them across multiple machines).
So I need to store them in a single place, but they have to be in separate directories as well.
There is actually a pretty simple way to do this.
A symlink.
- Store everything in a single git repository.
- Symlink each file or directory to where the apps expect them.
I will walk you through the initial setup and then how to add more configurations:
Setting Up the Repository
- I create the basic structure:
mkdir -p ~/dotfiles/home ~/dotfiles/configcd ~/dotfilesgit init
- I add a simple README and gitignore:
echo "# My Dotfiles" > README.mdgit add README.mdgit commit -m "Initial commit"
# I ignore common junk filescat > .gitignore << EOF*.log*.swp*~.DS_Store.netrwhistnode_modules/__pycache__/*.pycEOFgit add .gitignoregit commit -m "Add gitignore file"
Adding My Existing Configs
For Git:
# Copy my current Git configcp ~/.gitconfig ~/dotfiles/home/
# I might edit it to remove sensitive infonano ~/dotfiles/home/.gitconfig
git add ~/dotfiles/home/.gitconfiggit commit -m "Add Git configuration"
For Neovim:
mkdir -p ~/dotfiles/config/nvimcp -r ~/.config/nvim/* ~/dotfiles/config/nvim/
# I remove plugin folders and other large filesrm -rf ~/dotfiles/config/nvim/pluggedrm -rf ~/dotfiles/config/nvim/.git
git add ~/dotfiles/config/nvimgit commit -m "Add Neovim configuration"
My Installation Script
I create a script that sets up symlinks for me:
cat > ~/dotfiles/install.sh << 'EOF'#!/bin/bash
# Set variablesDOTFILES_DIR="$HOME/dotfiles"HOME_DIR="$HOME"CONFIG_DIR="$HOME/.config"DOTFILES_HOME_DIR="$DOTFILES_DIR/home"DOTFILES_CONFIG_DIR="$DOTFILES_DIR/config"
# Create backup directoryBACKUP_DIR="$HOME/.dotfiles_backup/$(date +%Y%m%d_%H%M%S)"mkdir -p "$BACKUP_DIR"echo "Created backup directory at $BACKUP_DIR"
# Function to backup and create symlinkslink_file() { local src="$1" local dest="$2"
# Back up existing files if [ -e "$dest" ] && [ ! -L "$dest" ]; then echo "Backing up $dest to $BACKUP_DIR/" mv "$dest" "$BACKUP_DIR/" elif [ -L "$dest" ]; then echo "Removing existing symlink $dest" rm "$dest" fi
# Create symlink echo "Creating symlink $dest -> $src" ln -sf "$src" "$dest"}
# Link home directory dotfilesecho "Linking home directory dotfiles..."for file in "$DOTFILES_HOME_DIR"/.*; do [ -f "$file" ] || continue filename=$(basename "$file") link_file "$file" "$HOME_DIR/$filename"done
# Link .config directory filesecho "Linking .config directory files..."mkdir -p "$CONFIG_DIR"for dir in "$DOTFILES_CONFIG_DIR"/*; do [ -d "$dir" ] || continue dirname=$(basename "$dir") link_file "$dir" "$CONFIG_DIR/$dirname"done
echo "Dotfiles installation complete!"EOF
chmod +x ~/dotfiles/install.shgit add ~/dotfiles/install.shgit commit -m "Add installation script"
Handling My Private Info
I should handle sensitive data like my email carefully:
- In my dotfiles version of
.gitconfig
, I add:
[include] path = ~/.gitconfig.local
- I keep personal info separate:
# This file stays local, not in gitcat > ~/.gitconfig.local << EOF[user] name = My Name email = my.email@example.comEOF
To be honest, I completely forgot about my email in the .gitconfig file, so it’s still being tracked. But my email is leaked elsewhere anyhow :D
Using My Setup
When I make changes:
- I edit files in my
~/dotfiles
repository - Changes appear in both places because of the symlinks
- I commit the changes:
cd ~/dotfilesgit add .git commit -m "Update configs"git push
When I get a new machine:
- I clone my repository:
git clone https://github.com/myusername/dotfiles.git ~/dotfiles
- I run my script:
cd ~/dotfiles./install.sh
That’s it! My entire environment follows me wherever I go.