我可以想到两种方法来做到这一点,两种方法都使用一些管道,其中现有的瓷器是在考虑其他因素的情况下建造的。
The first way's easiest but I only recently learned it was even possible1 and suspect some experienced git users will regard it as a monstrosity. The thing is, here it's a very useful monstrosity, and in past debates between the two characterizations "useful" has sometimes proved more ... useful. So:
第一种方法:
You can directly track content that is also tracked in nested repositories. Once git is tracking any content within a directory it will completely2 ignore any repository you subsequently create there.
从你的问题看来,你已经得到了整齐可分割的部分,因此,从顶部开始:
使用存根(或当前)初始内容创建一个完全普通的存储库
# from the top:
# create and commit the empty skeleton
git init book
cd !$
mkdir -p sect{1,2,3}
touch {.,!$}/.gitignore
# copy in any initial content here
git add .
git ls-files -s # to see exactly what you've done so far
git commit -m 'initial skeleton'
创建子存储库以独立跟踪各个部分
# now git is directly tracking content in each section, and commands in the
# parent will _ignore_ the existence of any nested repositories you subsequently
# create, but not there worktrees (because of the existing tracked content). viz.:
( cd sect1
git init
git add .
git commit -m 'initial skeleton'
git branch publishing-history
)
^1^2
^2^3
独立、自由地完成每个部分
现在,您可以在多个存储库中跟踪这些部分,并且可以完全独立地处理每个部分:
cd sect1
# work work commit commit lalala
# ... do whatever in the other repos
发布所有部分的合并当前内容
现在是时候发布每个子目录中的当前内容了。将他们的内容全部清理以供发布,并且从其中任何一个中,只需一次,即可
cd ..
git add -A .
git commit
published=`git rev-parse HEAD`
你完成了。如何记录行为:
将各部分的动作记录下来,以供参考
for section in sect*; do
cd $section
git update-ref refs/heads/publishing-history $(
# log where the checked-out commit was published
git commit-tree \
-p publishing-history \
-p `git rev-parse HEAD` \
-m "## published in main repository commit $published ##" \
HEAD^{tree} # just `HEAD:` will work too
)
cd ..
done
您选择发布的提交或发布顺序没有任何限制。这就是为什么 Linus 称 git 为“愚蠢的内容跟踪器”:核心没有抽象。分支正确记录了这些提交的顺序、内容和祖先。
便捷链接提交树 https://www.kernel.org/pub/software/scm/git/docs/git-commit-tree.html and 更新参考 https://www.kernel.org/pub/software/scm/git/docs/git-update-ref.html.
建立重写的独立出版历史
git symbolic-ref HEAD refs/heads/newmaster
并如上所述发布您喜欢的任何签出提交序列。这publish-history
分支将如实地准确记录您发布的内容和时间。
你可以看到这是怎么回事,对吧?您可以从提交的内容构建任意历史记录commit-tree
and update-ref
。如果父存储库中的提交顺序不是您想要的,请通过直接提交正确的树顺序将其替换为您想要的完全不同的历史记录。要在父存储库中记录单独的注释,也可以在其上使用发布历史记录构造。
请注意:如果您开始进行大量的历史重写,并且构建新序列所涉及的检查开始显得很繁重,那么 git 可以帮助您。从gitcore-教程 https://www.kernel.org/pub/software/scm/git/docs/gitcore-tutorial.html当你准备好时。
第二种方法
这种方式通过从完全独立的存储库获取和操作树而不是使用上面的覆盖存储库方法来替换“发布组合当前内容”步骤。然后发布步骤是
cd ../main
git read-tree --empty
for repo in sect{1,2,3}; do
( cd ../$repo
tag -f fetchme HEAD^{tree}
)
git fetch ../sect1 fetchme
git read-tree -m --prefix=sect1 FETCH_HEAD
done
git commit
但这有一个缺点,即您不仅必须显式同步重复的工作树,还必须显式同步工作树的更多副本,以启用任何整个项目测试,而不必发布(如上所述)您要测试的每个版本。
也许这只是一种精神状态的问题,但这种方式看起来很笨拙,我认为不值得追求。
散记:
git clean -dfx
不会清除嵌套存储库的工作树,git 显然只忽略嵌套的.git
当它有用时。唔。这可能会被以有用的方式滥用。
-
如果您想保护您的嵌入式存储库免受随机影响rm -rf sect3
你可以使用这个方法git submodule
uses,
mv .git /someplace/safer
echo gitdir: /someplace/safer >.git
以及核弹之后的重建mkdir -p
and echo
- 有人可能会找到一种更优雅的方法来做到这一点,如果是这样,我希望至少能很快出现它的草图;我在上面没有看到任何内容,但我确实倾向于过度设计事物,然后将其全部煮沸。
1 See here for the question that taught me this was possible https://stackoverflow.com/q/23668981/1290731
2 It turns out that git clean
does recognize the nested repositories, and doesn't clean them. So git clean -dfx
is still safe. More useful behavior :-)