如何在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是否真的需要子模块标签中的整个path
[submodule ".emacs.d/vimpulse"]
或者也可以只存储子项目的名称?
[submodule "vimpulse"]
注意:正如在评论中提到的,这个答案是指旧版本的git所需的步骤。 Git现在支持移动子模块:
既然git 1.8.5,
git mv old/submod new/submod
按预期工作,并为你做所有的pipe道工作。 您可能想要使用git 1.9.3或更高版本,因为它包含子模块移动修复程序。
这与您如何移除子模块相似(请参阅如何移除子模块? ):
- 编辑
.gitmodules
并适当地更改子模块的path,并使用git add .gitmodules
将其放在索引中。 - 如果需要,创build子模块的新位置(
mkdir -p new/parent
)的父目录。 - 将所有内容从旧目录移到新目录(
mv -vi old/parent/submodule new/parent/submodule
)。 - 确保Git跟踪这个目录(
git add new/parent
)。 - 用
git rm --cached old/parent/submodule
删除旧的目录。 - 将目录
.git/modules/old/parent/submodule
及其所有内容移至.git/modules/new/parent/submodule
。 - 编辑
.git/modules/new/parent/config
文件,确保worktree项指向新的位置,所以在这个例子中它应该是worktree = ../../../../../new/parent/module
。 通常应该有两个以上的目录,然后在那个地方的直接path中。 -
编辑文件
new/parent/module/.git
,确保其中的path指向主项目.git
文件夹内的正确的新位置,所以在本例中gitdir: ../../../.git/modules/new/parent/submodule
.git
gitdir: ../../../.git/modules/new/parent/submodule
。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 #
-
最后,进行更改。
最现代的答案,取自Valloric上面的评论:
- 升级到Git 2.0(或至less1.9.3)
-
git mv old/submod new/submod
- 之后,.gitmodules和submodule目录已经被提交了一个提交(你可以用
git status
来validation)。 - 用
git commit
提交更改,而且你还是很好的!
完成!
在我的情况下,我想将一个子目录从一个目录移动到子目录,例如“AFNetworking” – >“ext / AFNetworking”。 这些是我遵循的步骤:
- 编辑.gitmodules更改子模块的名称和path为“ext / AFNetworking”
- 将子模块的git目录从“.git / modules / AFNetworking”移动到“.git / modules / ext / AFNetworking”
- 将库从“AFNetworking”移动到“ext / AFNetworking”
- 编辑“.git / modules / ext / AFNetworking / config”并修复
[core] worktree
行。 从../../../AFNetworking
改为../../../../ext/AFNetworking
- 编辑“ext / AFNetworking / .git”并修复
gitdir
。 从../.git/modules/AFNetworking
改为../../git/modules/ext/AFNetworking
-
git add .gitmodules
-
git rm --cached AFNetworking
-
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
Et瞧。 上面的例子并没有改变目录深度,这对任务的复杂性有很大的影响,并且不会改变子模块的名字(这可能并不是真的有必要,但是我是这么做的如果我在该path上添加了一个新模块,将会发生。)
[更新:2014-11-26]正如Yar总结的那样, 在你做任何事情之前,请确保你知道子模块的URL。 如果未知,请打开.git/.gitmodules
并检查关键submodule.<name>.url
。
对我而言,使用git submodule deinit <submodule>
然后使用git rm <submodule-folder>
删除旧的子 git submodule deinit <submodule>
。 然后再次使用新的文件夹名称添加子模块并提交。 提交之前检查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"
技巧似乎是理解,子模块的.git
目录现在保存在主存储库中的.git/modules
,并且每个子模块都有一个指向它的.git
文件。 这是你现在需要的程序:
- 将子模块移到新家。
- 编辑子模块的工作目录中的
.git
文件,并修改其包含的path,使其指向主存储库的.git/modules
目录中的正确目录。 - input主存储库的
.git/modules
目录,并find与您的子模块对应的目录。 - 编辑
config
文件,更新工作worktree
path,使其指向子模块工作目录的新位置。 - 编辑主存储库根目录下的
.gitmodules
文件,更新子模块工作目录的path。 -
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}"
大型子模块的奖金方法:
如果子模块很大,而您不希望等待克隆,则可以使用旧的作为原点来创build新的子模块,然后切换原点。
示例(使用相同的示例设置)
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 ...
“[submodule]”之后的引号中的string无关紧要。 如果你愿意,你可以把它改成“foobar”。 它用来在“.git / config”中find匹配的条目。
因此,如果您在运行“git submodule init”之前进行更改,则可以正常工作。 如果你进行了更改(或通过合并来获取更改),则需要手动编辑.git / config或再次运行“git submodule init”。 如果你使用后者,你将会在.git / config中留下一个无用的“搁浅”条目,并且保留旧的名字。
给定的解决scheme不适合我,但是类似的版本…
这是与克隆的存储库,因此submodule git回购包含在顶级存储库.git目录。 所有的阳离子都来自顶层库:
-
编辑.gitmodules并更改相关子模块的“path =”设置。 (不需要更改标签,也不需要将此文件添加到索引。)
-
编辑.git / modules / name / config并更改相关子模块的“worktree =”设置
-
跑:
mv submodule newpath/submodule git add -u git add newpath/submodule
我想知道是否有所不同,如果存储库是primefaces,或相对的子模块,在我的情况下,它是相对的(submodule / .git是ref to topproject / .git / modules / submodule)
只需使用shell脚本git-submodule-move即可 。
我刚刚经历了这个磨难, 这个答案完美无缺。 这是我的步骤,为了清晰起见:
- 确保检查子模块并将其推送到其服务器。 你也需要知道它的分支。
- 你需要你的子模块的URL! 使用
more .gitmodules
因为一旦你删除子模块,它不会在周围 - 现在你可以使用
deinit
,rm
和submodule add
例
- Git子模块在:Classes / lib / mustIReally
- 移到:lib / AudioBus
- url: http : //developer.audiob.us/download/SDK.git
COMMANDS
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不会这样做。 完全一样。