how to sync dot files with git

this is one way (of many) to keep changes made to dot files (hidden, or files with names that begin with a period) in sync between hosts. this method serves my needs by keeping a source of truth in a master repository that can be cloned onto other machines (new workstation, new work laptop, etc.)

for safety, the dot files are manually copied to their final location. this is done to prevent undetected breakage on remote hosts. for instance, one could add the fortune command to the .bashrc file that is shared among all hosts. this is fine until one tries to scp a file to a host with an oddball version or configuration, and the extra output confuses scp, and the copy fails. this can be particularly insidious if the failure occurs during a cron job that has long been forgotten (weekly disk backups?), and all of the cron job’s output goes to a log, so no errors get mailed. now backups have silently stopped, and one doesn’t find out until a disk dies, and the last backup occurred days, weeks, or months ago. oops.

sure, the original problem is the lack of notification by the cron job, and that needs to be fixed, as well as the output from fortune that is causing the failure, but that too will have to wait because, right now, a host is down with a dead disk. (yes, it has happened…)

for the sake of illustration, this description assumes the following:

  • each host has a git repository living at $HOME/GITrepo.

  • the dot files on each host live in no particular directory. one can add /home/www/.conf (contrived) as easily as $HOME/.bashrc.

  • git access has been set up between hosts, e.g., passwordless ssh via keys.

  • files are synced between hosts via git push/pull et al.

  • dot files are manually copied from the local git repo to their proper destination.

  • subdirectories with host names exist for files that vary between hosts.

    • example: most hosts share a top level .tmux.conf, but host foo uses foo/.tmux.conf.

  • the hosts used are:

    • central server: grox

    • worksatation : idox

steps

grox

create repo for dot files:

git init $HOME/GITrepo/dots

test:

cd $HOME

pwd > tst
cat tst
/home/dave

cd $HOME/GITrepo/dots
pwd > tst
cat tst
/home/dave/GITrepo/dots

git add tst
git commit -m 'tst: initial commit. test file.'

git status
On branch master
nothing to commit, working directory clean

got log | cat
commit 4e5dd7a19d4b8cd48ce1f1006f260d53454ae5dc
Author: dave <dave>
Date:   Tue Sep 5 21:39:37 2017 +0000
    tst: initial commit. test file.
idox

create repo:

git clone ssh://grox.net/home/dave/GITrepo/dots/ $HOME/GITrepo/dots

cd $HOME/GITrepo/dots
cat tst
/home/dave/GITrepo/dots

git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean

git log
commit 4e5dd7a19d4b8cd48ce1f1006f260d53454ae5dc
Author: dave <dave>
Date:   Tue Sep 5 21:39:37 2017 +0000
    tst: initial commit. test file.

test with the tst file:

replace tst in the repo:

cd $HOME
pwd >tst
cat tst
/home/dave
cat tst >$HOME/GITrepo/dots/tst

commit the change:

cd $HOME/GITrepo/dots
git add tst
git commit -m 'tst: replaced from idox.'
git log -1
commit ee7a199e7cdd30afcbc39c6618831c437964ded6
Author: dave <dave>
Date:   Tue Sep 5 14:52:24 2017 -0700
    tst: replaced from idox.

push to the remote repo:

# cannot push while branch is checked out on remote
ssh grox '(cd $HOME/GITrepo/dots; git checkout --detach; )'
git push
# checkout on remote and verify change.
ssh grox '(cd $HOME/GITrepo/dots; git checkout master; git log -1; )'
# output indicates success:
/home/dave
clean up grox
rm $HOME/tst
cd $HOME/GITrepo/dots
git rm tst
git commit -m 'tst: remove test file.'
ls $HOME/tst $HOME/GITrepo/dots/tst
# not found

clean up idox:

rm $HOME/tst
cd $HOME/GITrepo/dots
# individual steps prob'ly not be necessary
# just being pedantic.
git fetch
git pull
ls $HOME/tst $HOME/GITrepo/dots/tst
# not found

start using. use .bashrc as example:

grox:

cd $HOME/GITrepo/dots
cp ~/.bashrc .
git add .bashrc
git commit -m '.bashrc: initial commit on grox.'

idox:

cd $HOME/GITrepo/dots
git pull
diff .bashrc $HOME/.bashrc

set up push from grox to idox

add remote repo to grox:
cd $HOME/GITrepo/dots
git remote add idox ssh://idox/home/dave/GITrepo/dots/
git push --set-upstream idox master
# To ssh://idox/home/dave/GITrepo/dots/
# ! [remote rejected] master -> master (branch is currently checked out)
ssh idox "(cd GITrepo/dots ; git checkout --detach ; )"
git push --set-upstream idox master
# To ssh://idox/home/dave/GITrepo/dots/
#   313f8ee..f999aa4  master -> master
#Branch master set up to track remote branch master from idox.
git push
# Everything up-to-date
git remote update idox
# Fetching idox
ssh idox "(cd GITrepo/dots ; git checkout origin ; )"
git push
# Everything up-to-date

merge, copy, enjoy, etc…