如何重命名一个包含子模块的git仓库(项目)及其子目录

19

我从未想过重命名一个Git仓库,特别是指包含项目的顶级文件夹会如此困难。是的,项目包含一些子模块,但需要重命名的是 顶级文件夹,而不是 子模块文件夹。Git似乎在其子模块机制中记录了一些奇怪的 绝对路径

让我们假设:

  1. 所有项目都位于 /tmp 中。
  2. 你有一个名为 proj_master 和一个名为 proj_mod 的项目。
  3. 你将 porj_master 克隆为 proj_ALL,然后将 prom_mod 克隆为其中的子模块。
  4. 你将 proj_ALL 重命名为 proj_onebillion。然后黑魔法发生了。

以下步骤将复现我提到的问题。我使用的git版本是:

$ git --version
git version 1.7.9.5
  1. 初始化proj_master

$ cd /tmp
$ mkdir proj_master; cd proj_master
$ git init .
$ touch README
$ git add .; git commit -m "hello proj_master"
  • 初始化proj_mod

  • $ cd /tmp
    $ mkdir proj_mod; cd proj_mod
    $ git init .
    $ touch README
    $ git add .; git commit -m "hello proj_mod"
    
  • proj_master 克隆为 proj_ALL,并将 proj_mod 作为子模块进行克隆。

  • $ cd /tmp
    $ git clone proj_master proj_ALL
    $ cd proj_ALL
    $ git submodule add /tmp/proj_mod ./mod
    $ git add .; git commit -m "hello proj_ALL"
    $ git status   % Everything is OK.
    
  • proj_ALL重命名为proj_onebillion。遇到致命错误。

  • $ cd /tmp
    $ mv proj_ALL proj_onebillion
    $ cd proj_onebillion
    $ git status
    fatal: Not a git repository: /tmp/proj_ALL/.git/modules/mod
    
    注意,子模块目录中有一个名为.git的文件。
    $ cat /tmp/proj_ALL/mod/.git 
    gitdir: /tmp/proj_ALL/.git/modules/mod
    

    是的,一个绝对路径。我第一次意识到,Git 了解超出顶层仓库文件夹范围的东西。

    就是这样。我再重复一遍,我重命名的是顶层项目文件夹,而不是子模块文件夹。我查看了 schmuck 的问题,他试图重命名子模块文件夹,因此似乎对我的问题没有帮助。

    如果我漏掉了应该先读的内容,我表示歉意。对于所有人,欢迎提供任何建议。

    4个回答

    12

    你有几个选项,它们最终都是相同的:

    再次克隆

    不要重命名文件夹,只需再次克隆即可。

    $ cd /project/original
    $ cd ..
    $ mkdir moved
    $ git init
    $ git pull ../original master
    $ git submodule init
    $ git submodule update
    

    比较 original/.git/configmoved/.git/config,并处理任何重要的差异(缺失分支需要创建 - 缺失的远程仓库只需添加到配置文件中)。

    修复路径

    您可以重命名项目文件夹,只需要进行一些微调即可。

    • 修复您的子模块的 .git 文件引用。

    例如这些文件:

    $ cd /project/moved
    $ find -name .git -type f
    

    你需要做的就是编辑它们,使其指向正确的目录

    • 修复你的子模块.git配置文件

    即这些文件:

    $ cd /project/moved
    $ find .git/modules/ -name config
    

    在这里,更新 worktree 设置:

    [core]
        ...
        worktree = /original/path/submodule
    
    [core]
        ...
        worktree = /moved/path/submodule
    

    就是这样了。

    关于版本的说明

    1.7.8 版本引入了在子模块中使用 .git 文件以及 使用绝对路径,这在 1.7.10 版本中得到了修复 - 因此该问题仅适用于使用 git 版本 1.7.8 和 1.7.9 创建的 git 存储库。


    谢谢,AD7six。你的技巧解决了我的问题。我只是好奇为什么git在最近的版本中使用了这样一个讨厌的方法(“绝对路径”)。 - Jianwen W.
    其他人也在抱怨这些问题。请查看"Annoying absolute path for "core.worktree" to submodule"。好消息是,在git-1.7.10中,相对路径将回归,而绝对路径将消失。 - Jianwen W.
    我注意到我的其中一台机器使用了相对路径,但没有检查版本 - 在快速的确认性研究后,我将该信息添加到答案中。 - AD7six

    5

    将包含git子模块的项目从一个文件夹移动到另一个文件夹时,需要更新一些硬编码的链接。在同一台计算机上操作。

    首先,所有的子模块都有一个.git文件,其中存储了它们的git配置文件夹的绝对路径(这些文件夹包含在主项目的.git文件夹中,分组存放在modules文件夹中)。为了修复所有这些问题,请从主项目的根目录运行以下命令:

    find . -name .git -print0 -type f | xargs -0 sed -i 's|<OLD PATH>|<NEW PATH>|g'
    

    第二,git子模块的配置文件中有一行保存工作目录的绝对路径。要同时更新所有引用,请从主项目的根目录运行以下命令:

    find . -name config -print0 -type f | xargs -0 sed -i 's|<OLD PATH>|<NEW PATH>|g'
    

    假定您的操作系统是某种形式的*nix,并且已安装sed软件包。

    4

    您还需要检查每个子模块的gitdir

    它应该在子模块的文件夹.git中。


    谢谢,这解决了我的问题。 - Colonel Sponsz

    1

    你需要实际修改两个文件

    .git/modules/<path-to-submodule>/config
    <path-to-submodule>/.git
    

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