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
Другие вопросы по тегам