962

I've created a git repository with a submodule in it. I'm able to tell the submodule itself to change its remote repository path, but I'm not sure how to tell the parent repository how to change the remote repository path for the submodule.

I wouldn't be surprised if I'm somewhat out of luck and have to do things manually, as even deleting submodules isn't easy.

Dawnkeeper
  • 2,844
  • 1
  • 25
  • 41
Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
  • 33
    Note: Git 2.25 (Q1 2020) comes with [a new command](https://stackoverflow.com/a/914135/6309)": `git submodule set-url [--] ` – VonC Dec 16 '19 at 21:37
  • 3
    There's an answer for that [below](https://stackoverflow.com/a/914135/442022). Please upvote it! – colan Jan 20 '21 at 16:44

9 Answers9

1270

You should just be able to edit the .gitmodules file to update the URL and then run git submodule sync --recursive to reflect that change to the superproject and your working copy.

Then you need to go to the .git/modules/path_to_submodule dir and change its config file to update git path.

If repo history is different then you need to checkout new branch manually:

git submodule sync --recursive
cd <submodule_dir> 

git fetch
git checkout origin/master
git branch master -f
git checkout master
Sergei Krivonos
  • 4,217
  • 3
  • 39
  • 54
Jim Puls
  • 79,175
  • 10
  • 73
  • 78
  • 1
    What affect should git submodule sync have? Am I doing it incorrectly in http://gist.github.com/120723 , or am I incorrect in expecting .git/config to be changed by git submodule sync? – Andrew Grimm May 31 '09 at 02:57
  • 30
    This doesn't seem to update .git/config, at least in 1.7.1 or 1.7.3. – davidtbernal Nov 02 '10 at 22:25
  • 7
    does this update the submodule url configuration for the previous commits also? ex if i checkout a older commit, will it point to new submodule urls? – maxmelbin Aug 16 '12 at 11:32
  • 75
    Use `git submodule foreach -q git config remote.origin.url` to see "actual" submodule urls – Joel Purra Oct 05 '12 at 19:51
  • @VonC and so it possible to have more than one remote git repo for a submodule? if so how do i do it? – abbood Nov 15 '13 at 08:46
  • @abbood not that I know of. Each submodule is associated with one, and only one, git repo. – VonC Nov 15 '13 at 09:18
  • 14
    It didn't update `.git/config` for me using git 2.1.0. I had to update both `.gitmodules` and `.git/config` manually before running a `git submodule sync --recursive` to have my submodule remote be updated. – desseim Sep 11 '14 at 09:32
  • How do I then commit this change in the .gitmodules file? what happens if I checkout a branch/commit earlier than this change? What happens if the old repo and the new repo aren't exactly the same? What will I have in the .git of the submodule? in the working directory of the submodule? – Motti Shneor Jan 17 '16 at 19:44
  • You can add multiple remotes from inside a subrepo using TortoiseGit so you must be able to do it on the command line. Those extra remotes are local-only, they won't get pushed with the rest of the settings. The extra remotes information ends up in the parent repo's `.git\modules\submodules\name_of_submodule\config` file. – CAD bloke Feb 27 '16 at 12:12
  • I had to 'touch' the .gitmodule file to make this work correctly. – Jimmy Johnson Dec 23 '16 at 05:12
  • 1
    I don't recommend this approach if the path is also changing, as it will leave stale references to the old submodule path inside .git that are difficult/impossible to clean up manually. It's cleaner to run `git submodule deinit modulename` followed by `git submodule init git@server/path/to/repo.git modulename`. – Aaron D Nov 29 '17 at 16:06
  • 19
    This appears to be missing the key step of `git submodule update --init --recursive --remote` which actually changes the repository to the new remote – Jason Axelson May 26 '19 at 19:05
  • 2
    Since this is the highest-voted answer, it should probably be updated; see [this answer](https://stackoverflow.com/a/914135/5666171) – CLOVIS Mar 18 '20 at 22:48
  • None of these worked for me. I had to `cd mymodulename` then `git remote --set-url origin ` – DLight Jun 11 '20 at 13:50
  • In case you are in a "linked working tree" (attached worktree), the config file is not in `.git/modules/path_to_submodule` , but in `path_to_main_working_tree/.git/worktrees/worktree_name/modules/path_to_submodule`. – Johannes Mar 21 '21 at 20:31
276

With Git 2.25 (Q1 2020), you can modify it.
See "Git submodule url changed" and the new command

git submodule set-url [--] <path> <newurl>

(On the -- separator, see "double hyphen as a signal to stop option interpretation and treat all following arguments literally")

WARNING: Hi-Angel mentions in the comments (tested even with Git 2.31.1):

One should be careful with git submodule set-url because it has a bug:

If, inside your .gitmodules file, the path looks like this some-path, and then you execute a:

# Usually causes unexpected behavior
git submodule set-url some-path/ new-url

(note the trailing slash / in some-path/), then, instead of modifying existing submodule, the command will add another one. Instead run:

# Good
git submodule set-url some-path new-url

Original answer (May 2009, fourteen years ago)

Actually, a patch has been submitted in April 2009 to clarify gitmodule role.

So now the gitmodule documentation does not yet include:

The .gitmodules file, located in the top-level directory of a git working tree, is a text file with a syntax matching the requirements -of linkgit:git-config4.
[NEW]:
As this file is managed by Git, it tracks the +records of a project's submodules.
Information stored in this file is used as a hint to prime the authoritative version of the record stored in the project configuration file.
User specific record changes (e.g. to account for differences in submodule URLs due to networking situations) should be made to the configuration file, while record changes to be propagated (e.g. +due to a relocation of the submodule source) should be made to this file.

That pretty much confirm Jim's answer.


If you follow this git submodule tutorial, you see you need a "git submodule init" to add the submodule repository URLs to .git/config.

"git submodule sync" has been added in August 2008 precisely to make that task easier when URL changes (especially if the number of submodules is important).
The associate script with that command is straightforward enough:

module_list "$@" |
while read mode sha1 stage path
do
    name=$(module_name "$path")
    url=$(git config -f .gitmodules --get submodule."$name".url)
    if test -e "$path"/.git
    then
    (
        unset GIT_DIR
        cd "$path"
        remote=$(get_default_remote)
        say "Synchronizing submodule url for '$name'"
        git config remote."$remote".url "$url"
    )
    fi
done

The goal remains: git config remote."$remote".url "$url"


Note:

Git 2.40 (Q1 2023) clarifies git config remote.<remote>.url:

See commit d390e08 (07 Feb 2023) by Calvin Wan (CalvinWan0101).
(Merged by Junio C Hamano -- gitster -- in commit 59397e9, 15 Feb 2023)

Documentation: clarify multiple pushurls vs urls

Signed-off-by: Calvin Wan

In a remote with multiple configured URLs, git remote -v(man) shows the correct url that fetch uses.

However, git config remote.<remote>.url(man) returns the last defined url instead.

This discrepancy can cause confusion for users with a remote defined as such, since any url defined after the first essentially acts as a pushurl.

Add documentation to clarify how fetch interacts with multiple urls and how push interacts with multiple pushurls and urls.

urls-remotes now includes in its man page:

The <pushurl> is used for pushes only.

It is optional and defaults to <URL>.

Pushing to a remote affects all defined pushurls or to all defined urls if no pushurls are defined.
Fetch, however, will only fetch from the first defined url if muliple urls are defined.

CivFan
  • 13,560
  • 9
  • 41
  • 58
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • I wanted to change the submodule's URL only on this machine. From the parent project I could modify the record in `.git/config` by doing: `git config submodule."$submodule_name".url "$new_url" ` which is [also described here](http://stackoverflow.com/a/928539/99777). – joeytwiddle Oct 27 '16 at 10:22
  • 2
    What does the optional double dashes in `git submodule set-url [--] ` do? – jeverling Feb 13 '20 at 10:59
  • 2
    @jeverling They help separate options from parameters: see https://stackoverflow.com/a/1192194/6309 – VonC Feb 13 '20 at 11:45
  • 1
    Note that for Ubuntu users with an older version git you can use this PPA to update: https://launchpad.net/~git-core/+archive/ubuntu/ppa – starbeamrainbowlabs Mar 10 '20 at 14:46
  • 1
    This should be the preferred answer now. One simple command for everything. – Johannes Jul 17 '21 at 13:24
  • 1
    What does `[--]` mean? Can you give an example? – Harry Aug 10 '21 at 05:40
  • @Harry It separates options from file parameters. I have documented the double-hyphen syntax in 2009, twelve years ago: https://stackoverflow.com/a/1192194/6309 – VonC Aug 10 '21 at 06:32
  • I would also be interested to know what the `[--]` mean – M.Ionut Dec 15 '21 at 08:11
  • 1
    @M.Ionut That is what I describe/explain in https://stackoverflow.com/a/1192194/6309 – VonC Dec 15 '21 at 08:15
  • I think that ` -- ` allows you to have a preceding `-` or `--` in the arguments that follow and not have them interpreted as options. Chances are, if you are doing direct work on the command line, you won't need this because you are probably not a maniac who puts `-` or `--` at the beginning of things. But it might happen for some reason and so for more robust scripts, you can use the ` -- ` to signal to the command line parser to no longer interpret dashes specially. It's confusing until you think of it as a script-writing tool, mainly. – Daniel Russell Mar 23 '23 at 20:33
  • @DanielRussell Good point. I really like to use `--`, precisely to *not* worry about what follows. Everything before are options, everything after, aguments. – VonC Mar 23 '23 at 21:11
203

These commands will do the work on command prompt without altering any files on local repository

git config --file=.gitmodules submodule.Submod.url https://github.com/username/ABC.git
git config --file=.gitmodules submodule.Submod.branch Development
git submodule sync
git submodule update --init --recursive --remote

Please look at the blog for screenshots: Changing GIT submodules URL/Branch to other URL/branch of same repository

Pavan Sokke Nagaraj
  • 2,385
  • 1
  • 14
  • 21
  • 11
    This worked but I had to remember to push the changes to the remote. `git add .gitmodules` `git commit -m "modified submodule URL"` `git push origin master` – skulz00 Aug 20 '15 at 14:08
  • 8
    Well, that created a terrible mess for me. Commands went down quietly, but the actual submodule repository still thinks its remote is the old one (the old URL). Maybe these commands should be accompanied with other commands within the submodule's repository? – Motti Shneor Jan 17 '16 at 20:02
  • 7
    The last command is a bit extreme... If you have submodules with submodules inside, this will remotely update the sub-submodules as well, which is unlikely what you need. – Baptiste Wicht Apr 26 '16 at 12:16
  • 12
    Note that you need replace Submod with name of your submodule! – Shital Shah Nov 15 '16 at 19:56
  • 1
    This is less risky than going into your .gitmodules file manually. thx – MayTheSForceBeWithYou Jul 22 '20 at 22:17
  • reply for other question about submodule url https://stackoverflow.com/a/42035018/205355 helpful description for command semantic – mmv-ru Jan 23 '21 at 23:13
166

In simple terms, you just need to edit the .gitmodules file, then resync and update:

Edit the file, either via a git command or directly:

git config --file=.gitmodules -e

or just:

vim .gitmodules

then resync and update:

git submodule sync
git submodule update --init --recursive --remote
Matthew Wilcoxson
  • 3,432
  • 1
  • 43
  • 48
88

What worked for me (on Windows, using git version 1.8.3.msysgit.0):

  • Update .gitmodules with the URL to the new repository
  • Remove the corresponding line from the ".git/config" file
  • Delete the corresponding directory in the ".git/modules/external" directory (".git/modules" for recent git versions)
  • Delete the checked out submodule directory itself (unsure if this is necessary)
  • Run git submodule init and git submodule update
  • Make sure the checked out submodule is at the correct commit, and commit that, since it's likely that the hash will be different

After doing all that, everything is in the state I would expect. I imagine other users of the repository will have similar pain when they come to update though - it would be wise to explain these steps in your commit message!

ViRuSTriNiTy
  • 5,017
  • 2
  • 32
  • 58
Ben Hymers
  • 25,586
  • 16
  • 59
  • 84
  • 2
    Thank you so much for this. This is the only one that worked for me after I had already run a `git submodule update`. Following the other answers wouldn't change what was in the `./git/modules/external` dir so attempting to update would result in it still pulling the incorrect url. – NtscCobalt Jul 13 '14 at 05:22
  • 1
    this seems to be a bit dangerous, and I'm not sure it preserves the history of the previous submodule. If, for instance, you want to check out an old commit or branch of your main-repository (the one containing the submodule) I'm not sure it will know to pull the OLD submodule attached and related to that old commit of the main. – Motti Shneor Jan 17 '16 at 19:40
  • No, it almost certainly won't know - you'll have to do all the steps after the first one again. This is just what I found worked for nuking the current state of the submodule. I don't know if the state of things has changed since I wrote this, mind :) – Ben Hymers Jan 18 '16 at 09:50
  • @MottiShneor that seems dangerous indeed if you need to keep the previous submodule history, though I'm not sure about it. In my case it's the only solution that worked, what I wanted was basically replace the original submodule with my own fork – arainone Feb 01 '16 at 21:21
  • 2
    Followed these steps and found that the "Delete the checked out submodule directory itself (unsure if this is necessary)" is necessary otherwise you will encounter "fatal: Not a git repository: ..." when running git submodule update – PiersyP Aug 22 '16 at 11:55
15

Just edit your .git/config file. For example; if you have a "common" submodule you can do this in the super-module:

git config submodule.common.url /data/my_local_common
FelipeC
  • 9,123
  • 4
  • 44
  • 38
  • 1
    This is only the best way if you are trying to change the URL for a one time use, not permanently in the super project. E.g. you want to clone submodules from local copies on disk. – Andy Feb 12 '20 at 17:16
3

git config --file=.gitmodules -e opens the default editor in which you can update the path

LuGo
  • 4,877
  • 1
  • 18
  • 19
-2

A brute force approach:

  • update the .gitmodules file in the supermodule to point to the new submodule url,
  • add and commit the changes to supermodule/.gitmodules,
  • make a new clone of the supermodule somewhere else on your computer (making sure that the latest changes to the .gitmodules file are reflected in the clone),
  • change your working directory to the new clone of the supermodule,
  • run git submodule update --init --remote path-to-submodule on the submodule,

et voilà! The submodule in the new clone of the supermodule is properly configured!

M2014
  • 1,094
  • 1
  • 9
  • 16
Jasha
  • 5,507
  • 2
  • 33
  • 44
-4

A lot of people (both here and on the internet at large) suggest solutions that require manually editing or deleting multiple files. But that really isn't needed!

Even in environments where Git 2.25 (and thus git submodule set-url <path> <newurl>) are not available, the easiest solution is to simply "unregister" the submodule and add it again with the new URL.

Depending on Git version and submodule setup, you might need to manually remove <path> before adding it again. No other manual actions needed!

git submodule deinit <path>
rm -rf <path>
git submodule add <repository> [<path>]

After that the .gitmodules file will have a different URL and should be committed. All other places (config, working tree) have already been handled by git.

To explain what deinit does, I'd like to quote from the Git manual:

deinit [-f|--force] (--all|[--] <path>…​)

Unregister the given submodules, i.e. remove the whole submodule.$name section from .git/config together with their work tree. Further calls [..] will skip any unregistered submodules until they are initialized again

Potherca
  • 13,207
  • 5
  • 76
  • 94