Tracking various personal machine configurations with my $HOME directory as a git bare repo
I currently don't have a way to (mostly) effortlessly backup various machine configuration, and as a result, I've lost various config files in a short period of time. It's set me back, timewise, and recrafting these files from memory isn't currently possible while I have an 11 m/o son climbing all over the place. This solution fits the specific case of backing up the mentioned files with the added benefit of version control.
- main - aimed to be a generic config branch for any nix disto (currently biased toward Fedora and Gnome).
- panda - my current laptop config. Most changes are in this branch.
- Below code is found here.
- I recommended that a git status prompt is used. Git comes with one disabled. Checkout The Git Book. [Bash|Zsh|PowerShell]
- These are all the environment variables I'm using with git's prompt. They are all documented in
/usr/share/doc/git/contrib/completion/git-prompt.sh
- Git also has various completions
/usr/share/doc/git/contrib/completion/git-completion.bash
/usr/share/doc/git/contrib/completion/git-completion.tcsh
/usr/share/doc/git/contrib/completion/git-completion.zsh
- I don't turn off untracked file listing for
git status
; rather, I use a.gitignore
file as an include list so that I only see the status of untracked files I care about. - or:
git add --force <whatever>
; then later add to.gitignore
- For sensetive files / directories, I'm using git-crypt from the Fedora repos (but the package is supported in other distros too). Right now, I'm using
git-crypt
for.gnupg/**
and.ssh/**
directories.
Wrapper pointing git to bare work-tree
and git-dir
export GIT_HOME_DIR=".git-home-$USER-$HOSTNAME"
git-home() {
# run git and specify the git directory as well as the working tree
command git --git-dir="$GIT_HOME_DIR" --work-tree="$HOME" "$@"
}
This initializes --bare
repo, additionally adds a .gitignore
that excludes everything by default. Selectively --force
add or create exceptions in .gitignore
git-home-init() {
# populate a .gitignore file and excluding everything
echo '*' > "$HOME"/.gitignore
# initialize the bare repo in your home directory
command git init --bare "$HOME"/"$GIT_HOME_DIR"
}
This git wrapper makes git just work like git. Most solutions I've found use a clunky function or alias, and this feels awkward to me. The function is using a simple conditional to check if in the work-dir
, and to use git-home
if so; otherwise call the git binary directly. Additionally, no need to add a case for git-crypt
. It actually gets passed into git-home
and acts like a git module (where you can call, for instance git <module>
or git-<module>
). So you can call it like git crypt <args>
git() {
# make the variables we'll use local in scope
local -a args first rest
# read-in arguments to an array ARGS
readarray args < <(printf -- "$*")
# capture the git command, for instance 'push'
first="${args[0]}"
# capture the rest of the arguments, for instancs '-u origin panda'
readarray rest < <(printf -- "${args[@]:1:${#args[@]}}")
# check if in the home dir bare repo.
# If so, use 'git-home' or 'git-home-init'; otherwise, call the git binary directly
if [[ $PWD = $HOME ]]; then
case "$first" in
init)
git-home-init ;;
*)
git-home "$first" "${rest[@]}"
esac
else
command git "${args[@]}"
fi
}
Add the above functions to some file that you source. I use a file in $HOME/.bashrc.d/
, but you can use .bashrc
or .profile
depending on your setup, then ...
~$ cd
~$ source ~/.bashrc.d/01-functions.rc
~$ git-home-init
~$ ls -Al | grep -E "$GIT_HOME_DIR|.gitignore"
~$ sep(){ for i in {1..79}; do ((i < 79 )) && printf = || printf "\n"; done; }; sep; cat .gitignore; sep; git status; sep
~$ echo '!.gitignore' >> .gitignore
~$ git status
At this point you should see that .gitignore
isn't tracked by git. If you want to keep this change (you most likely will), you can git add -A
, or if paranoid, git add .gitignore
; then git commit -m ...
as usual. If you don't want to keep the change, you can use whatever you want to remove the change (editor, sed), or you can do git restore .gitignore
.
Overall I think this setup is pretty handy.