编写拒绝无效子模块提交的git更新钩子的最佳方法是什么? [英] What is the best way to write a git update hook that rejects invalid submodule commits?

查看:166
本文介绍了编写拒绝无效子模块提交的git更新钩子的最佳方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图为git编写 update 钩子,如果子模块正在更新为子模块上游存储库中不存在的提交ID,则该钩子会弹跳。换言之,我想强制用户在对子模块存储库进行更改之前将更改推送到子模块存储库。



一个提示:




  • 我只想测试其裸露的上游存储库与父存储库位于同一服务器上的子模块。否则,我们将开始做一些疯狂的事情,比如在git钩子中调用'git clone'或'git fetch',这不会很有趣。


我一直在玩一个想法,但感觉好像有一个更好的方法来做到这一点。以下是我计划在更新挂钩中执行的操作:


  1. 检查传入挂钩的refname,看看我们是否正在更新参/头/ 。如果没有,请尽早退出。

  2. 使用 git rev-list 获取推送的修订列表。

  3. 对于每个修订:


    1. 调用 git show< revision_id> 并使用一个正则表达式,以查看子模块是否已更新(通过搜索`+ Subproject commit [0-9a-f] +)。
    2. 如果此提交确实更改了子模块,请获取< ( git show< revision_id>:.gitmodules )。code> .gitmodules
    3. 使用3.1和3.2的结果获取子模块URL及其更新的提交ID的列表。

    4. 检查3.3中创建的列表,对照映射的外部文件子模块URL到文件系统上的本地裸git存储库。
    5. cd 到3.4中找到的路径并执行 git rev-parse --quiet --verify< updated_submodule_commit_id> 查看该提交是否存在于该存储库中。如果不是,请退出时显示非零状态。


:只要输出到 git rev-parse --quiet --verify< revision_id>:。gitmodules doesn,我相信3.2的结果可以跨修订缓存我从这个部分出来简化了解决方案。)



所以是的,这看起来很复杂,我不禁但不知道是否有一些内部的git命令可能会让我的生活变得更轻松。或者也许有不同的方式来思考这个问题?

解决方案

编辑,稍后:从Git 1.7.7开始, git-push 现在有一个 - recurse-submodules = check 选项,拒绝推送父项目子模块提交没有被推送到他们的遥控器。它似乎没有添加相应的 push.recurseSubmodules 配置参数。这当然不能完全解决这个问题 - 一个无知的用户仍然可以在没有支票的情况下推 - 但它是相关的!



我认为最好的方法,而不是检查每个单独的提交都是查看所有推送提交的差异: git diff< old> <新> 。尽管如此,你不想看看整个差异。它可能是巨大的。不幸的是,git-submodule porcelain命令在bare repos中不起作用,但是您仍然应该能够快速检查 .gitmodules 以获取路径列表(也可能是URL )。对于每一个,你都可以 git diff< old> <新> - path ,如果有差异,则抓住新的子模块提交。 (如果你担心000000旧提交可能性,我相信你可以在新的一个上使用 git show 。)



一旦你得到了所有的照顾,你已经减少了问题,检查给定的远程存储库中是否存在给定的提交。不幸的是,因为它看起来像你已经注意到,这并不简单,至少据我所知。保持当地最新的克隆可能是你最好的选择,听起来你在那里很好。

缓存将在这里相关,因为更新挂钩每次参考一次。是的,你可以在预先接收的钩子中做到这一点,它可以获得标准输入的所有参考,但我不明白为什么你应该花费更多的工作。这不会是一个昂贵的操作,并且通过更新挂钩,您可以单独接受或拒绝正在推送的各个分支,而不是防止更新它们的全部,因为只有一个是不好的。



如果您想节省一些麻烦,我可能会避免解析gitmodules文件,并将列表硬编码到钩子中。我怀疑你的子模块列表经常改变,所以维护它可能比编写自动化的东西更便宜。


I am attempting to write an update hook for git that bounces if a submodule is being updated to a commit ID that does not exist in the submodule's upstream repository. To say it another way, I want to force users to push changes to the submodule repositories before they push changes to the submodule pointers.

One caveat:

  • I only want to test submodules whose bare, upstream repositories exist on the same server as the parent repository. Otherwise we start having to do crazy things like call 'git clone' or 'git fetch' from within a git hook, which would not be fun.

I have been playing around with an idea but it feels like there must be a better way to do this. Here is what I was planning on doing in the update hook:

  1. Check the refname passed into the hook to see if we are updating something under refs/heads/. If not, exit early.
  2. Use git rev-list to get a list of revisions being pushed.
  3. For each revision:

    1. Call git show <revision_id> and use a regular expression that looks to see if a submodule was updated (by searching for `+Subproject commit [0-9a-f]+).
    2. If this commit did change a submodule, get the contents of the .gitmodules files as seen by that particular commit (git show <revision_id>:.gitmodules).
    3. Use the results of 3.1 and 3.2 to get a list of submodule URLs and their updated commit IDs.
    4. Check this list created in 3.3 against an external file that maps submodule URLs to local bare git repositories on the filesystem.
    5. cd to the paths found in 3.4 and execute git rev-parse --quiet --verify <updated_submodule_commit_id> to see if that commit exists in that repository. If it does not, exit with a non-zero status.

(Note: I believe the results of 3.2 can potentially be cached across revisions as long as the output to git rev-parse --quiet --verify <revision_id>:.gitmodules doesn't change from one revision to the next. I left this part out to simplify the solution.)

So yeah, this seems pretty complex, and I can't help but wonder if there are some internal git commands that might make my life a lot easier. Or maybe there is a different way to think about the problem?

解决方案

Edit, much later: As of Git 1.7.7, git-push now has a --recurse-submodules=check option, which refuses to push the parent project if any submodule commits haven't been pushed to their remotes. It doesn't appear that a corresponding push.recurseSubmodules config parameter has been added yet. This of course doesn't entirely address the problem - a clueless user could still push without the check - but it's quite relevant!

I think the best approach, rather than examining each individual commit, is to look at the diff across all of the pushed commits: git diff <old> <new>. You don't want to look at the whole diff though, really; it could be enormous. Unfortunately, the git-submodule porcelain command doesn't work in bare repos, but you should still be able to quickly examine .gitmodules to get a list of paths (and maybe URLs). For each one, you can git diff <old> <new> -- path, and if there is a diff, grab the new submodule commit. (And if you're worried about a 000000 old commit possibility, you can just use git show on the new one, I believe.)

Once you get all that taken care of, you've reduced the problem to checking whether given commits exist in given remote repositories. Unfortunately, as it looks like you've noticed, that's not straightforward, at least as far as I know. Keeping local, up-to-date clones is probably your best bet, and it sounds like you're good there.

By the way, I don't think the caching is going to be relevant here, since the update hook is once per ref. Yes, you could do this in a pre-receive hook, which gets all the refs on stdin, but I don't see why you should bother doing more work. It's not going to be an expensive operation, and with an update hook, you can individually accept or reject the various branches being pushed, instead of preventing all of them from being updated because only one was bad.

If you want to save some trouble, I'd probably just avoid parsing the gitmodules file, and hardcode a list into the hook. I doubt your list of submodules changes very often, so it's probably cheaper to maintain that than to write something automated.

这篇关于编写拒绝无效子模块提交的git更新钩子的最佳方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆