The problem is that git doesn't know what to remove (it does not have an index over in the work tree, keeping track of such things). It should be possible to solve this with an index for each work tree, but I think it's simpler to just git checkout -f
into a new, empty directory, then rename the new directory and the old one to make the new version "go live". This also shrinks the race condition window: now there's just one brief moment (between mv
operations) when there is no version, instead of a slightly longer window (during checkout
) when there is a mix of old and new versions.
Note: The script you show will go awry if there is a tag named master
or develop
as the reference names for those two are refs/tags/master
and refs/tags/develop
respectively. I'd recommend fixing this (if you care :-) ) via shell function and case
statements to cut down on process spawning in the non-deploy cases, e.g.:
die() {
echo "$@" >&2
exit 1
}
# deploy (to given path, $1) the version named by $2
# if the target is /some/path/there we use a temp version
# named /some/path/tmp.<pid> to hold the new one until we
# can swap it out, and $1.old.<pid> while we remove the old.
deploy() {
local path=$1 branch=$2
local tmpdir=${path%/*}/tmp.$$ # tune this as needed
echo "deploying $branch to $path via $tmpdir..."
trap "rm -rf $tmpdir" 0 1 2 3 15
mkdir $tmpdir || die "can't create work dir $tempdir"
git --work-tree=$tmpdir/ checkout -f $branch
mv $path $path.old.$$ ||
die "unable to move live version out of the way"
mv $tmpdir $path ||
die "unable to set new version live"
trap - 0 1 2 3 15
echo "done, cleaning up old version"
rm -rf $path.old.$$
}
while read oldrev newrev ref; do
case $ref in
refs/heads/master) deploy /path/to/my/project/live master;;
refs/heads/develop) deploy /path/to/my/project/dev develop;;
esac
done
(note: totally untested).