git 子模块实现的效果正是您想要的:多个项目所依赖的公共代码主体,并修复了所有依赖项目之间共享的公共代码。子模块通过分离共享代码的历史来实现效果,但这只是机制——一旦你看到它,你就会明白它是自然正确的解决方案。
子模块命令本身的存在是为了跟踪一些挑剔的内务细节(通常,您可以rm -rf *
在存储库中并且不会丢失任何已提交的状态,但嵌套存储库并非如此,因此该命令通常会提升子模块 .git 目录;类似的东西),但是子模块本身只不过是一个具有自己历史的嵌套存储库。如果你 cd 进入它,git 命令甚至不知道它是任何东西的子模块,因为它们不必关心:作为子模块只是 repo 的使用方式,而不是 repo 本身固有的任何东西。
git init projectA
cd projectA
touch A # now there's a file at the projectA root,
# but the projectA repo doesn't know about it
echo 'this content is in file "A" at the projectA root'> A
git add A # content recorded, the index points to it
git commit -m'A' # now projectA repo has a permanent record of the indexed state
git init projectInner # now there's an entire repo at the projectA root,
# but the projectA repo doesn't know about it
cd projectInner
echo "Inner content" > Inner # a file at the inner repo, no repo knows about it
git add Inner # content recorded, the inner repo's index records it
git commit -mInner # the inner repo has a permanent record
cd ..
git add projectInner # now the projectA repo knows about the inner, the content is recorded ...
git commit -mInner # and now the projectA repo has a permanent record
git add
实际的 repo 意味着记录它的当前状态,就像添加文件或目录一样,但是文件的记录状态是它的全部内容,而目录的记录状态是它所有(跟踪或un-ignored) 内容,repo 的记录状态只是其 HEAD 提交的 SHA——其他所有内容都已记录在该 repo 本身中。
这里的有效负载是 git 子模块只是一个嵌套的 repo,事实证明嵌套 repo 可能是一个非常有用的东西。与 git 的其余部分一样,子模块命令实际上做的事情非常简单,所有明显的复杂性都在于在它非常有用的所有不同情况下实现最方便的东西。