如何在Git存储库中移动现有的Git子模块?

我想在我的Git超级项目中更改一个Git子模块的目录名称。

让我们假设我的.gitmodules文件中有以下条目:

[submodule ".emacs.d/vimpulse"]
path = .emacs.d/vimpulse
url = git://gitorious.org/vimpulse/vimpulse.git
我必须输入什么才能将.emacs.d/vimpulse目录移动到.emacs.d/vendor/vimpulse而不首先删除它(解释了) 在这里在这里),然后重新添加它

Git真的需要子模块标签中的整个路径吗

[submodule ".emacs.d/vimpulse"]

或者也可以只存储子项目的名称?

[submodule "vimpulse"]
157459 次浏览

“[submodule”后面引号中的字符串并不重要。如果你愿意,你可以把它改成“foobar”。它用于在“.git/config”中查找匹配的条目。

因此,如果你在运行"git submodule init"之前进行更改,它会正常工作。如果你做了更改(或通过合并进行更改),你需要手动编辑.git/config或再次运行"git submodule init"。如果您选择后者,您将在.git/config中留下一个带有旧名称的无害的“搁浅”条目。

更新版本的git

Git现在支持移动子模块:

自从git 1.8.5以来,git mv old/submod new/submod就像预期的那样工作,为你做了所有的管道工作。您可能希望使用git 1.9.3或更新版本,因为它包含了针对子模块移动的修复。

git的旧版本

正如评论中提到的,这个答案指的是旧版本git所需的步骤。

这个过程类似于你如何删除一个子模块(参见如何删除子模块?):

  1. 编辑.gitmodules并适当改变子模块的路径,并将其放在git add .gitmodules的索引中。

  2. 如果需要,创建子模块新位置的父目录(mkdir -p new/parent)。

  3. 将所有内容从旧目录移动到新目录(mv -vi old/parent/submodule new/parent/submodule)。

  4. 确保Git跟踪这个目录(git add new/parent)。

  5. git rm --cached old/parent/submodule删除旧目录。

  6. 将目录.git/modules/old/parent/submodule及其所有内容移动到.git/modules/new/parent/submodule

  7. 编辑.git/modules/new/parent/config文件,确保工作树项指向新的位置,因此在本例中它应该是worktree = ../../../../../new/parent/module。通常在该位置的直接路径中应该有两个以上的..目录。

  8. 编辑文件new/parent/module/.git,确保其中的路径指向主项目.git文件夹中的正确新位置,因此在本例中为gitdir: ../../../.git/modules/new/parent/submodule. exe。

    git status输出之后看起来像这样:

     # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #       modified:   .gitmodules
    #       renamed:    old/parent/submodule -> new/parent/submodule
    #
    
  9. 最后提交修改。

给出的解决方案对我不起作用,然而一个类似的版本却起作用了。

这是一个克隆的存储库,因此子模块git repos包含在顶级存储库.git目录中。所有阳离子都来自顶部存储库:

  1. 编辑.gitmodules并更改相关子模块的"path ="设置。(不需要更改标签,也不需要将该文件添加到索引。)

  2. 编辑.git/modules/name/config,修改子模块的"worktree ="设置

  3. < p >运行:

    mv submodule newpath/submodule
    git add -u
    git add newpath/submodule
    

I wonder if it makes a difference if the repositories are atomic, or relative submodules, in my case it was relative (submodule/.git is a ref back to topproject/.git/modules/submodule)

在我的例子中,我想将一个子模块从一个目录移动到另一个子目录,例如:"AFNetworking" -> "ext/AFNetworking"以下是我遵循的步骤:

  1. 编辑.gitmodules,将子模块名称和路径改为"ext/AFNetworking"
  2. 移动子模块的git目录。git/modules/AFNetworking到。git/modules/ext/AFNetworking
  3. 移动库从“AFNetworking”到“ext/AFNetworking”
  4. 编辑”。git/modules/ext/AFNetworking/config”,并修复[core] worktree行。我的从../../../AFNetworking变成了../../../../ext/AFNetworking
  5. 编辑“ext / AFNetworking /。并修复gitdir。我的从../.git/modules/AFNetworking变成了../../git/modules/ext/AFNetworking
  6. git add .gitmodules
  7. git rm --cached AFNetworking
  8. git submodule add -f <url> ext/AFNetworking

最后,我在git状态中看到:

matt$ git status
# On branch ios-master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   .gitmodules
#   renamed:    AFNetworking -> ext/AFNetworking

瞧。上面的例子没有改变目录深度,这对任务的复杂性有很大影响,也没有改变子模块的名称(这可能真的没有必要,但我这样做是为了与在该路径添加新模块时发生的情况保持一致)。

诀窍似乎是理解子模块的.git目录现在保存在主存储库中,在.git/modules下,并且每个子模块都有一个指向它的.git文件。这是你现在需要的程序:

  • 将子模块移动到它的新家。
  • 编辑子模块工作目录中的.git文件,并修改其包含的路径,使其指向主存储库.git/modules目录中的正确目录。
  • 进入主存储库的.git/modules目录,并找到与你的子模块对应的目录。
  • 编辑config文件,更新worktree路径,使其指向子模块工作目录的新位置。
  • 编辑主存储库根目录下的.gitmodules文件,将路径更新到子模块的工作目录。
  • git add -u
  • git add <parent-of-new-submodule-directory>(重要的是要添加,而不是子模块目录本身。)

注意事项:

  • .gitmodules.git/config中的[submodule "submodule-name"]行必须相互匹配,但不对应任何其他内容。
  • 子模块工作目录和.git目录必须正确指向对方。
  • .gitmodules.git/config文件应该同步。

您只需添加一个新的子模块,并使用标准命令删除旧的子模块。(应该防止.git内部的任何意外错误)

示例设置:

mkdir foo; cd foo; git init;
echo "readme" > README.md; git add README.md; git commit -m "First"
## add submodule
git submodule add git://github.com/jquery/jquery.git
git commit -m "Added jquery"
## </setup example>

移动jquery到vendor/jquery/jquery的例子:

oldPath="jquery"
newPath="vendor/jquery/jquery"
orginUrl=`git config --local --get submodule.${oldPath}.url`


## add new submodule
mkdir -p `dirname "${newPath}"`
git submodule add -- "${orginUrl}" "${newPath}"


## remove old submodule
git config -f .git/config --remove-section "submodule.${oldPath}"
git config -f .gitmodules --remove-section "submodule.${oldPath}"
git rm --cached "${oldPath}"
rm -rf "${oldPath}"              ## remove old src
rm -rf ".git/modules/${oldPath}" ## cleanup gitdir (housekeeping)


## commit
git add .gitmodules
git commit -m "Renamed ${oldPath} to ${newPath}"

大子模块的奖励方法: < / >强

如果子模块很大,并且您不想等待克隆,那么可以使用旧的子模块作为源来创建新的子模块,然后切换源。

示例(使用相同的示例设置)

oldPath="jquery"
newPath="vendor/jquery/jquery"
baseDir=`pwd`
orginUrl=`git config --local --get submodule.${oldPath}.url`


# add new submodule using old submodule as origin
mkdir -p `dirname "${newPath}"`
git submodule add -- "file://${baseDir}/${oldPath}" "${newPath}"


## change origin back to original
git config -f .gitmodules submodule."${newPath}".url "${orginUrl}"
git submodule sync -- "${newPath}"


## remove old submodule
...

只需使用shell脚本git-submodule-move

[更新:2014-11-26]Yar总结如下,在你做任何事情之前,确保你知道子模块的URL。如果未知,打开.git/.gitmodules并检查键submodule.<name>.url

对我有用的是使用git submodule deinit <submodule>后跟git rm <submodule-folder>移除旧的子模块。然后用新的文件夹名再次添加子模块并提交。在提交前检查git状态会显示旧子模块重命名为新名称,.gitmodule被修改。

$ git submodule deinit foo
$ git rm foo
$ git submodule add https://bar.com/foo.git new-foo
$ git status
renamed:    foo -> new-foo
modified:   .gitmodules
$ git commit -am "rename foo submodule to new-foo"

我昨天刚刚经历了这个考验,这个答案工作得很完美。为了清晰起见,以下是我的步骤:

  1. 确保子模块被签入并推入到它的服务器。你还需要知道它在哪个分支上。
  2. 您需要子模块的URL !使用more .gitmodules,因为一旦你删除了子模块,它就不存在了
  3. 现在你可以使用deinitrmsubmodule add

例子

命令

    git submodule deinit Classes/lib/mustIReally
git rm foo
git submodule add http://developer.audiob.us/download/SDK.git lib/AudioBus


# do your normal commit and push
git commit -a

注意: git mv不这样做。在所有。

最现代的答案来自Valloric的评论:

  1. 升级到Git 1.9.3(或2.18如果子模块包含嵌套子模块)
  2. git mv old/submod new/submod
  3. 之后.gitmodules和子模块目录已经被提交(你可以用git status来验证这一点)。
  4. 使用__abc0提交更改,然后就可以开始了!

完成了!

我遇到同样的问题并成功地解决了它。感谢这个Github问题delete_git_submodule.md

要移除一个子模块,你需要:

  • .gitmodules文件中删除相关的部分。
  • 执行.gitmodules更改,git add .gitmodules
  • .git/config中删除相关部分。(也许并不存在)
  • 运行git rm --cached path_to_submodule(没有后面的斜杠)。
  • 运行rm -rf .git/modules/path_to_submodule(没有后面的斜杠)。
  • 提交git commit -m "Removed submodule "
  • 删除现在未跟踪的子模块文件rm -rf path_to_submodule

对我来说,运行git mv <old/path> <new/path失败了:

Rename from 'old/path' to 'new/path' failed. Should I try again? (y/n)

运行git deinit <old/path>后,我能够使用git mv