高度耦合的git子模块

时间:2010-09-14 21:07:19

标签: git git-submodules

我有一个项目需要拆分为两个存储库:一组通用模型,以及基于这些模型的模拟,以及其他代码。最终可能存在使用相同模型集的多个模拟,因此将它们放在单独的存储库中是一个明确的要求。显而易见的解决方案是将通用模型作为模拟的子模块。

不幸的是,这两个存储库将非常高度耦合。人们会经常在他们的常见模型中添加一些东西,然后立即在模拟中使用它。我想这会在模拟回购的整合过程中引起很多麻烦。为了在模拟中合并来自许多开发人员的更改,集成商将不得不在通用模型子模块中进行并行合并。另一方面,它还使得使用子模块变得至关重要 - 模拟真正需要来了解应该使用哪个版本的常见模型。

该项目由相当多的人开展。大多数开发人员只对git有一个非常粗略的了解:他们添加文件,提交和从源头拉取很多东西,并希望有一个开发和稳定的分支。积分器自然而然地学到了很多东西,但任何涉及子模块的东西对他来说都是新的。额外的奖励:我即将休假一个月,所以我将无法扑灭任何火灾。结果是有很多动机使工作流真的难以搞砸,并最大限度地减少与以前工作流程的差异。

所以,我的问题是:我是否会后悔建议我们使用子模块? (有更好的想法吗?)我可以期待人们犯下什么样的错误,所以我可以提前警告他们?是否有任何好的工作流程策略要记住?

编辑:我刚遇到git slave,在这种情况下也可能值得一看。还不能对其网站上的能力/限制进行良好的评估。

2 个答案:

答案 0 :(得分:14)

对于其他任何人发生的一些注意事项!

新手将要做的最大的错误是在完成子模块更新后,在子模块中提交了分离的HEAD。我将尝试通过钩子的强烈警告来解决这个问题。

下一个最大的可能是在执行结账后无法进行子模块更新,这需要一个。同样,钩子可以检查并发出警告。

至于开发过程,这个设置使得在子模块中拥有一个好的测试基础架构变得更加重要,因此如果可能的话,你可以在不必在父模块中工作的情况下工作,并完全避免这个问题。 / p>

我会尝试从我最终使用的钩子中发布示例代码,并在一个月后跟进(希望不会太多)真正的恐怖故事。

编辑:

以下是挂钩的第一稿。请记住,这是一项繁忙的工作,对我很轻松!

在父级回购中:

对于合并后和结账后,我们会警告用户子模块是否不同步。 (合并后包含特别用于快速合并,从原点拉出)还要注意他们想要检查一个分支,虽然子模块的post-checkout挂钩也会在运行子模块更新时执行此操作。提醒者越多越好。

#!/bin/bash
if git submodule status | grep '^+' > /dev/null; then
    echo "WARNING: common model submodule now out of sync. You probably want to run" 1>&2
    echo "         git submodule update, then make sure to check out an appropriate branch" 1>&2
    echo "         in the submodule." 1>&2
fi

对于post-commit,如果存在子模块更改,我们会警告用户他们可能忘记将它们包含在提交中。在这种高度耦合的情况下,这是一个非常好的猜测。用户不太可能单独修改模拟和常见模型

#!/bin/bash
if git submodule status | grep '^+' > /dev/null; then
    echo "WARNING: common model submodule has changes. If the commit you just made depends" 1>&2
    echo "         on those changes, you must run git add on the submodule, and then run" 1>&2
    echo "         git commit --amend to fix your commit." 1>&2
fi

在子模块中,一个post-checkout钩子强烈警告分离的HEAD:

#!/bin/bash

get_ppid() {
    ps --no-headers -o ppid $1
}

# Check to see if this checkout is part of a submodule update
# git submodule calls git checkout, which calls this script, so we need to
# check the grandparent process.
if ps --no-headers -o command $(get_ppid $(get_ppid $$)) | grep 'submodule update' &> /dev/null; then
    if ! git symbolic-ref HEAD &> /dev/null; then
        echo "WARNING: common model submodule entering detached HEAD state. If you don't know" 1>&2
        echo "         what this means, and you just ran 'git submodule update', you probably" 1>&2
        echo "         want to check out an appropriate branch in the submodule repository." 1>&2
        echo
        # escape the asterisk from SO's syntax highlighting (it sees C comments)
        branches=($(git for-each-ref --format='%(objectname) %(refname:short)' refs/heads/\* | grep ^$(git rev-parse HEAD) | cut -d\  -f2))
        case ${#branches} in
            0 )
                ;;
            1 ) 
                echo "Branch '${branches[0]}' is at HEAD"
                ;;
            * )
                echo "The following branches are at HEAD: ${branches[@]}"
                ;;
        esac
    fi
    echo
fi

我还添加了一个预提交钩子来简单地中止使用分离的HEAD进行的提交(除非它是一个rebase)。我非常害怕得到经典的“我所有的承诺都消失了”恐慌的抱怨。如果您知道自己在做什么,可以随时使用--no-verify绕过它。

答案 1 :(得分:7)

子模块是确保参考所涉及的不同组件的精确修订的不错选择 正如我在“true nature of submodules”中详述的那样,您仍然可以更新任何子模块,前提是您先提交它们(然后转到父存储库并提交)

但是,对于紧密耦合的模块,我会尽量避免:

  

“我想这会在模拟回购的整合过程中引起很多麻烦。”

我没有看到中央整合过程有效运作:它应该只记录新的快速演变 为了实现这一点,任何想要推送任何东西的用户都需要先拉动并在已经推送的任何新变化的基础上改变他的变化。
开发人员更容易解决任何冲突和/或询问他/她的同事他们/她在rebase期间必须处理的一些修改的起源。

由于以下原因,这种(拉动,变形,推动)并非总是可行:

  • “高级”(不太基础)涉及的Git操作(以及与当前工作流程不完全相同的工作流程)
  • 涉及的工作(考虑到其他贡献者的演变)
  • 环境设置(最好设置一个额外的环境来制作那个rebase,这又是“不那么基本”

但那仍然是我会尝试的方向。

(...但也许就在一个月假期之前;)
那么,谁度过所有月的假期?!之前从未听说过这个概念