在子目录位于主仓库和子模块中的分支之间切换

Ale*_*exy 12 git git-submodules

我们已经将一个子目录S变成了一个单独的仓库,并将其重新添加为分支B中的子模块.现在,当我想切换回原始分支A时,子目录被检入原始仓库,git抱怨来自子模块的东西是未跟踪的,必须先将其移走.我们可以切换回A,而无需手动拖动S并将它移回B中吗?

更新:下面的评论表明它可能是旧分支的缺陷,并且git不愿意在这里做一件聪明的事情.是这样的,在主回购中使用S的原始分支有什么样的变基(如果有的话)可以让它在任何时候与子模块化版本共存并且可以结账吗?

Chr*_*sen 11

您的历史记录如下所示:

---X     A
    \
     Y   B
Run Code Online (Sandbox Code Playgroud)

git ls-tree A 节目(例如):

040000 tree 48770cdc854cc14fecc71029180be7a979f4baa1    S
100644 blob beac6e189b7c69b249271b52cd2db5e418c05a50    file
Run Code Online (Sandbox Code Playgroud)

git ls-tree A:S 节目(例如):

100644 blob 6357df9903460c9e8b43311aff3c7a6fd7fe6aa1    somefile
Run Code Online (Sandbox Code Playgroud)

git ls-tree B 节目(例如):

100644 blob 1f8556335163a2bcbcc366a17d08d1f8e0540e6f    .gitmodules
160000 commit 234871cd6f0c1f9109e483383d7712dd8a1986e5  S
100644 blob beac6e189b7c69b249271b52cd2db5e418c05a50    file
Run Code Online (Sandbox Code Playgroud)

(cd S; git ls-tree HEAD) 节目(例如):

100644 blob abccc3958be33be4b93f56efae1b60820545aad2    somefile
Run Code Online (Sandbox Code Playgroud)

您希望从提交Y(或更高版本)移动到提交X(或更早),反之亦然.

如果你的活动分支是B,那么git checkout A说(例如):

error: The following untracked working tree files would be overwritten by checkout:
        S/somefile
Please move or remove them before you can switch branches.
Aborting
Run Code Online (Sandbox Code Playgroud)

除非你告诉它(例如使用"强制"选项),否则Git会非常努力地永远不会丢失数据.Git在这里发现并报告的问题是,分支A具有不同的内容,S/somefile然后是工作树.因为S/somefile没有跟踪(从超级项目的角度来看),Git拒绝替换文件,因此拒绝切换分支/提交.

Git可以说是更聪明一点(通过注意文件在子模块中被跟踪,因此在超级项目中切换分支时不应该被认为是未跟踪的),但它是当前实现的限制.Git的Google Summer of Code 2011项目旨在解决某些子模块支持领域,但我不清楚这个问题是否会被涵盖.


你可以按照你的建议重写你的历史记录,以便S总是看起来像是一个子模块.这肯定会为将来的提交开关提供最平滑的表面,但是由于您需要确保在子模块的源存储库中提交反映S原始提交中目录的每个历史状态的事实,这很复杂.如果你有许多不同的S树(即你S在将它转换为子模块之前进行了一些局部更改),那么这可能是一个复杂的过程/脚本.

一个更简单的解决方法可能是在切换到将其作为目录的提交之前临时签出子模块中的"空分支".

  • 在子模块中创建"空分支".

    git checkout --orphan empty
    git rm -r --cached .
    git commit --allow-empty -mempty
    
    Run Code Online (Sandbox Code Playgroud)

    您可以在子模块的原始存储库中发布此"分支",以便其他任何人都不需要自己重新创建它.

  • 当你需要从S子模块的提交切换到S目录的提交时,首先检查子模块中的"空分支":

    (cd S && git checkout empty)
    git checkout A
    
    Run Code Online (Sandbox Code Playgroud)

    你会看到这个警告,因为Git会留下S/.git:

    warning: unable to rmdir S: Directory not empty
    
    Run Code Online (Sandbox Code Playgroud)

    因为S/.git仍然存在,所以S在处理具有S目录的提交时,应该小心只在外部发出Git命令; 发布的Git命令S将在S/.git(在这种状态下,它只是一个"子.git存储库",而不是一个完整的子模块)而不是顶级存储库上运行.

  • 当您需要从S目录提交切换到S子模块的提交时,您需要在切换超级项目的提交后检查子模块中的相应分支/提交.
    您可以使用它git submodule update来恢复超级项目中记录的提交.或者,如果您正在处理子模块中的分支,请将其检出.

    git checkout B
    
    # THEN
    
    git submodule update
    
    #   OR checkout a specific branch
    
    (cd S && git checkout master)
    
    #   OR checkout previous branch
    
    (cd S && git checkout -)
    
    Run Code Online (Sandbox Code Playgroud)