2011-04-03 110 views
10

我有一个post-receive挂钩脚本坐在远程回购我推到不一个git reset --hard上混帐推硬复位

事情是这样的:

$ git push opal 
Counting objects: 74, done. 
Delta compression using up to 2 threads. 
Compressing objects: 100% (45/45), done. 
Writing objects: 100% (53/53), 16.68 KiB, done. 
Total 53 (delta 20), reused 0 (delta 0) 
remote: warning: updating the current branch 
remote: HEAD is now at 88f1e35 tweak lavalamp styles 

什么,我不明白这里是 - 远程表示头现在在XXX,但是当我登录到服务器 - 远程工作副本根本没有更新!

有什么想法吗?

+0

当你遇到问题时,你应该发布你的钩子脚本。 – 2011-04-04 03:35:44

+0

Chris,我的post-receive脚本只包含那一行。无需发布。 – David 2011-04-04 18:51:12

回答

0

那么脚本可能不会运行。它不会运行在愚蠢的http服务器上。 它会运行在ssh上。我不确定智能http服务器。

如果不是这样,你应该检查hook上的'execute'permssion(chmod + x .git/hooks/post-receive)。当你在这里时,通常检查owenership和权限。

如果看起来没问题,只需在脚本中包含一个作为第一行的日志语句(例如date "%T $0 executed" >> /tmp/debug_hook.log)并检查日志文件以查看是否更新了任何内容。

此外,它可能推动到而不是实际上做任何事情(一切都是最新的)。在这种情况下,有意义的是不叫钩子

如果所有这些都没有提示,请发布.git/config,因为它驻留在服务器上(或至少部分)。 git log -1 HEAD会在服务器上给出预期的结果吗?您的钩子脚本是否包含可能会覆盖GIT_DIR,GIT_WORK_TREE或GIT_INDEX_FILE的任何内容?

+0

'HEAD现在在......'消息只可能来自'git checkout'或'git reset'。这两者都不是正常推送的一部分,所以钩子脚本几乎肯定会运行。 – 2011-04-04 04:13:07

+0

您是否做过其他检查?特别是HEAD检查?读另一篇文章,你必须在'GIT_DIR'检查中得到一个积极的结果... – sehe 2011-04-04 06:25:54

22

问题是Git命令在为钩子脚本创建的环境与正常环境之间的行为差​​异。

首先,钩子脚本以其当前工作目录设置为Git目录本身(即非裸仓库的.git/目录)运行。其次,钩子脚本使用GIT_DIR环境变量集运行,并指向Git存储库(同样是非裸存储库的.git/目录)。

通常情况下,如果你尝试运行从.git/目录git reset --hard,它会与下面的消息死:

fatal: This operation must be run in a work tree 

但当GIT_DIR设置,Git命令假设当前目录是工作树。由于钩子运行时的当前目录是.git/目录,因此您的git reset --hard实际上是直接将您的工作树文件“检出”为.git/而不是其父目录(即,您现在在.git/目录中拥有版本化内容的副本)。

希望版本库中没有版本化的内容的路径名与pathnames that Git uses in Git repositories themselves一致。如果它们一致,那么你的git reset --hard将覆盖你的仓库的一些内部结构,你可能会想从其他仓库重新克隆它。如果你有信心,没有使用Git的内部路径名的版本内容冲突,那么你可以用这个把它清理干净:

# make a backup of your repository first! 
(cd .git && GIT_DIR=$PWD git ls-files -cz | xargs -0 rm) 

这只会删除当前跟踪的文件(它会留下有文件自从被移除后,但是在断钩处于活动状态时曾经被推入提示提交中)。


一种解决方法是调用Git命令之前,改变当前工作目录到正常工作树和取消GIT_DIR和GIT_WORK_TREE。

⋮ 
test "${PWD%/.git}" != "$PWD" && cd .. 
unset GIT_DIR GIT_WORK_TREE 
# you can now safely use Git commands 
⋮ 

另一种解决方案是显式重置GIT_DIR,在那里设置GIT_WORK_TREE和chdir。 Git FAQ “Why won't I see changes in the remote repo after "git push"?”建议post-update script这样做。链接的脚本也更加安全,因为如果索引或工作树在执行硬重置之前变脏,它会进行存储。

+0

优秀的东西,谢谢 – sehe 2011-04-04 06:29:02

+1

+1 Aargh,这是可怕的。更糟糕的是,我之前没有意识到$ PWD和$ GIT_DIR在非裸仓库中运行时对于不同的钩子是不一致的。 (例如,在'post-commit'中,它们分别设置为工作树和'.git'。) – 2011-04-09 08:02:14

+0

@Mark:嗯,我没有考虑到“本地”钩子。它看起来可能只是设置这个有问题的环境的“远程”挂钩(接收和更新变体)。其他钩子主要针对那些需要工作树的活动,而且它们似乎是用一个理想的配置运行的,它需要一个工作树(这很有意义,因为这些钩子通常是从需要工作树的命令调用的) 。 – 2011-04-09 09:36:52

13

总之,使用挂钩,一行代码:

git --git-dir=. --work-tree=$PWD/.. reset --hard 

为了更加精确,编辑服务器上的文件.git/hooks/post-receive

#!/bin/sh 
git --git-dir=. --work-tree=$PWD/.. reset --hard 

将其设置为可执行:

chmod +x .git/hooks/post-receive 

当从客户端推送到这个回购时,应该这样说:

HEAD is now at abcd123 comment 
+1

在问题被提出之前,比改变环境更好,并且可以在git中使用。 – digenishjkl 2014-07-29 11:45:30

+1

应该是被接受的答案。 – sjy 2014-09-15 07:40:11