高度耦合的git子模块

Cas*_*bel 16 git git-submodules

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

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

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

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

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

Cas*_*bel 14

对于其他任何人发生的一些注释!

新手将要做的最大的错误是在完成子模块更新后,在子模块中使用分离的HEAD.我将试图通过钩子的强烈警告来对抗这个问题.

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

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

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

编辑:

这是钩子的第一个草稿.请记住,这是一项繁忙的工作,对我来说很容易!

在父回购中:

对于合并后和结账后,我们警告用户子模块是否不同步.(后合并特别包括快进合并,从原点拉出)还要注意他们想要检查一个分支,虽然子模块的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
Run Code Online (Sandbox Code Playgroud)

对于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
Run Code Online (Sandbox Code Playgroud)

在子模块中,一个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
Run Code Online (Sandbox Code Playgroud)

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

  • @Jefromi过去两年你可以分享的许多经验教训?我正在考虑采用一个非常相似的结构,但我害怕那些害怕git的开发人员,以及他们将如何处理这样的设置. (2认同)

Von*_*onC 7

子模块是确保参考所涉及的不同组件的精确修订的良好选择.
正如我在" 子模块的真实性质 "中详述的那样,如果您先提交它们,您仍然可以更新任何子模块(然后转到父存储库并提交)

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

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

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

由于以下原因,这种(拉动,反转,推动)并不总是可行的:

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

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

(...但也许不只是在一个月的假期之前 ;)
然后,谁又需要一整个月的假期?!从来没有听说过这个概念)