Could anyone help me please. I want to move some Git repositories from one server to another, and rename them at the same time. The problem I'm having is when some repositories are submodules of other repositories. I want to replace the URL of the submodule throughout the history of all the branches within the top level module so that once the originals have been deleted I can still go back and rebuild an old commit. I'm on a Windows PC and, at the moment, I'm using a .bat file to run my repository migrations.

To move the submodule from server1 to server2 and change the name from sub_old to sub_new I clone the original (bare) into a folder on my C: drive, change the URL and then push up to the new server:

git clone --bare https://server1/sub_old.git c:\temp_repo
cd c:\temp_repo
git remote set-url origin https://server2/sub_new.git
git push --mirror

then delete sub_old from server1.

Now when I want to move a top level repo, which uses the sub_old repo as a submodule, to the new server:

git clone --bare https://server1/top_old.git c:\temp_repo
cd c:\temp_repo
git remote set-url origin https://server2/top_new.git
REM At this point I want to change all of the references to the submodule from https://server1/sub_old.git to https://server2/sub_new.git
git push --mirror

then delete top_old from server1.

At the point where I want to change all of the URL references to the submodule, I've tried using:

git config --global url.https://server2/sub_new.git.insteadOf https://server1/sub_old.git

but with no success. I clearly don't understand how this is supposed to work, or whether it's the appropriate thing to be using.

1

There are 1 answers

2
torek On

I want to replace the URL of the submodule throughout the history of all the branches ...

This requires using git filter-branch or git filter-repo. It's technically impossible to change any commit, so these commands do not do that. Instead, they copy your existing repository's commits to an entirely new set of commits that contain the alternate history.1

If you choose to do this, be very sure you want to, because there is no going back. Consider using the newfangled git filter-repo, which is better at this sort of thing.2 Remember that once you are done, nobody should ever use the old repository or any of its clones any more. Throw those clones out. Make new clones of the new repository instead.

The git config instead-of trick that you're using is sometimes a better approach. This does not replace the URL of the submodule throughout history! Instead, this leaves all the original commits intact. It just means that for you—your account only, because you used git config --global: no other users are affected by this—whenever your Git is about to reach out to the original URL, it switches to the replacement URL instead.

For this to work for any other users, those other users must take the same git config step. If that's a problem, you need the "replace the repository (all commits, which are the history) with a new repository (all-new commits representing an alternate history)" approach.


1If the rewritten "alternate history" starts from an un-rewritten commit, the alternate history is merely almost entirely new, rather than entirely new. This is, in a sense, worse, because it makes it easier to accidentally re-introduce the original history. You then have two histories, and it becomes difficult to tell which one is the "true" one.

2It does not seem to have a targeted "fix submodule URL" option, but that would be a reasonable thing to ask for. Internally that would just amount to filtering the file named .gitmodules, so it should be pretty easy to implement.