Migrating the Mac from ~/.config-as-repo → ~/dotfiles-MacBook
Right now your Mac is the odd one out: the repo is ~/.config (you cloned it
straight there, and $ZDOTDIR + dotsync point inside it). The nine other Unix
machine repos — seven Linux distros plus the two role repos — live at ~/dotfiles-*
and symlink into ~/.config. This runbook moves the Mac onto that same model so
sync-core.sh and every assumption works uniformly.
It is written to be safe on your daily driver: you take a full backup first, nothing is deleted until the new setup is verified, and there’s a rollback at the bottom. Do this when you have 20 quiet minutes — not five minutes before a meeting.
Throughout,
<REMOTE>= your GitHub base, e.g.git@github.com:dotgibson.
0. Pre-flight (in the current ~/.config)
cd ~/.config
git status # commit/stash anything outstanding
git add -A && git commit -m "pre-migration snapshot" || true
git push
Confirm clean + pushed before continuing. GitHub is your off-machine backup.
1. Full local backup (the safety net)
tar -czf "$HOME/config-backup-$(date +%Y%m%d-%H%M%S).tar.gz" -C "$HOME" .config
ls -lh "$HOME"/config-backup-*.tar.gz # confirm it exists and is non-trivial
If anything goes sideways, §Rollback restores from this.
2. Build the new repo at ~/dotfiles-MacBook
Push the new structure (the files from this session: bootstrap.sh, os/,
zsh/, Brewfile, macos/, ssh/, README, .gitignore) to your
dotfiles-MacBook remote, then:
git clone <REMOTE>/dotfiles-MacBook ~/dotfiles-MacBook
cd ~/dotfiles-MacBook
# one-time initial vendoring, never the update path (same as the other repos).
# A RELEASED tag, never main — see the note below.
git subtree add --prefix=core <REMOTE>/dotfiles-core refs/tags/v7 --squash
# make the popup scripts executable (the outputs filesystem can't carry +x)
chmod +x core/tmux/scripts/*.sh core/bin/clip core/bin/clip-paste
git add -A && git commit -m "mark scripts executable" || true
git push
Don’t run
bootstrap.shyet — first clear the old repo-ness from~/.configin the next step, or the two will fight over the same files.
Why the tag, and why only once. Vendoring from
mainlands a tree at a commit nocore.lockrecords, andcore-integrityreports the fresh copy asTAMPERED. After this one-time add, Core updates arrive as a fan-out PR fromdotfiles-core— nevergit subtree pull, which movescore/without the lock. See Vendoring Core.
3. Turn ~/.config back into a plain directory
~/.config holds two kinds of things: files your old repo tracked (these get
recreated as symlinks) and configs other apps dropped there (these stay
untouched). We use git itself to tell them apart, so only the right files move.
cd ~/.config
# record exactly what the old repo tracked (for reference / cleanup)
git ls-files > ~/.config-old-tracked.txt
wc -l ~/.config-old-tracked.txt
# remove ONLY the old tracked files (everything is backed up + on GitHub)
git ls-files -z | xargs -0 rm -f
# prune now-empty dirs left behind (won't touch dirs other apps still use)
find ~/.config -type d -empty -delete 2>/dev/null || true
# stop ~/.config from being a git repo (keep the old .git aside, just in case)
mv ~/.config/.git ~/.config-old.git
Your running shell keeps working — it already loaded its config into memory.
4. Wire the new symlinks
cd ~/dotfiles-MacBook
./bootstrap.sh --links-only # symlinks Core + os/ into ~/.config and ~
bootstrap backs up any stray real file it finds at a target (as
*.pre-dotfiles.<timestamp>) before linking, so this is non-destructive even if
step 3 missed something. It also seeds ~/.config/git/local.gitconfig — open it
and put your real name/email there (it’s never tracked):
$EDITOR ~/.config/git/local.gitconfig # [user] name + email (+ signingkey if you sign)
Then provision packages and apply system prefs when ready:
./bootstrap.sh # Homebrew + brew bundle (full run)
./bootstrap.sh --macos-defaults # optional: apply macos/defaults.sh
5. Verify
exec zsh # fresh shell off the new symlinks
echo "$ZDOTDIR" # → ~/.config/zsh
ls -la ~/.zshenv ~/.config/zsh/.zshrc ~/.gitconfig ~/.config/nvim # all symlinks → ~/dotfiles-MacBook/...
Smoke test the things most likely to reveal a bad link:
- prompt loads (starship),
z/Ctrl+R(atuin)/Ctrl+G(sessionizer) work nvimopens clean (:checkhealthif paranoid);"+yythen paste elsewhere (clipboard)tmux→prefix+w/prefix+T/prefix+fpopups open (the promoted scripts)git config --get user.emailreturns your local identity;git diffshows deltadotsynclands you in~/dotfiles-MacBook
6. Clean up (only once everything above is green)
# orphaned per-target backups bootstrap may have made
find ~ ~/.config -maxdepth 2 -name '*.pre-dotfiles.*' -print # review, then delete
rm -rf ~/.config-old.git ~/.config-old-tracked.txt
# keep the tarball a few days, then:
# rm ~/config-backup-*.tar.gz
Rollback (if anything is wrong before cleanup)
# remove the half-migrated config and restore the snapshot
rm -rf ~/.config
tar -xzf ~/config-backup-<stamp>.tar.gz -C "$HOME"
mv ~/.config-old.git ~/.config/.git 2>/dev/null || true
exec zsh
You’re back to the pre-migration state. Nothing about ~/dotfiles-MacBook or the
GitHub repos is affected, so you can retry whenever.