我正在尝试为git编写一个update
挂钩,如果子模块正在更新为子模块的上游存储库中不存在的提交ID,则会跳转。换句话说,我想强制用户在将更改推送到子模块指针之前将更改推送到子模块存储库。
一个警告:
我一直在玩一个想法,但感觉必须有更好的方法来做到这一点。这是我计划在更新钩子中做的事情:
refs/heads/
下的内容。如果没有,请提前退出。git rev-list
获取正在推送的修订列表。git show <revision_id>
并使用正则表达式查看子模块是否已更新(通过搜索`+子项目提交[0-9a-f] +)。.gitmodules
)所见的git show <revision_id>:.gitmodules
文件的内容。cd
到3.4中找到的路径并执行git rev-parse --quiet --verify <updated_submodule_commit_id>
以查看该存储库中是否存在该提交。如果没有,则以非零状态退出。(注意:我相信3.2的结果可能会在修订版中缓存,只要git rev-parse --quiet --verify <revision_id>:.gitmodules
的输出不会从一个修订版更改为下一个修订版。我将此部分留下来简化解决方案。 )
所以是的,这看起来相当复杂,我不禁想知道是否有一些内部git命令可能会让我的生活变得更轻松。或者可能有不同的方式来思考这个问题?
答案 0 :(得分:3)
编辑,很久以后:从Git 1.7.7开始,git-push
现在有一个--recurse-submodules=check
选项,如果没有任何子模块提交被推送到他们的遥控器,它会拒绝推送父项目。似乎尚未添加相应的push.recurseSubmodules
配置参数。这当然不能完全解决这个问题 - 一个无能的用户仍然可以在没有检查的情况下推动 - 但它非常相关!
我认为最好的方法,而不是检查每个单独的提交,是在所有推送的提交中查看差异:git diff <old> <new>
。你真的不想看整个差异;它可能是巨大的。不幸的是,git-submodule porcelain命令在裸存储库中不起作用,但您仍应该能够快速检查.gitmodules
以获取路径列表(可能还有URL)。对于每一个,您可以git diff <old> <new> -- path
,如果存在差异,则获取新的子模块提交。 (如果你担心000000旧的提交可能性,我相信你可以在新版本上使用git show
。)
一旦你完成了所有这些工作,你就减少了问题,检查给定的远程存储库中是否存在给定的提交。不幸的是,看起来你已经注意到了,这不是直截了当的,至少是as far as I know。保持本地的,最新的克隆可能是你最好的选择,听起来你在那里很好。
顺便说一句,我认为缓存在这里并不重要,因为更新挂钩是每个ref一次。是的,你可以在预接收钩子中执行此操作,该钩子获取stdin上的所有引用,但我不明白为什么你应该打扰做更多的工作。它不会是一个昂贵的操作,并且使用更新挂钩,您可以单独接受或拒绝被推送的各个分支,而不是阻止所有更新它们,因为只有一个是坏的。< / p>
如果你想省一些麻烦,我可能只是避免解析gitmodules文件,并将列表硬编码到钩子中。我怀疑你的子模块列表经常变化,因此维护它可能比写自动化更便宜。
答案 1 :(得分:3)
这是我对git update hook的小尝试。在此记录,以便对其他人有用。已知的警告是'0000 ......'特殊情况未得到处理。
#!/bin/bash
REF=$1
OLD=$2
NEW=$3
# This update hook is based on the following information:
# http://stackoverflow.com/questions/3418674/bash-shell-script-function-to-verify-git-tag-or-commit-exists-and-has-been-pushe
# Get a list of submodules
git config --file <(git show $NEW:.gitmodules) --get-regexp 'submodule..*.path' | while read key path
do
url=$(git config --file <(git show $NEW:.gitmodules) --get "${key/.path/.url}")
git diff "$OLD..$NEW" -- "$path" | grep -e '^+Subproject commit ' |
cut -f3 -d ' ' | while read new_rev
do
LINES=$(GIT_DIR="$url" git branch --quiet --contains "$new_rev" 2>/dev/null | wc -l)
if [ $LINES == 0 ]
then
echo "Commit $new_rev not found in submodule $path ($url)" >&2
echo "Please push that submodule first" >&2
exit 1
fi
done || exit 1
done || exit 1
exit 0