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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13677125/
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-19 07:51:02  来源:igfitidea点击:

Force git to run post-receive hook, even if everything is "up-to-date"

git

提问by AndyL

How do I force gitto run a post-receivehook on a server even if I don't have a new commit to push?

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

Background

背景

I use git to automatically deploy a website to a server. I have a bare repo in a protected area of the server and a post-receivehook that checks out the contents and systematically copies over certain files into a public_htmlfolder. (Inspired by this tutorial)

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

I got tired of modifying the post-receivehook manually on the server, so my post-receivehook now actually copies over a new version of itself from the repo:

我厌倦了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

The problem, of course, is that the new post-receivehook never gets run. A seemingly simple solution would be merely to push again, but now everything is already up to date. This is annoying, because it requires me to fake a new commit every time I update the post-receivehook. Is there a way to invoke the post-receivehook without faking a commit or sshing in?

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

What I tried

我试过的

git push
git push -f

回答by AndrewD

Use '--allow-empty'

使用'--allow-empty'

After the initial push replacing the script, you can do this :

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

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

The --allow-emptyflag overrides git's default behavior of preventing you from making a commit when there are no changes.

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

Use an alias and make your life even easier

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

Add the following to ~/.gitconfig

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

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

Now Just do git pushpr

现在就做 git pushpr

git pushpr

This will push any changes to master, which in your case will trigger your post receive replacement script, then it will push again (using the --allow-emptyflag) which will then execute your updated post-receivescript.

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

回答by Jamie Carl

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:

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

$ git push origin :testing
$ git push origin testing

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

不要接受这个作为答案。这更像是一个仅供参考的事情。

回答by pts

I'm afraid you have to ssh to the server and run the hook script manually. git pushdoesn't make the server run the pre-push, pre-receiveand post-receivehooks if there was nothing added (i.e. when git prints Everything up-to-date).

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

The rest of the answer is about version-tracking the post-receivehook, so you can modify it without sshing to the server.

答案的其余部分是关于对post-receive挂钩进行版本跟踪,因此您可以在不通过 SSH 连接到服务器的情况下对其进行修改。

Add a shell script named do-post-receiveto the local repository:

添加一个命名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'

Replace your hooks/post-receivehook on the server with:

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

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

(Make sure to chmod 755 hooks/post-receiveon the server.)

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

Push your changes from the local repository to the server, and watch your do-post-receivecode run:

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

$ git push origin master
...
remote: Hello, World!
...

回答by laughedelic

If you want to avoid making a fake newcommit, you can simply use

如果你想避免进行虚假的提交,你可以简单地使用

git commit --amend --no-edit

This will modify the last commit record and you will be able to use git push -f(assuming from your answer that you're fine with the overwrite).

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

  • convenient:it doesn't create an extra commit
  • good:it doesn't use explicit path for the hook in the remote repo
  • bad:you overwrite history, which is fine in your use case, but shouldn't be used in a shared repository
  • 方便:它不会创建额外的提交
  • 好:它没有为远程仓库中的钩子使用显式路径
  • 不好:您覆盖历史记录,这在您的用例中很好,但不应在共享存储库中使用


I use this command relatively often to fix something in the last commit before pushing, so I made an alias for it:

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

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

Now I can use it directly for the use case as yours (git amend), or

现在我可以像你一样直接将它用于用例(git amend),或者

  • to add (all) modified files to the last commit: git amend -a
  • to modify the message: git amend -m 'better message'
  • 将(所有)修改过的文件添加到最后一次提交: git amend -a
  • 修改消息: git amend -m 'better message'

回答by sites

I tried empty commitsand delete upload branch.

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

But what about a direct ssh command:

但是直接 ssh 命令呢:

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

回答by jthill

Post-receive is the wrong place for artificial command responses.

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

You want your server-side goodies in the pre-receive exit, dependent on the updated ref -- do e.g. git update-ref refs/commands/update-hooks @on the server, then you can e.g. git push server +@:commands/update-hooks, and in the server's pre-receive you can

你希望你的服务器端好东西在 pre-receive 出口中,取决于更新的 ref——git update-ref refs/commands/update-hooks @在服务器上做,然后你可以 eg git push server +@:commands/update-hooks,在服务器的 pre-receive 中你可以

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

回答by Bryce Guinta

I made a bash function to do this. It assumes that you have ssh access can ~/.ssh/configset accordingly. The default remote is origin

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

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

Source and run kick-git [remote]

来源和运行 kick-git [remote]

回答by Clay

I like Jamie Carl's suggestion but it doesn't work, and I got the error:

我喜欢杰米卡尔的建议,但它不起作用,我得到了错误:

remote: error: By default, deleting the current branch is denied, because the next error: 'git clone' won't result in any file checked out, causing confusion.

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

In my case I'm testing post-receive hooks on my localhost against a bare repository. Warning/super important, run this command onlyon the remoteserver location!

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

git update-ref -d refs/heads/develop 

It'll delete the reference for the develop branch (you may also need to delete any of the files you deployed for that branch too), then you can go ahead and do the git push deploy_localtest developor whatever push command you want for that branch.

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

回答by Cosme Marins

In my case i login into remote and run:

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

$ sh project.git/hooks/post-receive

$ sh project.git/hooks/post-receive

works fine!

工作正常!