Git:递归移动子模块(嵌套子模块)

13

我有以下的git结构

- git-repo a
-- subdirectory 2015
--- git-submodule b
-- git-submodule c
--- git-submodule d
我想将git子模块c移动到2015文件夹中。我知道有“不正当的方法”可以实现这一点(涉及修改.git/config并更改.git/modules文件中几个文件中的gitdir)。
我最近读到git mv应该能够做到这一点,即运行:
git mv c 2015/

对于没有嵌套子模块的代码库(例如我的情况中的d),这种方法可以正常运行。然而,当我在我的目录上运行此命令时,会出现类似以下错误:

fatal: Not a git repository: d/../../.git/modules/c/modules/d
fatal: 'git status --porcelain' failed in submodule 2015/c

(注:在执行上述移动操作后,此错误会在 git status 命令中出现)

有人知道一种干净的方法来进行此移动吗?(即不需要手动更改 .git/modules 文件中的路径)

编辑:(2015年6月10日)

目前我最好的解决方案不涉及对任何 git 配置文件的修改(首先确保所有对 d 的更改已提交并推送到某个地方)

rm c/d -rf
git mv c 2015
cd 2015/c
git submodule update

编辑:(2015年8月10日)

更不具侵入性的解决方法。

git mv c 2015
rm 2015/c/d/.git
cd 2015/c
git submodule update

编辑:(2018年9月21日)

自Git 2.19版本以来,已经修复了此问题,git mv的行为与预期相同。

2个回答

7

更新Q2 2018和Git 2.18:

使用"git mv"移动一个包含子模块的子模块时,忘记对嵌套的子子模块进行必要的调整;
现在代码路径已经学会递归进入子模块

请查看由Jonathan Tan (jhowtan)于2018年3月28日提交的提交 6856077
请查看由Stefan Beller (stefanbeller)于2018年3月28日提交的提交 da62f78, 提交 0c89fdd, 提交 3b8fb39, 提交 f793b89, 提交 61aad92
(已合并至提交 0c7ecb7,作者为Junio C Hamano -- gitster --,发布日期为2018年5月8日)

子模块:移动子模块后修复嵌套的子模块

由于子模块本身可以有嵌套的子模块,因此我们希望在需要时修复嵌套的子模块。添加一个选项以递归进入嵌套的子模块并连接它们。

由于子模块是通过其名称(确定其与超级项目的git目录相关联)在内部标识的,并且通过超级项目的工作树中的路径进行标识,因此我们需要确保名称<->路径映射保持完整。我们可以通过先编写.gitmodules文件,然后强制重新加载子模块配置机制来在git-mv命令中实现这一点。


2017年第四季度更新:

最新的Git 2.14.x/2.15 (2017年第四季度)文档记录了该漏洞

请参见提交记录c514167 (2017年9月15日) by Heiko Voigt (hvoigt)
(由Junio C Hamano -- gitster --于2017年9月25日合并至提交记录450b908)

当使用 git-mv 命令移动子模块时,它会检测到并更新相关配置文件(.gitmodules、工作树和 gitfile)的路径。
但对于递归子模块,在用户重命名根子模块时,此方法无效。

原始答案 2015

我刚刚在 Windows 上使用 git 2.6.0 进行了测试,移动包含嵌套子模块的子模块似乎存在问题:

C:\Users\vonc\prog\git\tests\submove>git clone --recursive a a1
Cloning into 'a1'...
done.
Submodule '2015/b' (C:/Users/vonc/prog/git/tests/submove/b) registered for path '2015/b'
Submodule 'c' (C:/Users/vonc/prog/git/tests/submove/c) registered for path 'c'
Cloning into '2015/b'...
done.
Submodule path '2015/b': checked out 'dc18955ec7b9ad0c04245968e2474646e4d593b2'
Cloning into 'c'...
done.
Submodule path 'c': checked out 'fb4722eaca17ac171b7a2c8c5a1ac1e697f0ee85'
Submodule 'd' (C:/Users/vonc/prog/git/tests/submove/d) registered for path 'd'
Cloning into 'd'...
done.
Submodule path 'c/d': checked out '73cd7b8ff82519720b2fcca18df5ed00dd618b71'

我有:

a1
  c
    d
  2015
    b

如果我尝试将子模块c移动到2015子文件夹中:
C:\Users\vonc\prog\git\tests\submove\a1>git mv c 2015/c

C:\Users\vonc\prog\git\tests\submove\a1>git status
fatal: Not a git repository: d/../../.git/modules/c/modules/d
fatal: 'git status --porcelain' failed in submodule 2015/c

我发现我需要在嵌套模块 d 中修改两个东西:

1/ 手动修改 .git/modules/c/modules/d/config 以注入正确的路径:

git config -f .git/modules/c/modules/d/config core.worktree ../../../../../2015/c/d
                                                                           ^^^^

2/ 修改 d 工作树:

git config -f .git/modules/c/modules/d/config core.worktree ../../../../../2015/c/d

从那里开始,git status 可以工作,但我喜欢(确保)添加一个 git submodule sync --recursive

C:\Users\vonc\prog\git\tests\submove\a1>git submodule sync --recursive
Synchronizing submodule url for '2015/b'
Synchronizing submodule url for '2015/c'
Synchronizing submodule url for '2015/c/d'

git status 显示了预期的结果:

C:\Users\vonc\prog\git\tests\submove\a1>git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   .gitmodules
        renamed:    c -> 2015/c

我添加并提交了那个更改:
C:\Users\vonc\prog\git\tests\submove\a1>git add .

C:\Users\vonc\prog\git\tests\submove\a1>git commit -m "move sub c in 2015/c"
[master 8289632] move sub c in 2015/c
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename c => 2015/c (100%)

C:\Users\vonc\prog\git\tests\submove\a1>gl
* 8289632 - (HEAD -> master) move sub c in 2015/c (3 seconds ago) <VonC>
* 7ebb8e0 - (origin/master, origin/HEAD) a with sub c (38 minutes ago) <VonC>

我现在克隆该仓库以检查移动是否被正确注册:
C:\Users\vonc\prog\git\tests\submove>git clone --recursive a1 a2
Cloning into 'a2'...
done.
Submodule '2015/b' (C:/Users/vonc/prog/git/tests/submove/b) registered for path '2015/b'
Submodule 'c' (C:/Users/vonc/prog/git/tests/submove/c) registered for path '2015/c'
Cloning into '2015/b'...
done.
Submodule path '2015/b': checked out 'dc18955ec7b9ad0c04245968e2474646e4d593b2'
Cloning into '2015/c'...
done.
Submodule path '2015/c': checked out 'fb4722eaca17ac171b7a2c8c5a1ac1e697f0ee85'
Submodule 'd' (C:/Users/vonc/prog/git/tests/submove/d) registered for path 'd'
Cloning into 'd'...
done.
Submodule path '2015/c/d': checked out '73cd7b8ff82519720b2fcca18df5ed00dd618b71'

正如您所看到的,cc/d位于预期的2015/子文件夹中:
C:\Users\vonc\prog\git\tests\submove>cd a2

C:\Users\vonc\prog\git\tests\submove\a2>dir 2015\c

 Directory of C:\Users\vonc\prog\git\tests\submove\a2\2015\c

03/10/2015  18:10    <DIR>          .
03/10/2015  18:10    <DIR>          ..
03/10/2015  18:10                29 .git
03/10/2015  18:10                40 .gitmodules
03/10/2015  18:10    <DIR>          d
               2 File(s)             69 bytes
               3 Dir(s)  23 656 910 848 bytes free

C:\Users\vonc\prog\git\tests\submove\a2>dir 2015\c\d

 Directory of C:\Users\vonc\prog\git\tests\submove\a2\2015\c\d

03/10/2015  18:10    <DIR>          .
03/10/2015  18:10    <DIR>          ..
03/10/2015  18:10                42 .git
03/10/2015  18:10                 3 d.txt
               2 File(s)             45 bytes
               2 Dir(s)  23 656 910 848 bytes free

那听起来非常像我目前的解决方法。无论如何还是谢谢。 - BartBog
@BartBog,这听起来像是一种经过优化和更精确的解决方法。如果这是一个git的bug,我认为你不会得到更好的答案。 - VonC
它确实比手动编辑配置文件要干净一些,而是通过git命令编辑工作树。不过依然很难使用。我现在已经更新了我的问题,并包含了我的最新工作流程,其中包括在移动之前删除子模块d(效果相当好且不涉及复杂的修改)。 - BartBog
@BartBog 很好。我的回答的目的更多是为了说明当涉及递归子模块时,这很可能是 git mv 的一个错误。 - VonC

4

正如@VonC在https://dev59.com/BVwY5IYBdhLWcg3wTWMu#32924692中所确认的那样,这是git mv中的一个bug。

有几种可能的解决方法。最简单的方法不需要对.git文件进行复杂的修改(自从我提出这个问题以来,我一直在使用这个方法)。它的工作原理如下:

git mv c 2015
rm 2015/c/d/.git
cd 2015/c
git submodule update

它暂时移除了d子模块中的.git文件。然后,git子模块更新会再次修复这个.git文件。

对于其他避免临时删除gitdir的解决方法,请参见此答案:https://dev59.com/BVwY5IYBdhLWcg3wTWMu#32924692


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接