我将git存储库的内容移动到另一个存储库中,对于所有常规提交,一切都很好。不过,我遇到了子模块的问题。
设置,我们从两个回购开始。我们会打电话给他们" docs"和"操作",我们想要移动" docs"的内容。进入" operations"的子目录,如下所示:
docs/
file1.txt
dir1/
file2.txt
other-docs/ <- This is a git submodule
operations/
bin/
do-things
docs/
important.txt
我们希望最终版本看起来像这样,&#34; docs&#34; repo最终归于&#34; docs / legacy&#34;在操作仓库:
operations/
bin/
do-things
docs/
important.txt
legacy/
file1.txt
dir1/
file2.txt
other-docs/ <- This is a git submodule
我有一个脚本,它使用git filter-branch --tree-filter
和git rebase
的组合(将新内容重新绑定到现有内容并处理.gitignore
文件之类的冲突)来执行实际迁移,但是,在运行迁移后,我最终得到:
operations/
bin/
do-things
docs/
important.txt
legacy/
file1.txt
dir1/
file2.txt
other-docs/ <- This is a git submodule
other-docs
子模块仍位于新仓库的根目录。
我明白为什么会这样。当我通过提交移动东西时,没有子模块的实际文件,因此,在&#34;这个目录中的所有内容都完全按照你保留的方式提交&#34; git filter-branch --tree-filter
的模型,没有到&#34;离开&#34;对于子模块。
所以,第一个问题:使用git filter-branch
的某些方面我可以解释这个问题吗?我想知道的一个地方是,我是否可以添加--commit-filter
并弄乱那里的东西,但我还不完全清楚提交过滤器周围的不变量是什么。
如果没有,那么我还能在其他地方做到这一点。据我所知,我将不得不修改子模块的现有提交,基本上&#34;删除&#34;旧的,不正确的位置的子模块和&#34;添加&#34;子模块在新的正确位置。我想我可以通过交互式rebase操作编写脚本,找到这些提交并修改它们。如果有更好的方法,这听起来像是很多工作。
任何想法都赞赏。
答案 0 :(得分:3)
树过滤器很容易,但它们很慢,而且你发现它们是不经意的。最好只检查您需要更改的内容,然后使用git read-tree
。
git filter-branch --index-filter='
# load up the docs-repo commit we're importing under docs/legacy/
git read-tree --prefix=docs/legacy/ $(imported-commit-for $GIT_COMMIT):
# hoist any imported submodule configs
git checkout .gitmodules
git checkout docs/legacy/.gitmodules 2>&- &&
sed -n "s,path ,path docs/legacy/,
s,^,git config -f .gitmodules ,e" &&
git rm docs/legacy/.gitmodules &&
git add .gitmodules
# any other needed content updates here
'
答案 1 :(得分:1)
我明白为什么会这样。当我通过提交来移动东西时,子模块没有实际的文件,因此,在“这个目录中的所有内容都完全按照你保留的方式提交”模型
git filter-branch --tree-filter
中,有没有来“离开”子模块。
这正是问题所在。这看起来有点讨厌。
所以,第一个问题:使用
git filter-branch
的某些方面我可以解释这个问题吗?我想知道的一个地方是,我是否可以添加--commit-filter
并弄乱那里的东西,但我并不完全清楚提交过滤器周围的不变量是什么。
你可以。它不是很漂亮。
更好的地方是--index-filter
。正如the documentation所述,过滤器按列出的顺序运行,因此索引过滤器在树过滤器之后运行。它可以对树过滤器周围代码编写的索引进行任何操作。 (树过滤器使用git update-index --add-remove
更新索引条目,根据您的过滤器留下的树,根据需要自动add
个文件。)
您也可以直接在索引过滤器中执行所有操作,速度要快得多,因为这不需要对实际文件系统操作(mkdir
,创建文件等)进行捣乱。索引过滤器一般很难编写,但是git update-index
命令可以构造一个全新的索引,或者只是更新现有索引的一部分,但是你必须首先读出一个或一些变化。旧索引(可能使用git ls-files --stage
)并操纵生成的文本。
但是这个会让你做你想做的事。