用于网站登台的 Git Post-Receive Hook

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3838727/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 09:12:12  来源:igfitidea点击:

Git Post-Receive Hook for Website Staging

gitgit-post-receive

提问by Matt

I'm trying to set up Git for staging my website so that I can git pullto get the current version to work on locally and then git pushto push the changes to the remote server. I've got it set up so that it works the way I want it to, but after I push, I have to manually run git checkout -for git reset --hard HEADon the remote server.

我正在尝试设置 Git 来登台我的网站,以便我可以git pull让当前版本在本地工作,然后git push将更改推送到远程服务器。我已经对其进行了设置,使其按照我想要的方式工作,但是在我推送之后,我必须手动运行git checkout -fgit reset --hard HEAD在远程服务器上运行。

I've tried putting these into a shell script as the post-receive hook on the server, but it just doesn't seem to have any effect. I know that the script is running because I'm seeing "Changes pushed to server" after I push. Here's the post-receive hook:

我已经尝试将它们作为服务器上的 post-receive 钩子放入一个 shell 脚本中,但它似乎没有任何效果。我知道脚本正在运行,因为我在推送后看到“更改已推送到服务器”。这是接收后挂钩:

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

回答by Paul

The answer to your question is here: http://toroid.org/ams/git-website-howto

您的问题的答案在这里:http: //toroid.org/ams/git-website-howto

In short, what you want to do is add a "detached work tree" to the bare repository. Normally you think of your work tree as containing the .gitdirectory. Bare repositories do not have a work tree by definition, but you can create one as long as it's in a different directory than the bare repo.

简而言之,您要做的就是将“分离的工作树”添加到裸存储库中。通常您认为您的工作树包含.git目录。根据定义,裸存储库没有工作树,但您可以创建一个,只要它与裸存储库位于不同的目录中。

The post-receive hook is just a simple git checkout -fto replicate the repository's HEADinto the work directory. Apache uses that as its document root, and you're all set. Any time you push to the bare repository, Apache will immediately start serving it.

post-receive hook 只是git checkout -f将存储库复制HEAD到工作目录中的一个简单方法。Apache 使用它作为它的文档根目录,一切就绪。每当您推送到裸存储库时,Apache 都会立即开始为其提供服务。

I generally use this to automatically push to a staging server to see if the "real" environment will puke on my changes. Deploying to the live server is a completely different story. :-)

我通常使用它来自动推送到临时服务器,以查看“真实”环境是否会影响我的更改。部署到实时服务器是一个完全不同的故事。:-)

回答by VonC

Update March 2015

2015 年 3 月更新

As I mentioned in "What is this Git warning message when pushing changes to a remote repository?", you actually can push directlyto a non-bare repo now (Git 2.3.0+, February 2015) with:

正如我在“将更改推送到远程存储库时这条 Git 警告消息是什么?”中提到的,您现在实际上可以直接推送到非裸存储库(Git 2.3.0+,2015 年 2 月):

git config receive.denyCurrentBranch updateInstead

Update the working tree accordingly, but refuse to do so if there are any uncommitted changes.

相应地更新工作树,但如果有任何未提交的更改,则拒绝这样做。

That would allow you to avoid any post-receive hook.

这将允许您避免任何 post-receive hook。



(Original answer: Oct 2010)

(原答案:2010 年 10 月)

The GitFAQrecommends for non-bare repothis post-update hook:
(it might give you more clue as to what is actually going on in the hook execution. Note this is a post-update hook, not a post-receive)

GitFAQ建议非裸露回购此更新后的挂钩:
(它可能给你更多的线索,以什么在钩执行实际上是怎么回事注意,这是一个更新后的挂钩,而不是后领取。)

#!/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=
    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

For this to work, you would still need to specifically allow pushing changes to the current branch by using either one of these configuration settings:

为此,您仍然需要使用以下任一配置设置专门允许将更改推送到当前分支:

git config receive.denyCurrentBranch ignore

or

或者

git config receive.denyCurrentBranch warn

回答by ido

I had the exact same issue. In a reply to this link: http://toroid.org/ams/git-website-howto- The following command has done it:

我有完全相同的问题。在对此链接的回复中:http: //toroid.org/ams/git-website-howto- 以下命令已完成:

sudo chmod +x hooks/post-receive

We missed a sudopermission first configured the stuff.

我们错过了sudo首先配置的东西的权限。

回答by Tronic

Fixed version of VonC's script, works for me (absolutely no guarantees).

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=
    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

回答by Honza

Simple script for setting this git deployment:

用于设置此 git 部署的简单脚本:

Preparing post-receive hook:

准备 post-receive hook:

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

Allowing push into this repository, though it is not bare:

允许推送到这个存储库,虽然它不是空的:

git config receive.denycurrentbranch false

回答by takeshin

I'm just guessing, but this may be some permission issue (full path needed? cd?). Check what is really happening in the log files.

我只是猜测,但这可能是一些权限问题(需要完整路径cd??)。检查日志文件中真正发生了什么。

However publishing the files via git is always just one tasks of the publishing process. You usually need to copy some files, delete other, setup, update permissions, generate docs etc.

然而,通过 git 发布文件始终只是发布过程的一项任务。您通常需要复制一些文件、删除其他文件、设置、更新权限、生成文档等。

For a complex solution a build script might be better than any git hook. Tools which can handle those tasks very well:

对于复杂的解决方案,构建脚本可能比任何 git hook 都好。可以很好地处理这些任务的工具:

(I realize this is not the answer you are expecting, but it's too long to post as a comment)

(我意识到这不是您期望的答案,但作为评论发布太长了)