How do I move an existing Git submodule within a Git repository?
GitGit SubmodulesGit Problem Overview
I would like to change the directory name of a Git submodule in my Git superproject.
Lets suppose I have the following entry in my .gitmodules
file:
[submodule ".emacs.d/vimpulse"]
path = .emacs.d/vimpulse
url = git://gitorious.org/vimpulse/vimpulse.git
What do I have to type to move the .emacs.d/vimpulse
directory to .emacs.d/vendor/vimpulse
without deleting it first (explained
here and here) and then re-adding it.
Does Git really need the whole path in the submodule tag
[submodule ".emacs.d/vimpulse"]
or is it also possible to store just the name of the subproject?
[submodule "vimpulse"]
Git Solutions
Solution 1 - Git
Newer versions of git
Git now has native support for moving submodules:
> Since git 1.8.5, git mv old/submod new/submod
works as expected and does all the plumbing for you. You might want to use git 1.9.3 or newer, because it includes fixes for submodule moving.
Older versions of git
As mentioned in the comments, this answer refers to the steps needed with older versions of git.
The process is similar to how you'd remove a submodule (see https://stackoverflow.com/questions/1260748/how-do-i-remove-a-git-submodule):
-
Edit
.gitmodules
and change the path of the submodule appropriately, and put it in the index withgit add .gitmodules
. -
If needed, create the parent directory of the new location of the submodule (
mkdir -p new/parent
). -
Move all content from the old to the new directory (
mv -vi old/parent/submodule new/parent/submodule
). -
Make sure Git tracks this directory (
git add new/parent
). -
Remove the old directory with
git rm --cached old/parent/submodule
. -
Move the directory
.git/modules/old/parent/submodule
with all its content to.git/modules/new/parent/submodule
. -
Edit the
.git/modules/new/parent/config
file, make sure that worktree item points to the new locations, so in this example it should beworktree = ../../../../../new/parent/module
. Typically there should be two more..
than directories in the direct path in that place. -
Edit the file
new/parent/module/.git
, make sure that the path in it points to the correct new location inside the main project.git
folder, so in this examplegitdir: ../../../.git/modules/new/parent/submodule
.git status
output looks like this for me afterwards:# On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # modified: .gitmodules # renamed: old/parent/submodule -> new/parent/submodule #
-
Finally, commit the changes.
Solution 2 - Git
The most modern answer, taken from Valloric's comment above:
- Upgrade to Git 1.9.3 (or 2.18 if the submodule contains nested submodules)
git mv old/submod new/submod
- Afterwards the .gitmodules and the submodule directory are already staged for a commit (you can verify this with
git status
.) - Commit the changes with
git commit
and you're good to go!
Done!
Solution 3 - Git
In my case, I wanted to move a submodule from one directory into a subdirectory, e.g. "AFNetworking" -> "ext/AFNetworking". These are the steps I followed:
- Edit .gitmodules changing submodule name and path to be "ext/AFNetworking"
- Move submodule's git directory from ".git/modules/AFNetworking" to ".git/modules/ext/AFNetworking"
- Move library from "AFNetworking" to "ext/AFNetworking"
- Edit ".git/modules/ext/AFNetworking/config" and fix the
[core] worktree
line. Mine changed from../../../AFNetworking
to../../../../ext/AFNetworking
- Edit "ext/AFNetworking/.git" and fix
gitdir
. Mine changed from../.git/modules/AFNetworking
to../../git/modules/ext/AFNetworking
git add .gitmodules
git rm --cached AFNetworking
git submodule add -f <url> ext/AFNetworking
Finally, I saw in the git status:
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 voila. The above example doesn't change the directory depth, which makes a big difference to the complexity of the task, and doesn't change the name of the submodule (which may not really be necessary, but I did it to be consistent with what would happen if I added a new module at that path.)
Solution 4 - Git
[Update: 2014-11-26] As Yar summarizes nicely below, before you do anything, make sure you know the URL of the submodule. If unknown, open .git/.gitmodules
and examine the keysubmodule.<name>.url
.
What worked for me was to remove the old submodule using git submodule deinit <submodule>
followed by git rm <submodule-folder>
. Then add the submodule again with the new folder name and commit. Checking git status before committing shows the old submodule renamed to the new name and .gitmodule modified.
$ 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"
Solution 5 - Git
The trick seems to be understanding that the .git
directory for submodules are now kept in the master repository, under .git/modules
, and each submodule has a .git
file that points to it. This is the procedure you need now:
- Move the submodule to its new home.
- Edit the
.git
file in the submodule's working directory, and modify the path it contains so that it points to the right directory in the master repository's.git/modules
directory. - Enter the master repository's
.git/modules
directory, and find the directory corresponding to your submodule. - Edit the
config
file, updating theworktree
path so that it points to the new location of the submodule's working directory. - Edit the
.gitmodules
file in the root of the master repository, updating the path to the working directory of the submodule. git add -u
git add <parent-of-new-submodule-directory>
(It's important that you add the parent, and not the submodule directory itself.)
A few notes:
- The
[submodule "submodule-name"]
lines in.gitmodules
and.git/config
must match each other, but don't correspond to anything else. - The submodule working directory and
.git
directory must correctly point to each other. - The
.gitmodules
and.git/config
files should be synchronised.
Solution 6 - Git
The string in quotes after "[submodule" doesn't matter. You can change it to "foobar" if you want. It's used to find the matching entry in ".git/config".
Therefore, if you make the change before you run "git submodule init", it'll work fine. If you make the change (or pick up the change through a merge), you'll need to either manually edit .git/config or run "git submodule init" again. If you do the latter, you'll be left with a harmless "stranded" entry with the old name in .git/config.
Solution 7 - Git
You can just add a new submodule and remove the old submodule using standard commands. (should prevent any accidental errors inside of .git)
Example setup:
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>
Examle move 'jquery' to '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}"
Bonus method for large submodules:
If the submodule is large and you prefer not to wait for the clone, you can create the new submodule using the old as origin, and then switch the origin.
Example (use same example setup)
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
...
Solution 8 - Git
Just use the shell script git-submodule-move.
Solution 9 - Git
The given solution did not work for me, however a similar version did...
This is with a cloned repository, hence the submodule git repos are contained in the top repositories .git dir. All cations are from the top repository:
-
Edit .gitmodules and change the "path =" setting for the submodule in question. (No need to change the label, nor to add this file to index.)
-
Edit .git/modules/name/config and change the "worktree =" setting for the submodule in question
-
run:
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)
Solution 10 - Git
I just went through this ordeal yesterday and this answer worked perfectly. Here are my steps, for clarity:
- Ensure that submodule is checked in and pushed to its server. You also need to know what branch its on.
- You need the URL of your submodule! Use
more .gitmodules
because once you delete the submodule it's not going to be around - Now you can use
deinit
,rm
and thensubmodule add
EXAMPLE
- Git submodule is in: Classes/lib/mustIReally
- Moving to: 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
NOTE: git mv doesn't do this. At all.
Solution 11 - Git
I meet the same problem and solve it successfully. Thanks for this Github issue delete_git_submodule.md
To remove a submodule you need to:
- Delete the relevant section from the
.gitmodules
file. - Stage the .gitmodules changes,
git add .gitmodules
- Delete the relevant section from
.git/config
. (maybe doesn't exists) - Run
git rm --cached path_to_submodule
(no trailing slash). - Run
rm -rf .git/modules/path_to_submodule
(no trailing slash). - Commit
git commit -m "Removed submodule "
- Delete the now untracked submodule files
rm -rf path_to_submodule