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

编辑:(21/9/2018)

从 git 版本 2.19 开始。这已得到修复并按git mv预期运行。

4

2 回答 2

7

更新 2018 年第二季度和 Git 2.18:

移动一个本身包含子模块的子模块,“ git mv”忘记对嵌套的子子模块进行必要的调整;
现在代码路径学会了递归到子模块中。

请参阅Jonathan Tan ( ) 的提交 6856077(2018 年 3 月 28 日。 请参阅Stefan Beller ( )的提交 da62f78提交 0c89fdd提交 3b8fb39提交 f793b89提交 61aad92(2018 年 3 月 28 日) 。(由Junio C Hamano 合并 -- --0c7ecb7 提交中,2018 年 5 月 8 日)jhowtan
stefanbeller
gitster

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

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

由于子模块在内部由它们的名称(这决定了它们的 git 目录相对于它们的超级项目的 git 目录)以及它们在超级项目的工作树中的路径来标识,因此我们需要确保 的映射name <-> path保持不变。我们可以在git-mv命令中通过先写出.gitmodules文件然后强制重新加载子模块配置机制来做到这一点。


2017 年第四季度更新:

最新的 Git 2.14.x/2.15(2017 年第四季度)记录了该错误

请参阅Heiko Voigt ( )的提交 c514167(2017 年 9 月 15 日) 。(由Junio C Hamano 合并 -- --提交 450b908中,2017 年 9 月 25 日)hvoigt
gitster

git-mv与子模块一起使用时,它会检测到并更新其配置(.gitmodules、工作树和 gitfile)的路径。
这不适用于用户重命名根子模块的递归子模块。


原始答案 2015

我刚刚使用 git 2.6.0(在 Windows 上)对其进行了测试,并且使用自己的嵌套子模块移动子模块似乎有问题:

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

从那里开始, agit status有效,但我喜欢(可以肯定)添加 a 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'

如您所见,c并且c/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
于 2015-10-03T16:14:18.607 回答
4

正如@VonC 在https://stackoverflow.com/a/32924692/2274140中所确认的,这是 git mv 中的一个错误。

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

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

它临时删除子模块中的 .git 文件d。git 子模块更新然后再次修复这个 .git 文件。

有关避免临时删除 gitdir 的其他解决方法,请参阅此答案:https ://stackoverflow.com/a/32924692/2274140

于 2016-06-23T09:09:18.713 回答