我如何git"子树拆分"但保持完整的文件夹层次结构?

Dav*_*art 7 git

我一直在尝试将项目子库拆分为新的仓库,但我想要分离整个文件夹路径,而不仅仅是目标文件夹.

当我过滤时,生成的文件夹结构是目标文件夹的父级,而不是存储库根目录(或我指定的祖先),它有效地破坏了包结构,因为类不再正确匹配文件夹:

原始回购:

+- repo/master
    +- lib1
    +- lib2
    +- lib3
        +- ClassA
        +- ClassB
        +- ClassC
Run Code Online (Sandbox Code Playgroud)

Git命令:

git subtree split -P lib3 -b new-branch
Run Code Online (Sandbox Code Playgroud)

结果结构:

+- repo/new-branch
    +- ClassA
    +- ClassB
    +- ClassC
Run Code Online (Sandbox Code Playgroud)

所需结构:

+- repo/new-branch
    +- lib3
        +- ClassA
        +- ClassB
        +- ClassC
Run Code Online (Sandbox Code Playgroud)

有没有办法做到这一点?我已经阅读了关于变基的文章,以某种方式添加根"核心"文件夹,好像它在拆分之前就已存在,但我的git-fu不够强大,可悲的是:(

我尝试的另一件事是filter-branch删除其他目录,但我似乎只能删除一个根级文件夹,然后当我尝试其他时git开始抱怨.

谢谢 :)

ams*_*ams 8

git subtree split 似乎没有提供你想要的选项(但它听起来很有用,所以也许你可以为项目贡献一个!)

因此,根据您的需要,有两种方法可以做到这一点.

1)导出单个目录(更简单的选项)

这利用了您想要移动到另一个repo的事实,因此我们可以提取子树,然后在单独的步骤中重新定位它.

  1. 用于git subtree split将您想要的文件提取到存储库中的中间分支(您已经完成了此操作).

    git subtree split -P lib3 -b new-branch
    
    Run Code Online (Sandbox Code Playgroud)
  2. 创建一个新的空存储库:

    git init lib3-repo
    cd lib3-repo
    
    Run Code Online (Sandbox Code Playgroud)
  3. 将中间分支的内容添加为子树:

    git subtree add -P lib3 repo new-branch
    
    Run Code Online (Sandbox Code Playgroud)

这应该再次重写历史记录并重新插入缺少的目录级别.

每当你想要在两个仓库之间交换历史时,你将不得不通过中间分支(即subtree split,然后subtree pull),但它应该工作.

2)导出任何文件集(更复杂)

要保留多个特定的子树,您需要git filter-branch.

有很多方法可以选择要保留或丢弃的提交和文件,但是这个方法用于--index-filter选择文件而无需访问文件的内容.

将所有文件保留在"lib3"和"src/core"目录中,而不以任何方式编辑其位置.

git co -b new-branch
git filter-branch --index-filter \
    'git ls-files \
       | grep -v "^lib3/\|^src/core/" \
       | xargs --no-run-if-empty git rm --cached'; \
    HEAD
Run Code Online (Sandbox Code Playgroud)

过滤器代码是一个shell脚本,用于编辑Git 索引(我们正在使用--index-filter,请记住).

git ls-files是一样的ls,除了它列出文件回购,而不是在工作树.

grep -v <pattern>提供与模式不匹配的所有内容,并且\|在模式中是替代方案,因此我们获取要删除的文件列表.

xargs --no-run-if-empty 为管道输入中的每个文件名运行一个命令(除非没有).

git rm --cached 从索引中删除文件.

这将创建一个branch(new-branch),其中包含您想要的过滤文件.您可以使用普通的pull命令将它们导入另一个repo:

git init new-repo
cd new-repo

git remote add origin /path/to/old-repo 
git pull origin new-branch
Run Code Online (Sandbox Code Playgroud)

  • 对于方法1)值得一提的是,新存储库不能为空,git会抱怨。因此,在添加子树之前至少添加一次提交。 (3认同)
  • 感谢@HappyCactus提供的关于方法1)的技巧:如果您从一个空的仓库开始,`git subtree add`会给您一个错误:`致命:模棱两可的参数'HEAD':未知修订或路径不在工作树中。在这种情况下,请执行:git commit --allow-empty -m“初始提交” (3认同)