Git:确保推送到非裸存储库的安全
我可以使用 git 专家的一些指导来确保非裸存储库的推送操作安全。基本上我有一个关于如何做到这一点的计划,并且可以使用一些关于该计划是否合理的建议:)
通常当您推送到 git 中的非裸存储库时,其工作副本和索引不会更新。正如我发现的,如果您忘记稍后手动更新它们,这可能会导致严重的问题!
在我们的团队中,我们有一些“中央”存储库,人们可以克隆并推送回这些存储库,但许多人也希望能够克隆他们的克隆,并根据需要以真正的分布式方式在它们之间推送/拉取。为了确保安全,我想确保通过“clone”或“init”创建的每个存储库都自动安装了一个接收后挂钩,该挂钩将在推送操作后更新工作目录和索引,以便与新头。
我发现我可以通过在 hooks 子目录中使用我的 post-receive hook 创建一个模板目录来实现这一点,然后让我组中的每个人执行以下操作:
git config --global init.templatedir /path/to/template/dir
目前我的 post-receive hook 看起来像这样:
export GIT_WORK_TREE=..
git checkout -f HEAD
这似乎可以作为想要的,但我对结帐命令有一些不确定性。为了将工作目录和索引与 HEAD 中的状态同步,“git checkout -f HEAD”和“git reset --hard HEAD”是否等效?
我问这个问题是因为虽然我知道“git reset --hard HEAD”会做我想要的事情,但在接收后挂钩中使用它会在我的测试中大大减慢推送操作(它似乎对所有文件进行了重新检查,无论工作目录中的文件是脏的还是干净的)。 “git checkout -f HEAD”似乎可以更快地完成同样的事情(给我一个干净的工作目录和与 HEAD 同步的索引),但考虑到 checkout 命令倾向于即时执行,我有点紧张与未提交的工作目录更改合并。这个命令真的会给我一个工作目录吗?在所有情况下(包括文件删除、重命名等)与 HEAD 中的状态完全匹配的索引?
预先感谢您的任何建议!
I could use some guidance from the git experts out there regarding making push operations to non-bare repositories safe. Basically I have a plan about how to do this, and could use some advice about whether the plan is sane or not :)
Normally when you push to a non-bare repository in git, its working copy and index are not updated. As I've discovered, this can cause serious problems if you forget to later update them manually!
In our group, we have a few "central" repositories that people clone off of and push back to, but many people also want to be able to make clones of their clones and push/pull between them as needed in true distributed fashion. In order to make this safe, I want to ensure that every repository created via either "clone" or "init" has a post-receive hook automatically installed that will update the working directory and index after a push operation to be in sync with the new HEAD.
I've found that I can make this happen by creating a template directory with my post-receive hook in a hooks subdirectory, then having everyone in my group do a:
git config --global init.templatedir /path/to/template/dir
Currently my post-receive hook looks like this:
export GIT_WORK_TREE=..
git checkout -f HEAD
This SEEMS to work as desired, but I have some uncertainty about the checkout command. For the purposes of syncing the working directory and index with the state in HEAD, are "git checkout -f HEAD" and "git reset --hard HEAD" equivalent?
I ask because although I know that "git reset --hard HEAD" will do what I want, using it in a post-receive hook slows down push operations considerably in my testing (it seems to do a fresh check out of all files, regardless of whether a file is dirty or clean in the working dir). "git checkout -f HEAD" SEEMS to do the same thing much faster (get me a clean working directory and index in sync with HEAD), but I am a little nervous given the propensity of the checkout command to do on-the-fly merges with uncommitted working directory changes. Will this command really give me a working dir & index that exactly match the state in HEAD in all cases (including, eg., file deletions, renames, etc.)?
Thanks in advance for any advice!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我可能误解了这个问题。您是否真的想将其设置为当开发人员正在进行未提交的更改时任何人都可以推送到他的工作目录?任何词语都不能将其称为“安全”。
大多数人所做的就是拥有自己的正常工作目录(这是私有的),并将其裸克隆到同一磁盘上的公共存储库中,然后共享该目录。它使用硬链接,因此您几乎不需要使用任何额外的空间。您将更改推送到同事的公共裸存储库,当他准备好接收更改时,他会拉入他的工作目录。或者,您将更改推送到您的公共裸存储库中,然后您的同事准备好后从那里提取。推动非裸存储库难以设置是有原因的。
I might have misunderstood the problem. Do you really want to set it up so anyone can push to a developer's working directory while he has uncommitted changes he's working on? That can't be made "safe" by any stretch of the word.
What most people do is have their normal working directory, which is private, and make a bare clone of that into a public repo on the same disk, and share that one. That uses hard links so you barely use any additional space. You push your changes to your colleague's public bare repo, and he does a pull into his working directory when he's ready to receive the changes. Alternately, you push your changes into your public bare repo, and your colleague pulls from there when he's ready. There's a reason pushing to non-bare repositories is difficult to set up.
我建议使用
post-update
钩子,由 < a href="https://git.wiki.kernel.org/index.php/GitFaq" rel="nofollow">Git FAQ 条目 ”为什么在“git”之后我看不到远程存储库中的更改推“?”。在进行硬重置之前,它将隐藏暂存和未暂存的更改(对跟踪文件)。它比普通的硬重置更安全,但正如常见问题解答条目所述,它仍然没有涵盖可能出现的所有情况(例如,无法隐藏具有预先存在冲突的索引;它不会自动合并更改到未修改的文件,如 git checkout 等)。
然而,……
如果可能的话,……
您可能应该首先避免推送到任何已签出的分支。
只要您不推送到签出分支,推送到非裸存储库就可以(毕竟,涉及的配置变量是
receive.denyCurrentBranch
,而不是“receive.denyNonBare< /代码>”)。
上述链接的常见问题解答条目的最后一段链接到(正如 Mark Longair 在下面的评论中提到的那样)另一个条目,概述了推送到非裸存储库的方法。条目的动机是两个非裸存储库之间的非对称网络连接,但该技术可以应用于您需要/想要推送到非裸存储库的任何情况。
后一个常见问题解答条目提供了推送到远程跟踪分支(在
refs/remotes/
下)的示例。仅可以在不分离 HEAD 的情况下检查 refs/heads/ 下的引用(不使用 git symoblic-ref ),因此推送到 refs/ 之外的任何内容Heads/ 应该是安全的,可以避免“推送到已签出的分支”。由于您在集中式环境中工作,因此您也许能够为此类推送的目的地制定策略。例如:
I suggest using the
post-update
hook indicated by the Git FAQ entry ”Why won't I see changes in the remote repo after "git push"?”.It will stash away staged and unstaged changes (to tracked files) before doing the hard reset. It is safer than a plain hard reset, but as the FAQ entry says, it still does not cover all the situations that might come up (e.g. an index with a pre-existing conflict can not be stashed; it does not auto-merge changes to unmodified files like
git checkout
does, etc.).However, …
if at all possible, …
you should probably just avoid pushing to any checked out branch in the first place.
Pushing to a non-bare repository is okay as long as you are not pushing to the checked out branch (after all, the involved configuration variable is
receive.denyCurrentBranch
, not “receive.denyNonBare
”).The last paragraph of the above-linked FAQ entry links to (as, in a comment below, Mark Longair mentions) another entry that outlines an approach for pushing to a non-bare repository. The motivation for the entry is an asymmetric network connection between two non-bare repositories, but the technique can be applied to any situation where you need/want to push to a non-bare repository.
This latter FAQ entry gives an example of pushing to a remote-tracking branch (under
refs/remotes/
). Only the refs underrefs/heads/
can be checked out without detaching HEAD (without the use ofgit symoblic-ref
), so pushing to anything outsiderefs/heads/
should be safe for avoiding “pushing to the checked out branch”.Since you are working in a centralized environment, you might be able to make a policy for the destination of such pushes. For example: