我们公司有庞大的代码库(超过 100000 个文件),因此我们将其保存在多个 git 存储库中。因此,我们有一个存储库森林和一个仅包含子模块引用的超级存储库。
这个想法是让超级存储库作为一种方便的粘合剂,每当开发人员更新任何子模块时它都会自动更新。
我已经尝试过接收后钩子并最终得到以下实现:(
它涉及 git 管道以便能够直接修改裸存储库)
#!/bin/bash -e
UPDATED_BRANCHES="^(master|develop)$"
UPDATED_REPOS="^submodules/.+$"
# determine what branch gets modified
read REV_OLD REV_NEW FULL_REF
BRANCH=${FULL_REF##refs/heads/}
if [[ "${BRANCH}" =~ ${UPDATED_BRANCHES} ]] && [[ "${GL_REPO}" =~ ${UPDATED_REPOS} ]];
then
# determine the name of the branch in the super repository
SUPERBRANCH=$FULL_REF
SUBMODULE_NAME=${GL_REPO##submodules/}
# clean the submodule repo related environment
unset $(git rev-parse --local-env-vars)
# move to the super repository
cd $SUPERREPO_DIR
echo "Automaticaly updating the '$SUBMODULE_NAME' reference in the super repository..."
# modify the index - replace the submodule reference hash
git ls-tree $SUPERBRANCH | \
sed "s/\([1-8]*\) commit \([0-9a-f]*\)\t$SUBMODULE_NAME/\1 commit $REV_NEW\t$SUBMODULE_NAME/g" | \
git update-index --index-info
# write the tree containing the modified index
TREE_NEW=$(git write-tree)
COMMIT_OLD=$(git show-ref --hash $SUPERBRANCH)
# write the tree to a new commit and use the current commit as its parent
COMMIT_NEW=$(echo "Auto-update submodule: $SUBMODULE_NAME" | git commit-tree $TREE_NEW -p $COMMIT_OLD)
# update the branch reference
git update-ref $SUPERBRANCH $COMMIT_NEW
# shall we also update the HEAD?
# git symbolic-ref HEAD $SUPERBRANCH
fi
现在的问题是:
- 使用 git hook 来修改触发事件之外的其他存储库是一个好主意吗?
- 钩子实现是否正常?
(它似乎在我的计算机上运行正常,但我之前没有使用过 git 管道,所以也许我遗漏了一些东西) - 我猜想如果同时更新两个(或更多)子模块,可能会出现竞争条件。 是否有可能以某种方式防止这种情况发生(例如锁定文件)?
(我们正在使用吉托莱特作为接入层)。 - 使用超级存储库的克隆进行修改然后推送(而不是直接修改裸超级存储库)是否更好?
提前致谢。
答案1
您所做的实现有很多好处。尽管您忽略了一些可能的边缘情况,例如检查其他分支中未暂存的更改(您可能希望先添加/存储)。替代方案是使用 Jenkins 等持续集成系统来处理更新:
https://wiki.jenkins-ci.org/display/JENKINS/Meet+Jenkins
与 git hooks 系统相比,这有几个好处。它可以集中控制(我们在让 git-hooks 在我们的工程师使用的不同操作系统上工作时遇到了问题,我们增加了更多的复杂性)。还有更多可用的功能(大量用户贡献的模块)。我们的 repo 脚本现在联系 Jenkins 以获取 repo 状态并可以进行相应的更新。