将包含子模块的子目录拆分到单独的git存储库中

时间:2010-08-05 02:33:21

标签: git git-filter-branch

作为detach-subdirectory之前已经提出的问题的一个子集,并考虑到这样一个事实,即尽管有很多关于拆分和合并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) )。

所以我想知道是否有办法在不造成历史不一致的情况下做到这一点。

3 个答案:

答案 0 :(得分:6)

我遇到与Unode完全相同的问题,并设法使用以下过程解决它:

git clone git@github.com: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 git@github.com:kdeldycke/cool-cavemen.git
git push -u origin master --force --tags

如您所见,诀窍是暂时重命名.gitmodules文件并使用sed重写其内容。您可以获取所有详细信息和context of this procedure on my blog

答案 1 :(得分: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文件所需的树重写类型。

答案 2 :(得分:0)

详细说明Kevin的答案:假设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