Git Post-Receive Hook для размещения веб-сайта

Я пытаюсь настроить Git для размещения моего веб-сайта, чтобы я мог git pull получить текущую версию для локальной работы, а затем git push отправить изменения на удаленный сервер. Я настроил его так, чтобы он работал так, как я хочу, но после нажатия я должен вручную запустить git checkout -f или git reset --hard HEAD на удаленном сервере.

Я пробовал поместить их в сценарий оболочки в качестве обработчика post-receive на сервере, но, похоже, это не имеет никакого эффекта. Я знаю, что сценарий запущен, потому что после нажатия я вижу «Изменения отправлены на сервер». Вот крючок после получения:

#!/bin/sh
git reset --hard HEAD
echo "Changes pushed to server."

person Matt    schedule 01.10.2010    source источник
comment
@VonC: самая важная часть вашего ответа был написан в основном на bash языке, а голосующий, вероятно, утверждал, что он родной;)   -  person takeshin    schedule 01.10.2010


Ответы (6)


Ответ на ваш вопрос здесь: http://toroid.org/ams/git-website-howto

Короче говоря, вы хотите добавить «отдельное дерево работы» в пустой репозиторий. Обычно вы думаете, что ваше рабочее дерево содержит каталог .git. У голых репозиториев нет рабочего дерева по определению, но вы можете создать его, если оно находится в другом каталоге, чем голое репо.

Ловушка post-receive - это просто git checkout -f репликация HEAD репозитория в рабочий каталог. Apache использует это в качестве корня документа, и все готово. Каждый раз, когда вы нажимаете на чистый репозиторий, Apache немедленно начинает его обслуживать.

Обычно я использую это для автоматической отправки на промежуточный сервер, чтобы посмотреть, не подействует ли «реальная» среда на мои изменения. Развертывание на живом сервере - это совсем другая история. :-)

person Paul    schedule 01.10.2010
comment
Спасибо, я все еще новичок в Git, и когда я начал работу над этим проектом, я не был уверен, почему должен быть пустой репозиторий, когда я мог бы cd в корень документа и просто git init. Я думаю, теперь понимаю, что он просто хранит метаданные git вне корня документа. Это правильно? - person Matt; 01.10.2010
comment
Кроме того, пример в приведенной выше ссылке показывает, как начать с нуля и отправить на сервер из локального репозитория. Какой лучший способ получить чистый репозиторий (за пределами корня веб-документа) из того, который в настоящее время находится там? - person Matt; 01.10.2010
comment
Мэтт, на вашем центральном сервере обычно используется чистый репозиторий. Если у вас есть только одна копия репозитория и вы выполняете развертывание непосредственно из нее, вы быстро столкнетесь с проблемами. Создайте пустой репозиторий в другом каталоге с помощью git init --bare. Затем в вашем локальном клоне репозитория выполните git origin add path_to_central_repo, чтобы пометить новое центральное репо как оригинальное. Наконец, git push origin master отправит все, что вы сделали, мастеру. Создайте отдельное дерево работ из центрального репо, и вы будете размещать свой сайт с каждым push из вашего клона. - person Paul; 04.10.2010
comment
+1 ... Это решение кажется самым умным из того, что я нашел до сих пор ... Предоставляя возможность не только переносить изменения с помощью нескольких командных шагов ... но также поддерживать цепочку поставок, так сказать, когда работа выполняется непосредственно на сервере, требуя извлечения, когда изменения вносятся удаленно ... - person Edward J Beckett; 05.05.2012
comment
Веб-процесс Git - еще одна хорошая статья с небольшим другой подход. - person Ian Dunn; 15.08.2012

Обновление март 2015 г.

Как я упоминал в «Что это за предупреждающее сообщение Git при отправке изменений в удаленный репозиторий?», вы действительно можете нажать < em> напрямую в репозиторий без репо (Git 2.3.0+, февраль 2015 г.) с помощью:

git config receive.denyCurrentBranch updateInstead

Обновите рабочее дерево соответствующим образом, но откажитесь от этого, если есть какие-либо незафиксированные изменения.

Это позволит вам избежать перехвата после получения.


(Оригинальный ответ: октябрь 2010 г.)

GitFAQ рекомендует для non-bare repo этот крючок после обновления:
(он может дать вам больше подсказок относительно того, что на самом деле происходит при выполнении ловушки. Обратите внимание, что это ловушка после обновления, а не после получения)

#!/bin/sh
#
# This hook does two things:
#
#  1. update the "info" files that allow the list of references to be
#     queries over dumb transports such as http
#
#  2. if this repository looks like it is a non-bare repository, and
#     the checked-out branch is pushed to, then update the working copy.
#     This makes "push" function somewhat similarly to darcs and bzr.
#
# To enable this hook, make this file executable by "chmod +x post-update".

git-update-server-info

is_bare=$(git-config --get --bool core.bare)

if [ -z "$is_bare" ]
then
    # for compatibility's sake, guess
    git_dir_full=$(cd $GIT_DIR; pwd)
    case $git_dir_full in */.git) is_bare=false;; *) is_bare=true;; esac
fi

update_wc() {
    ref=$1
    echo "Push to checked out branch $ref" >&2
    if [ ! -f $GIT_DIR/logs/HEAD ]
    then
        echo "E:push to non-bare repository requires a HEAD reflog" >&2
        exit 1
    fi
    if (cd $GIT_WORK_TREE; git-diff-files -q --exit-code >/dev/null)
    then
        wc_dirty=0
    else
        echo "W:unstaged changes found in working copy" >&2
        wc_dirty=1
        desc="working copy"
    fi
    if git diff-index --cached HEAD@{1} >/dev/null
    then
        index_dirty=0
    else
        echo "W:uncommitted, staged changes found" >&2
        index_dirty=1
        if [ -n "$desc" ]
        then
            desc="$desc and index"
        else
            desc="index"
        fi
    fi
    if [ "$wc_dirty" -ne 0 -o "$index_dirty" -ne 0 ]
    then
        new=$(git rev-parse HEAD)
        echo "W:stashing dirty $desc - see git-stash(1)" >&2
        ( trap 'echo trapped $$; git symbolic-ref HEAD "'"$ref"'"' 2 3 13 15 ERR EXIT
        git-update-ref --no-deref HEAD HEAD@{1}
        cd $GIT_WORK_TREE
        git stash save "dirty $desc before update to $new";
        git-symbolic-ref HEAD "$ref"
        )
    fi

    # eye candy - show the WC updates :)
    echo "Updating working copy" >&2
    (cd $GIT_WORK_TREE
    git-diff-index -R --name-status HEAD >&2
    git-reset --hard HEAD)
}

if [ "$is_bare" = "false" ]
then
    active_branch=`git-symbolic-ref HEAD`
    export GIT_DIR=$(cd $GIT_DIR; pwd)
    GIT_WORK_TREE=${GIT_WORK_TREE-..}
    for ref
    do
        if [ "$ref" = "$active_branch" ]
        then
            update_wc $ref
        fi
    done
fi

Чтобы это сработало, вам все равно необходимо специально разрешить отправку изменений в текущую ветвь, используя любой из этих параметров конфигурации:

git config receive.denyCurrentBranch ignore

or

git config receive.denyCurrentBranch warn
person VonC    schedule 01.10.2010
comment
+1: сценарий может показаться громоздким или многословным, но на это есть веские причины; в отличие от грубых подходов к использованию простого git reset --hard или git checkout -f, он сохранит любые незафиксированные изменения в тайнике. - person Chris Johnsen; 01.10.2010
comment
Этот скрипт совершенно глупый и ничего не делает. Мне удалось его отремонтировать (надеюсь, правильно), смотрите мой ответ ... - person Tronic; 27.07.2012
comment
С Git 2.3 вам больше не нужен этот хук, вы можете использовать git config receive.denyCurrentBranch updateInstead. См. github.com/blog/1957-git-2-3 -выпущено. - person Aurelien; 15.03.2015
comment
@Aurelien Верно, хорошее замечание. Я отредактировал ответ, поскольку этот вариант был описан в stackoverflow.com/a/28262104/6309 в феврале прошлого года. - person VonC; 15.03.2015

У меня была такая же проблема. В ответе на эту ссылку: http://toroid.org/ams/git-website-howto - следующая команда сделала это:

sudo chmod +x hooks/post-receive

Мы пропустили sudo разрешение, сначала настроили материал.

person ido    schedule 04.01.2012

Исправленная версия скрипта VonC, у меня работает (абсолютно никаких гарантий).

#!/bin/sh
#
# This hook does two things:
#
#  1. update the "info" files that allow the list of references to be
#     queries over dumb transports such as http
#
#  2. if this repository looks like it is a non-bare repository, and
#     the checked-out branch is pushed to, then update the working copy.
#     This makes "push" function somewhat similarly to darcs and bzr.
#
# To enable this hook, make this file executable by "chmod +x post-update".

set -e

git update-server-info

is_bare=$(git config --get --bool core.bare)

if [ -z "${is_bare}" ]
then
    # for compatibility's sake, guess
    git_dir_full=$(cd $GIT_DIR; pwd)
    case $git_dir_full in */.git) is_bare=false;; *) is_bare=true;; esac
fi

update_wc() {
    ref=$1
    echo "Push to checked out branch $ref" >&2
    if [ ! -f ${GIT_DIR}/logs/HEAD ]
    then
        echo "E:push to non-bare repository requires a HEAD reflog" >&2
        exit 1
    fi
    if (cd ${GIT_WORK_TREE}; git diff-files -q --exit-code >/dev/null)
    then
        wc_dirty=0
    else
        echo "W:unstaged changes found in working copy" >&2
        wc_dirty=1
        desc="working copy"
    fi
    if git diff-index --cached HEAD@{1} >/dev/null
    then
        index_dirty=0
    else
        echo "W:uncommitted, staged changes found" >&2
        index_dirty=1
        if [ -n "$desc" ]
        then
            desc="$desc and index"
        else
            desc="index"
        fi
    fi
    if [ "$wc_dirty" -ne 0 -o "$index_dirty" -ne 0 ]
    then
        new=$(git rev-parse HEAD)
        echo "W:stashing dirty $desc - see git-stash(1)" >&2
        ( trap 'echo trapped $$; git symbolic-ref HEAD "'"$ref"'"' 2 3 13 15 ERR EXIT
        git update-ref --no-deref HEAD HEAD@{1}
        cd ${GIT_WORK_TREE}
        git stash save "dirty $desc before update to $new";
        git symbolic-ref HEAD "$ref"
        )
    fi

    # eye candy - show the WC updates :)
    echo "Updating working copy" >&2
    (cd ${GIT_WORK_TREE}
    git diff-index -R --name-status HEAD >&2
    git reset --hard HEAD
    # need to touch some files or restart the application? do that here:
    # touch *.wsgi
    )

}

if [ x"${is_bare}" = x"false" ]
then
    active_branch=$(git symbolic-ref HEAD)
    export GIT_DIR=$(cd ${GIT_DIR}; pwd)
    GIT_WORK_TREE="${GIT_DIR}/.."
    for ref in $(cat)
    do
        if [ x"$ref" = x"${active_branch}" ]
        then
            update_wc $ref
        fi
    done
fi
person Tronic    schedule 27.07.2012

Простой сценарий для настройки этого развертывания git:

Подготовка хука после получения:

echo '#!/bin/sh'        >  .git/hooks/post-receive
echo 'git checkout -f'  >> .git/hooks/post-receive
echo 'git reset --hard' >> .git/hooks/post-receive
chmod +x .git/hooks/post-receive

Разрешить push в этот репозиторий, хотя он и не пустой:

git config receive.denycurrentbranch false
person Honza    schedule 10.07.2013
comment
Вы также можете использовать внешнее рабочее дерево: git config core.worktree /path/to/workdir. Вы можете превратить пустой репозиторий в репозиторий с рабочим деревом (git config core.bare false) - person Vi.; 21.09.2013
comment
Зачем вам нужен git reset --hard BTW? - person Vi.; 21.09.2013
comment
Вы также можете добавить git diff -R --cached --name-status перед оформлением заказа, чтобы получить хороший список того, какие файлы обновляются на стороне отправки. - person Vi.; 21.09.2013
comment
Ви: Когда я пробовал это без git reset --hard, рабочее дерево sametime не было изменено, когда я нажимаю в репозиторий, и git вёл себя так, как если бы я вручную изменил файлы в рабочем дереве сервера. - person Honza; 21.09.2013

Я просто предполагаю, но это может быть проблема с правами доступа (нужен полный путь? cd?). Проверьте, что на самом деле происходит, в файлах журнала.

Однако публикация файлов через git - это всегда лишь одна из задач процесса публикации. Обычно вам нужно скопировать одни файлы, удалить другие, настроить, обновить разрешения, создать документы и т. Д.

Для сложного решения сценарий сборки может быть лучше любого крючка git. Инструменты, которые очень хорошо справляются с этими задачами:

  • phing (или муравей)
  • hudson + подключаемый модуль git

(Я понимаю, что это не тот ответ, которого вы ожидаете, но он слишком длинный, чтобы публиковать его в качестве комментария)

person takeshin    schedule 01.10.2010