2010-08-05 112 views
5

作为之前已经提出的detach-subdirectory问题的一个子集,考虑到即使关于拆分和合并git存储库的过程提出了很多问题,找到一个触及子模块出现时分裂的主题。将子模块的子目录拆分到单独的git存储库中

所以在以下情形:

.git/ 
.gitmodules 
folder/ 
    data/ 
    content/ 
     other_data/ 
     submoduleA/ 
     submoduleB/ 

我想拿到两个库结构如下:

.git/ 
data/ 

.git/ 
.gitmodules 
content/ 
    other_data/ 
    submoduleA/ 
    submoduleB/ 

第一种情况是不是问题并且可以用detach-subdirectory中描述的方法容易地解决。

第二不是很多。子模块的存在以及.gitmodules包含folder/content/submoduleAfolder/content/submoduleB的完整路径的事实会导致部分历史记录不一致,因为.gitmodules引用了不存在的目录结构(一旦使用了filter-branch)。

所以我想知道是否有办法做到这一点,而不会造成不一致的历史。

回答

1

我怀疑(未测试)第二个git filter-branch将有机会修改.gitmodules内容的每个提交的新回购。

但实际上是git submodule split command was in discussion early 2009

拟议用法:

git submodule split [--url submodule_repo_url] submodule_dir \ 
    [alternate_dir...] 

更换submodule_dir与新创建的子模块,保持的submodule_dir所有的历史。
此命令还会重写当前存储库历史记录中的每个提交,以包含正确的修订号sumodule_dir和相应的.gitmodules条目。

但是,我没有看到它在latest what's cooking
建议的修补程序中的脚本可以让您了解更新.gitmodules文件所需的树重写类型。

+0

使用第二git的过滤分支命令,我能够用SED命令重写.gitmodules,但实际子模块文件夹仍然保持原样(都使用索引过滤器和树型过滤器)。只有子目录过滤器能够改变它们,但是.gitmodules被删除。 git submodule split命令似乎完全按照我的意思去做,但是读取线程时我得到了它有一些问题的印象,所以我不习惯使用它。 – Unode 2010-08-05 16:37:37

+0

@Unode:我明白了。我不认为这个特别的补丁现在正在积极开发中。 – VonC 2010-08-05 16:58:17

5

我有完全相同的问题,因为Unode和管理具有以下步骤来解决这个问题:

git clone [email protected]:kdeldycke/kev-code.git 
cd kev-code 
git filter-branch --tree-filter "test -f ./.gitmodules && mv ./.gitmodules ./cool-cavemen/gitmodules || echo 'No .gitmodules file found'" -- --all 
git filter-branch --force --prune-empty --subdirectory-filter cool-cavemen --tag-name-filter cat -- --all init..HEAD 
git filter-branch --force --tree-filter "test -f ./gitmodules && mv ./gitmodules ./.gitmodules || echo 'No gitmodules file found'" -- --all 
git filter-branch --force --tree-filter "test -f ./.gitmodules && sed -i 's/cool-cavemen\///g' ./.gitmodules || echo 'No .gitmodules file found'" -- --all 
git remote rm origin 
rm -rf .git/refs/original/ 
git reflog expire --all 
git gc --aggressive --prune 
git remote add origin [email protected]:kdeldycke/cool-cavemen.git 
git push -u origin master --force --tags 

正如你看到的,关键是要暂时命名.gitmodules文件,并使用sed重写其内容。你可以得到所有的细节和context of this procedure on my blog

+0

您可能希望在所有filter-branch命令中包含'--tag-name-filter cat'选项以在过滤后保留标签。 – kolyuchiy 2012-05-01 15:52:21

+0

感谢您记录这一点。我必须调整两件事才能使其发挥作用。首先,我认为你假设初始提交标记为'init'作为'init..HEAD'范围。其次,我必须在sed命令中加上'-e',即:'sed -i -e's/cool-cavemen \ /// g'./。gitmodules' – Von 2013-05-08 01:49:53

0

详细解释凯文的答案:假设cool/cavemen以外的任何子模块都不存在 - 文件夹被分离(否则更精细的编辑。gitmodules将需要去除这些多余的部分),这可以在一个步骤中使用index-filter实现更快:

$ git filter-branch --subdirectory-filter cool/cavemen --index-filter $' 
hash=$(git rev-parse --verify $GIT_COMMIT:.gitmodules 2>/dev/null) && 
git update-index --add --cacheinfo 100644 $(git cat-file -p $hash | 
sed \'s/cool\\/cavemen\\///g\' | git hash-object -w --stdin) .gitmodules || 
true' --tag-name-filter cat --prune-empty -- --all 

另外一个好处是,如果cool/cavemen没有在每一个版本或者分支只存在那些包含cool/cavemen的版本或分支将被查看。

如果这是你可能要运行以下命令以删除引用不变的情况下:

$ git for-each-ref --format='%(refname)' | 
grep -vF "$(git for-each-ref --format='%(refname)' refs/original | 
sed 's/refs\/original\///g')" | xargs -n 1 git update-ref -d 
相关问题