强制git运行post-receive hook,即使一切都是“最新的”

时间:2012-12-03 04:26:30

标签: git

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

背景

我使用git自动将网站部署到服务器。我在服务器的受保护区域中有一个简单的repo和一个post-receive挂钩,它检查内容并系统地将某些文件复制到public_html文件夹中。 (灵感来自this tutorial

我厌倦了在服务器上手动修改post-receive挂钩,所以我的post-receive挂钩现在实际上从回购中复制了自己的新版本:

#!/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的情况下调用ssh挂钩?

我尝试了什么

git push
git push -f

9 个答案:

答案 0 :(得分:53)

使用' - 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 post replacement脚本,然后它将再次推送(使用--allow-empty标志),然后执行更新的post-receive脚本

答案 1 :(得分:22)

我知道这可能会被认为是"危险"但我喜欢生活在边缘。

我只是删除了远程分支,然后再次推送它。确保您的本地分支机构是最新的,以限制丢失东西的可能性。

因此,如果我想触发post-receive,在我的情况下要让测试分支进行配置,我所做的就是:

$ git push origin :testing
$ git push origin testing
但是,不要接受这个作为答案。它更像是一个公平的事情。

答案 2 :(得分:13)

我担心你必须ssh到服务器并手动运行钩子脚本。如果没有任何内容,git push不会使服务器运行预推送预接收收件后挂钩添加(即当git打印一切都是最新的)。

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

将名为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!
...

答案 3 :(得分:10)

如果您想避免伪造提交,只需使用

即可
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'

答案 4 :(得分:3)

我尝试了empty commitsdelete upload branch

但是直接的ssh命令怎么样:

ssh your_host /path/to/your_repo/hooks/post-receive

答案 5 :(得分: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

答案 6 :(得分:1)

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

  

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

在我的情况下,我正在测试我的localhost上的post-receive钩子对着裸存储库。警告/非常重要,请在 remote 服务器位置上运行此命令

git update-ref -d refs/heads/develop 

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

答案 7 :(得分:0)

在我的情况下,我登录到远程并运行:

$ sh project.git/hooks/post-receive

工作正常!

答案 8 :(得分:0)

我做了一个bash函数来做到这一点。它假设您有ssh访问权限,~/.ssh/config可以相应地设置。默认遥控器是原点

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

来源并运行kick-git [remote]