Renaming a Folder in Git That Contains Submodules

Because of some project structure changes. It was required to renamed some folders. In git this should be as easy as running git mv. But when the folders you are trying to move contain submodules. Its a whole different story.

$ git mv old/ new

fatal: source directory is empty, source=old/cookbooks/apache2, destination=new/cookbooks/apache2

Like i said. This seems to work for normal folders. But submodules are a bit more complicated because of paths set in various files. So let’s try just moving them on the filesystem.

$ mv old/ new
$ git status

# deleted: old/VVagrantfile.example
# deleted: old/cookbooks/apache2
# deleted: old/cookbooks/apt
# deleted: old/cookbooks/beanstalkd/.travis.yml

That’s not what we’re looking for. We want to move the files. Not remove them. At this point i was at a loss and spend some time looking around stackoverflow. Which has multiple solutions available from other developers. But none seemed to fit the bill. So i ended up combining a couple.

First create the new location and add it to the git index.

$ mkdir new
$ git add new

In my case i had normal folders and submodules in the same directory. So first i moved the normal folders to the new structure.

$ git mv old/[some folder] /new

Now it’s time for the submodules. We need to update the paths in each submodule’s .git file. And the paths in project .gitmodule file

$ find . -name .git -type f -print0 -type f | xargs -0 sed -i 's|old|new|g'
$ find . -name .gitmodule -type f -print0 -type f | xargs -0 sed -i 's|old|new|g'

After that add the .gitmodule file to the git index and checkout the status

$ git add .gitmodule
$ git status 

fatal: Could not chdir to ‘../../../../../new/cookbooks/apache2’: No such file or directory
fatal: ‘git status –porcelain’ failed in submodule old/cookbooks/apache2

So we’re not there yet. As it turns out the git config file also contains the submodule paths. And the .git/modules folder contains a submodule mapping as well. So let’s fix that

$ find . -name config -print0 -type f | xargs -0 sed -i 's|old|new|g'
$ mv .git/modules/old .git/modules/new
$ git status

That looks good

modified: .gitmodules
# renamed: old/Vagrantfile.example -> new/Vagrantfile.example
# renamed: old/cookbooks/apache2 -> new/cookbooks/apache2
# renamed: old/cookbooks/apt -> new/cookbooks/apt
# renamed: old/cookbooks/beanstalkd/.travis.yml -> new/cookbooks/beanstalkd/.travis.yml

Now we can remove the old folder from the git project and commit the changes.

$ git rm -r --cached old/
$ git commit -a -m "Moved old to new folder"
$ git push
comments powered by Disqus