74

即使我没有要推送的新提交,如何强制在服务器上git运行挂钩?post-receive

背景

我使用 git 自动将网站部署到服务器。我在服务器的受保护区域中有一个裸仓库,还有一个post-receive挂钩,可以检查内容并将某些文件系统地复制到public_html文件夹中。(受本教程启发)

我厌倦了post-receive在服务器上手动修改钩子,所以我的post-receive钩子现在实际上从 repo 复制了一个新版本:

#!/bin/sh

rm -rf ~/../protected/*
GIT_WORK_TREE=~/../protected git checkout -f

# Rewrite over this file with any updates from the post-receive file
cp ~/../protected/post-receive hooks/post-receive

# Delete public_html
# Copy stuff public_html

当然,问题是新的post-receive钩子永远不会运行。一个看似简单的解决方案只是再次推送,但现在一切都已经是最新的了。这很烦人,因为每次更新post-receive钩子时都需要我伪造一个新的提交。有没有办法在post-receive不伪造提交或sshing 的情况下调用钩子?

我试过的

git push
git push -f
4

9 回答 9

63

使用'--allow-empty'

在初始推送替换脚本后,您可以执行以下操作:

git commit --allow-empty -m 'push to execute post-receive'

--allow-empty标志覆盖了 git 的默认行为,即在没有更改时阻止您进行提交。

使用别名,让您的生活更轻松

将以下内容添加到~/.gitconfig

[alias]
    pushpr = "!f() { git push origin master;git commit --allow-empty -m 'push to execute post-receive';git push origin master; }; f"

现在就做git pushpr

git pushpr

这会将任何更改推送到 master,在您的情况下,这将触发您的 post 接收替换脚本,然后它将再次推送(使用--allow-empty标志),然后执行您更新的post-receive脚本。

于 2015-02-24T18:12:34.243 回答
25

I know this probably going to be considered "dangerous" but I like to live on the edge.

I just delete the remote branch and then push it again. Make sure your local branch is up-to-date first to limit the chance of losing stuff.

So if I want to trigger post-receive, in my case to get the testing branch to provision, all I do is:

$ git push origin :testing
$ git push origin testing

Don't accept this as the answer though. It's more of a just FYI thing.

于 2014-08-07T00:25:55.327 回答
15

如果您想避免做出虚假的提交,您可以简单地使用

git commit --amend --no-edit

这将修改最后一个提交记录,您将能够使用git push -f(假设您的回答可以覆盖)。

  • 方便:它不会创建额外的提交
  • 好:它不使用远程仓库中的挂钩的显式路径
  • 不好:您覆盖历史记录,这在您的用例中很好,但不应该在共享存储库中使用

我相对经常使用这个命令来修复推送前最后一次提交中的某些内容,所以我为它起了一个别名:

git config --global alias.amend 'commit --amend --no-edit'

现在我可以直接将它用于您的用例(git amend),或者

  • 将(所有)修改后的文件添加到最后一次提交:git amend -a
  • 修改消息:git amend -m 'better message'
于 2018-02-27T22:30:18.687 回答
13

恐怕您必须 ssh 到服务器并手动运行挂钩脚本。如果没有添加任何内容(即当 git 打印Everything up-to-dategit push时) ,不会使服务器运行pre-pushpre-receivepost-receive钩子。

其余的答案是关于版本跟踪post-receive钩子,因此您可以修改它而无需 ssh 到服务器。

do-post-receive向本地存储库添加一个名为的 shell 脚本:

$ ls -ld .git
$ echo 'echo "Hello, World!"' >do-post-receive
$ git add do-post-receive
$ git commit do-post-receive -m 'added do-post-receive'

hooks/post-receive将服务器上的钩子替换为:

#! /bin/sh
while read OLDID NEWID BRANCH; do
  test "$BRANCH" = refs/heads/master && eval "$(git show master:do-post-receive)"
done

(确保chmod 755 hooks/post-receive在服务器上。)

将您的更改从本地存储库推送到服务器,并观察您的do-post-receive代码运行:

$ git push origin master
...
remote: Hello, World!
...
于 2013-04-13T07:47:04.727 回答
3

我尝试了空提交删除了上传分支

但是直接 ssh 命令呢:

ssh your_host /path/to/your_repo/hooks/post-receive
于 2016-09-08T00:10:50.577 回答
2

我做了一个 bash 函数来做到这一点。它假定您具有 ssh 访问权限,可以~/.ssh/config进行相应设置。默认远程是原点

kick-git() {
    remote="${1:-origin}"
    ssh $(echo $(git remote get-url "$remote")/hooks/post-receive | tr ':' ' ')
}

源和运行kick-git [remote]

于 2018-01-09T18:33:48.663 回答
2

就我而言,我登录到远程并运行:

$ sh project.git/hooks/post-receive

工作正常!

于 2017-12-05T17:24:56.650 回答
2

接收后是人工命令响应的错误位置。

您希望您的服务器端好东西在预接收出口中,这取决于更新的参考 - 例如git update-ref refs/commands/update-hooks @在服务器上执行,然后您可以例如git push server +@:commands/update-hooks,并且在服务器的预接收中您可以

while read old new ref; do case $ref in
commands/update-hooks)
        maybe check the incoming commit for authorization
        update hooks here
        echo the results from the update
        denypush=1
        ;;
refs/heads/master)
        extreme vetting on master-branch updates here
        ;;
esac; done

((denypush)) && exit $denypush
于 2018-02-28T01:11:29.867 回答
1

我喜欢 Jamie Carl 的建议,但它不起作用,我得到了错误:

remote: error: 默认情况下,拒绝删除当前分支,因为下一个错误: 'git clone' 不会导致任何文件被检出,造成混乱。

就我而言,我正在我的本地主机上针对裸存储库测试接收后挂钩。警告/超级重要,remote服务器位置运行此命令!

git update-ref -d refs/heads/develop 

它将删除开发分支的引用(您可能还需要删除为该分支部署的任何文件),然后您可以继续为该分支执行git push deploy_localtest develop或任何您想要的推送命令。

于 2015-12-17T04:46:40.110 回答