Git:安全推送非裸存储库

时间:2011-05-20 17:30:38

标签: git git-post-receive

我可以使用git专家的一些指导,将安全操作推送到非裸存储库。基本上我有一个关于如何做到这一点的计划,并且可以使用关于该计划是否合理的一些建议:)

通常,当您在git中推送到非裸存储库时,其工作副本和索引不会更新。正如我所发现的,如果您忘记以后手动更新它们,这可能会导致严重的问题!

在我们的小组中,我们有一些“中心”存储库,人们克隆并推回,但许多人也希望能够克隆他们的克隆并在真正的分布式中根据需要推/拉时尚。为了使这个安全,我想确保通过“clone”或“init”创建的每个存储库都有一个自动安装的post-receive挂钩,它将在推送操作后更新工作目录和索引,以便与新的HEAD。

我发现我可以通过在hooks子目录中使用post-receive hook创建一个模板目录来实现这一点,然后让我的组中的每个人都执行:

git config --global init.templatedir /path/to/template/dir

目前我的post-receive挂钩看起来像这样:

export GIT_WORK_TREE=..
git checkout -f HEAD

这个SEEMS按预期工作,但我对checkout命令有一些不确定性。为了将工作目录和索引与HEAD中的状态同步,“git checkout -f HEAD”和“git reset --hard HEAD”等效吗?

我问,因为虽然我知道“git reset --hard HEAD”会做我想要的,但是在我的测试中使用它在后接收钩子中大大减慢了推送操作(它似乎做了一个新的检查所有文件,无论文件在工作目录中是脏还是干净)。 “git checkout -f HEAD”SEEMS更快地做同样的事情(给我一个干净的工作目录和索引与HEAD同步),但我有点紧张,因为checkout命令倾向于在飞行中做与未提交的工作目录更改合并。这个命令真的会给我一个工作目录吗?在所有情况下都与HEAD中的状态完全匹配的索引(包括,例如,文件删除,重命名等)?

提前感谢任何建议!

2 个答案:

答案 0 :(得分:5)

我可能误解了这个问题。你真的想要设置它,这样任何人都可以推送到开发人员的工作目录,而他正在进行未提交的更改吗?无论如何,这都无法使其变得“安全”。

大多数人所做的是拥有他们正常的工作目录,这是私有的,并将其完全克隆到同一磁盘上的公共仓库中,然后共享该目录。这使用硬链接,所以你几乎不使用任何额外的空间。您将更改推送到同事的公开裸仓库中,当他准备接收更改时,他会进入工作目录。或者,您将更改推送到您的公共裸仓库中,当他准备就绪时,您的同事会从那里撤离。推动非裸存储库的原因很难设置。

答案 1 :(得分:4)

我建议使用post-update hook条目“Git FAQ”所指示的Why won't I see changes in the remote repo after "git push"?

在执行硬重置之前,它会隐藏已暂存和未暂存的更改(跟踪文件)。它比普通的硬重置更安全,但正如FAQ条目所述,它仍然没有涵盖可能出现的所有情况(例如,具有预先存在的冲突的索引无法被隐藏;它不会自动合并更改未经修改的文件,如git checkout等等。)。


然而,...... 如果可能的话,...
你可能应该首先避免推送到任何签出的分支。

只要您没有推送到已检出的分支,就可以推送到非裸存储库(毕竟,所涉及的配置变量是receive.denyCurrentBranch,而不是“receive.denyNonBare”。 / p>

上面链接的FAQ条目的最后一段链接到(在下面的评论中,Mark Longair提到)another entry,其中概述了推送到非裸存储库的方法。该条目的动机是两个非裸存储库之间的非对称网络连接,但该技术可以应用于您需要/想要推送到非裸存储库的任何情况。

后一个FAQ条目提供了推送到远程跟踪分支(在refs/remotes/下)的示例。只有refs/heads/下的引用可以在不分离HEAD(不使用git symoblic-ref)的情况下签出,因此推送到refs/heads/以外的任何内容应该是安全的,以避免“推送到签出的分支” ”

由于您在集中式环境中工作,因此您可以为此类推送的目标制定策略。例如:

  

当您需要将提交推送到其他人的非裸存储库时,请将它们推送到refs/remotes/from/<your-username>/<branch>。为了避免与正常的远程跟踪分支冲突,任何人都不应该定义名为from的远程。像这样推送的分支将显示在git branch -a(或-r)中,因此可以在没有refs/remotes/前缀的情况下引用。但是,from伪远程不会显示在git remote中,因为没有remote.from.url配置变量。

     

示例:

alice$ remote add betty bettys-machine:path/to/some/non-bare/repository
alice$ git push betty master:refs/remotes/from/alice/bug/123/master

betty$ git log --reverse -p origin/master..from/alice/bug/123/master