Overview
video grab from Youtube
Setup
1. Create the bare repository (it lives hidden in your home)
1
2
| cd ~ # make sure you're in $HOME
git init --bare .dotfiles
|
2. Create a shell alias
you can use a normal-looking config command instead of typing the long –git-dir and –work-tree every time.
For zsh (~/.zshrc):
1
2
| echo 'alias dotfiles="/usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME"' >> ~/.zshrc
source ~/.zshrc
|
3. Tell Git to hide untracked files by default
(This is very important — otherwise config status will show hundreds/thousands of untracked files every time.)
1
| dotfiles config --local status.showUntrackedFiles no
|
4. Create a .gitignore right away - Optional
1
2
| mkdir -p ~/.config/dotfiles
nvim ~/.config/dotfiles/ignore
|
ignore content
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| # Home clutter
Downloads/
Desktop/
Documents/
Music/
Pictures/
Videos/
# Cache / state
.cache/
.local/share/
.local/state/
# SSH private material (never commit)
.ssh/id_*
.ssh/known_hosts
# GPG
.gnupg/
# Language tooling
.npm/
.cargo/
.rustup/
.go/
.gradle/
.maven/
# Neovim junk
.config/nvim/.luarc.json
.config/nvim/.cache/
# OS / editor
.DS_Store
Thumbs.db
|
5. Tell the bare repo to use this ignore file
1
| dotfiles config core.excludesFile ~/.config/dotfiles/ignore
|
6. Create setup.sh
1
| nvim ~/.config/dotfiles/setup.sh
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| #!/usr/bin/env bash
set -e
DOTFILES_DIR="$HOME/.dotfiles"
CONFIG_DIR="$HOME/.config"
echo "[*] Setting up dotfiles environment..."
# --- Git alias -------------------------------------------------
if ! grep -q "alias dotfiles=" "$HOME/.zshrc" 2>/dev/null; then
echo "alias dotfiles='/usr/bin/git --git-dir=$DOTFILES_DIR --work-tree=$HOME'" >> "$HOME/.zshrc"
fi
if ! grep -q "alias dotfiles=" "$HOME/.bashrc" 2>/dev/null; then
echo "alias dotfiles='/usr/bin/git --git-dir=$DOTFILES_DIR --work-tree=$HOME'" >> "$HOME/.bashrc"
fi
# --- Git config ------------------------------------------------
/usr/bin/git --git-dir="$DOTFILES_DIR" --work-tree="$HOME" \
config --local status.showUntrackedFiles no
/usr/bin/git --git-dir="$DOTFILES_DIR" --work-tree="$HOME" \
config core.excludesFile "$CONFIG_DIR/dotfiles/ignore"
# --- Ensure directories ---------------------------------------
mkdir -p \
"$CONFIG_DIR/zsh" \
"$CONFIG_DIR/bash" \
"$CONFIG_DIR/fish" \
"$CONFIG_DIR/nvim" \
"$CONFIG_DIR/wezterm" \
"$CONFIG_DIR/tmux" \
"$CONFIG_DIR/dotfiles"
echo "[+] Dotfiles setup complete"
|
1
| chmod +x ~/.config/dotfiles/setup.sh
|
7. Add dotfiles to Git
1
2
3
4
5
6
7
8
9
10
| dotfiles add .zshrc
dotfiles add .bashrc
dotfiles add .config/dotfiles
dotfiles add .config/zsh
dotfiles add .config/bash
dotfiles add .config/fish
dotfiles add .config/nvim
dotfiles add .config/wezterm
dotfiles add .config/tmux
dotfiles add .config/starship
|
Check:
Then commit:
1
| dotfiles commit -m "Initial dotfiles"
|
8. Push to GitHub
1
2
| dotfiles remote add origin git@github.com:YOURUSERNAME/.dotfiles.git
dotfiles push -u origin main
|
Restoring Dotfiles on new system
Create restore.sh
1
| nvim ~/.config/dotfiles/restore.sh
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
| #!/usr/bin/env bash
set -e
REPO_URL="git@github.com:USERNAME/.dotfiles.git"
DOTFILES_DIR="$HOME/.dotfiles"
CONFIG_DIR="$HOME/.config"
BACKUP_DIR="$HOME/.dotfiles-backup-$(date +%Y%m%d-%H%M%S)"
echo "[*] Restoring dotfiles..."
# --- Clone bare repo if missing -------------------------------
if [ ! -d "$DOTFILES_DIR" ]; then
echo "[*] Cloning bare dotfiles repo..."
git clone --bare "$REPO_URL" "$DOTFILES_DIR"
else
echo "[*] Dotfiles repo already exists"
fi
# --- Temporary alias ------------------------------------------
alias dotfiles='/usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME'
# --- Git config ------------------------------------------------
dotfiles config --local status.showUntrackedFiles no
dotfiles config core.excludesFile "$CONFIG_DIR/dotfiles/ignore"
# --- Attempt checkout -----------------------------------------
echo "[*] Checking out dotfiles..."
if ! dotfiles checkout; then
echo "[!] Conflicts detected — backing up existing files to:"
echo " $BACKUP_DIR"
mkdir -p "$BACKUP_DIR"
dotfiles checkout 2>&1 | grep -E "^\s+" | awk '{print $1}' | while read -r file; do
mkdir -p "$BACKUP_DIR/$(dirname "$file")"
mv "$HOME/$file" "$BACKUP_DIR/$file"
done
echo "[*] Retrying checkout..."
dotfiles checkout
fi
# --- Pull latest changes --------------------------------------
dotfiles pull
# --- Ensure setup is applied ----------------------------------
if [ -x "$CONFIG_DIR/dotfiles/setup.sh" ]; then
echo "[*] Running setup.sh..."
bash "$CONFIG_DIR/dotfiles/setup.sh"
fi
echo "[+] Dotfiles restored successfully"
|
⚠️ IMPORTANT
Replace this line with your real repo:
1
| REPO_URL="git@github.com:USERNAME/.dotfiles.git"
|
1
2
3
4
| chmod +x ~/.config/dotfiles/restore.sh
dotfiles add ~/.config/dotfiles/restore.sh
dotfiles commit -m "Add restore.sh for safe dotfiles recovery"
dotfiles push
|
restore on a brand-new machine
Install Git:
1
2
| sudo pacman -S git # Arch
sudo apt install git # Debian/Kali/Ubuntu
|
Run restore:
1
| bash ~/.config/dotfiles/restore.sh
|
Cheatsheet
📍 Repo facts
- Git dir:
~/.dotfiles - Work tree:
$HOME - Manager alias:
dotfiles🔧 One-time setup (on first machine)
1
2
3
4
| git init --bare ~/.dotfiles
alias dotfiles='/usr/bin/git --git-dir=$HOME/.dotfiles --work-tree=$HOME'
dotfiles config --local status.showUntrackedFiles no
dotfiles config core.excludesFile ~/.config/dotfiles/ignore
|
➕ Track files / configs
1
2
3
4
5
6
7
8
9
10
11
| dotfiles add .zshrc
dotfiles add .bashrc
dotfiles add .tmux.conf
dotfiles add .config/zsh
dotfiles add .config/fish
dotfiles add .config/nvim
dotfiles add .config/wezterm
dotfiles add .config/tmux
dotfiles add .config/starship.toml
dotfiles add .config/dotfiles
|
📋 Status & diff
1
2
3
| dotfiles status
dotfiles diff
dotfiles diff --staged
|
💾 Commit & push
1
2
| dotfiles commit -m "message"
dotfiles push
|
First push only:
1
2
3
| dotfiles remote add origin git@github.com:USERNAME/dotfiles.git
dotfiles branch -M main
dotfiles push -u origin main
|
⬇️ Pull updates
🖥️ Restore on a new machine (recommended)
1
| bash ~/.config/dotfiles/restore.sh
|
Manual restore (if needed):
1
2
3
| git clone --bare git@github.com:USERNAME/dotfiles.git ~/.dotfiles
alias dotfiles='/usr/bingit --git-dir=$HOME/.dotfiles --work-tree=$HOME'
dotfiles checkout
|
⚠️ Fix checkout conflicts
1
2
3
| mv ~/.zshrc ~/.zshrc.bak
mv ~/.bashrc ~/.bashrc.bak
dotfiles checkout
|
Or fully automated (preferred):
1
| bash ~/.config/dotfiles/restore.sh
|
🧹 Stop tracking a file (keep it locally)
1
2
| dotfiles rm --cached ~/.config/nvim/init.lua
dotfiles commit -m "Stop tracking nvim init"
|
🗑️ Remove from repo + system
1
2
| dotfiles rm ~/.tmux.conf
dotfiles commit -m "Remove tmux config"
|
🔍 Show tracked files
1
| dotfiles ls-tree -r --name-only HEAD
|
🔄 Rename / move a config
1
2
| dotfiles mv .config/nvim/init.vim .config/nvim/init.lua
dotfiles commit -m "Rename nvim init"
|
🧪 Test without touching files
1
| dotfiles checkout --dry-run
|
🔧 Run setup again (safe)
1
| bash ~/.config/dotfiles/setup.sh
|
🧾 Common paths (quick reference)
1
2
3
4
5
| ~/.config/nvim/init.lua
~/.config/wezterm/wezterm.lua
~/.config/tmux/tmux.conf
~/.config/fish/config.fish
~/.config/starship/starship.toml
|
🏆 Golden rules
❌ Never run git directly → always use dotfiles
❌ Never delete ~/.dotfiles
✅ Track only what you explicitly add
✅ Use restore.sh on new machines
✅ Keep secrets out (or encrypt)