So, you got yourself into a bit of a pickle with your configuration files again, did you? Well, fortunately you had the good sense to document what you did all those [time-units] ago.

You may not remember, but I do… past-past you thought it would be swell to manage files with GNU Stow. And things were good and didn’t really break or anything, and we moved across serveral distros and a pretty major shift from MacOS to our foreverOS, but here I am telling you that the symlinks were causing some unnecessary complexity.

Ergo we git all the things.

What did we/I/he stow exactly?

TBH, I can’t remember myself. Let’s take a look…

rg-i-stow

Hmmm. Not very helpful. Unless you’re heading to Mid Ulster.

Commandline history tho…

cd ~/.dotfiles && stow --verbose=3 -S -n -d ~/.config/test-stow -t ~/.dotfiles

Yeah. No notes. Good job. /s

Just nuke that dir and do the startovers. By “nuke” I mean mv ~/.dotfiles .dotfiles--DELETEME cause, ya know, safety first.

Make repository remotely

Do the usuals at the your remote.

For most peeps, and for me, this is github. And a private repository in this case. Sorry. I’ve not audited what maybe should and should not be “in the wild”. Anyway, this is for future me.

clone remote to local

git clone --bare [email protected]:salopst/dotfiles.git $HOME/dotfiles

OK. Cool. What have we just done?

This creates a directory, ~/dotfiles, which, looking at it, has the same layout of ANY .git directory you will find in a regular, non-bare, repo.

The practical magic of the bare-repository approach to dotfile management (first, famously, posted here: https://www.atlassian.com/git/tutorials/dotfiles, and repeated on countless personal blogs ever since) now comes with referencing all subsequent git commands relative to this “pseudo-.git”. That is dotfiles is, effectively the .git for $HOME.

Yeah, that sounds confusing. Basically one uses one’s usual git commands, but they are prefixed with --git-dir=$HOME/dotfiles/ --work-tree=$HOME

So, for example, a git status is now a git --git-dir=$HOME/dotfiles/ --work-tree=$HOME status

Which is obvs a PITA, so we set up aliases/functions in the usual places… shell rc files and their inclusions.

Imma gonna use:

gitdot () {
  git --git-dir="$HOME/dotfiles" --work-tree="$HOME" "$@"
}

But then I also pushed this onto the end of my rarely used .bashrc:

echo "\n# 2021-10-15\nalias gitdot='/usr/bin/git --git-dir=$HOME/dotfiles/ --work-tree=$HOME'" >> $HOME/.bashrc

Or One could add a git alias to global git config

git config --global alias.gitdot 'git --git-dir=$HOME/.dotfiles --work-tree=$HOME'

Which is probably neater. But then I have mixed aliases across various configs anyway, so not gonna do that just yet. Perhaps AFTER these unruly things are brought under control… they very point of doing all this anyway!

Don’t show untracked files

After sourcing, this means that the following commands are equivalent:

  • git --git-dir=$HOME/dotfiles/ --work-tree=$HOME status
  • gitdot status

Running either of these will show a bunch of untracked files… a LOT of them because, well, essentially the whole of $HOME is a repository (--work-tree=$HOME, remember?).

Since our dotfiles is our .git, let’s supress output of these untrack files and directories by simple adding:

[status]
	showUntrackedFiles = no

to $HOME/dotfiles/config

I’ve seen people suggesting the equivalent of using git config --local to set status.showUntrackedFiles no but that is opaque, doesn’t drill home what a bare repository is, and can lead to coflicts with other git configs elsewhere in the config chain.

add and commit and push away to the intertubes…

The full commands, not using the alias for clarity:

git --git-dir=$HOME/dotfiles/ --work-tree=$HOME add ~/.gemrc
git --git-dir=$HOME/dotfiles/ --work-tree=$HOME commit -m "initial commit"
git --git-dir=$HOME/dotfiles/ push -u origin main

Errm. Naming conventions

It was probably a mistake to use dotfiles. .gitdotfiles may have been clearer, but this is why we keep notes, right? All I have to do is remember (Oh, brother!) that dotfiles is not a regular directory.

Oh noes. I’ve done some horrible things locally…

If they are not commited: git --git-dir=$HOME/dotfiles/ --work-tree=$HOME checkout -f HEAD

If they are committed, then checkout the whatever-hash

If they are committed and pushed. Same as above, and be wary, cause git is not a backup, OK?




Working with existing dotfiles

So setting up a new machine from an existing Git should mean: gitdot checkout

This should place the tracked files in $HOME from the bare dotfiles repo.

$DOTFILES is exported from ~/.zshenv

gitdot () {
  git --git-dir="$HOME/dotfiles" --work-tree="$HOME" "$@"
}

gitdotnew () {
  git clone --bare $1 $DOTFILES
  gitdot config --local status.showUntrackedFiles no
}

gitdotrestore () {
  git clone --bare $1 $DOTFILES
  gitdot config --local status.showUntrackedFiles no
  gitdot checkout || echo -e 'Files conflict. Overwrite with gitdot checkout -f'
}