Git post-receive hook не удаляет удаленные файлы из мастера
Я создал на своем сервере пустое git-репо и настроил следующий хук после получения из этого блога:
#!/bin/bash
while read oldrev newrev ref
do
branch=`echo $ref | cut -d/ -f3`
if [ "master" == "$branch" ]; then
git --work-tree=/path/to/my/project/live/ checkout -f $branch
echo 'Changes pushed live.'
fi
if [ "develop" == "$branch" ]; then
git --work-tree=/path/to/my/project/dev/ checkout -f $branch
echo 'Changes pushed to dev.'
fi
done
Так что всякий раз, когда я отправляю локально на свой сервер, изменения автоматически публикуются в папке каждой ветви без необходимости извлечения вручную.
Я установил правильные права доступа для обеих папок dev:
drwxrwsr-x 2 git git 4096 Sep 29 12:10 live/
drwxrwsr-x 2 git git 4096 Sep 29 12:09 dev/
И отталкивание от развивающейся ветки работает как положено. Проблема возникает, когда я извлекаю основную ветку и выполняю слияние. Когда я нажимаю мастер, новые файлы копируются в оперативную папку на моем сервере, но удаленные локально файлы не удаляются.
Как сделать так, чтобы пост-получение корректно обновляло живую папку? Спасибо!
2 ответа
Проблема в том, что git не знает, что удалить (у него нет индекса в рабочем дереве, отслеживающего такие вещи). Должна быть возможность решить эту проблему с помощью индекса для каждого рабочего дерева, но я думаю, что проще всего git checkout -f
в новый пустой каталог, затем переименуйте новый каталог и старый, чтобы новая версия "заработала". Это также уменьшает окно состояния гонки: теперь есть только один короткий момент (между mv
операции), когда нет версии, вместо немного более длинного окна (во время checkout
) когда есть смесь старых и новых версий.
Примечание. Сценарий, который вы показываете, не работает, если есть тег с именем master
или же develop
в качестве имен ссылок для этих двух refs/tags/master
а также refs/tags/develop
соответственно. Я бы порекомендовал исправить это (если вы заботитесь:-)) через функцию оболочки и case
операторы для сокращения процессов, возникающих при не развертывании, например:
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
(примечание: полностью не проверено).
Я столкнулся с той же проблемой. Я искал rsync для копирования файлов папки tmp в папку live, но потом понял, почему бы просто не использовать git glean в рабочем дереве.
Я не уверен, что это будет плохо, но он должен только удалить неотслеживаемые файлы из папки и использовать ваши настройки.gitignore, чтобы не удалять файлы, не входящие в ваш репозиторий.
Кажется, он выполняет то, что я хочу - очистить оставшиеся файлы, которые не были удалены нажатием.
#!/bin/sh
while read oldrev newrev refname
do
branch=$(git rev-parse --symbolic --abbrev-ref $refname)
if [ "master" == "$branch" ]; then
GIT_WORK_TREE=/home/store/public_html git checkout -f master
GIT_WORK_TREE=/home/store/public_html git clean -fd
fi
if [ "test" == "$branch" ]; then
GIT_WORK_TREE=/home/store/test_html git checkout -f test
GIT_WORK_TREE=/home/store/test_html git clean -fd
fi
if [ "dev" == "$branch" ]; then
GIT_WORK_TREE=/home/store/dev_html git checkout -f dev
GIT_WORK_TREE=/home/store/dev_html git clean -fd
fi
done