(This documentation probably belongs in gitmodules(5) --- then, git-submodule(1) could focus on command-line usage and point there for configuration information.)
There are two aspects of this to be separated: what governs the behavior of commands running locally, and where we get information about submodules from a remote repository.
Local commands -------------- The original submodule design was that local commands rely on information from .git/config, and that information gets copied there from .gitmodules when a submodule is initialized. That way, a local user can specify their preferred mirror or other options using some straightforward 'git config' commands.
As a side effect, the settings in .git/config tell git which submodules to pay attention to (which submodules were initialized).
When .gitmodules changes, the settings in .git/config are left alone, since the end user *might* have manually set something up and we don't want to trample on it.
This design is somewhat problematic for a few reasons:
- When I want to stop paying attention to a particular submodule and
start paying attention to it again later, all my local settings are
gone.
- When upstream adds a new submodule, I have to do the same manual
work to change the options for that new submodule.
- When upstream changes submodule options (perhaps to fix a URL
typo), I don't get those updates.
A fix is to use settings from .git/config when present and fall back to .gitmodules when not. I believe the submodule code has been slowly moving in that direction for new features. Perhaps we can do so for existing features (like submodule.*.url) too.
An alternative would have been to introduce a .git/info/submodules file that overrides settings from .gitmodules, analagous to .git/info/excludes overriding .gitignore and .git/info/attributes overriding .gitattributes. We are already using .git/config for this so that doesn't seem necessary.
Remote repositories ------------------- The .gitmodules file has some odd properties as a place to put configuration:
- it is versioned. There is no way to change URLs in an old version
of .gitmodules retroactively when a URL has changed.
- it is controlled by whoever writes history. There is no way for me
to change the URLs in my mirror of https://gerrit.googlesource.com/gerrit
to match my mirror's different filesystem layout without producing
my own history that diverges from the commits I am mirroring.
When the URLs in .gitmodules are relative URLs, this means that if I mirror a superproject, I have to mirror all its submodules, too, with the same layout. It's not so easy for me to publish my copy of the parent project and the one subproject I made changes in --- I have to mirror everything. In particular, this means I can't mirror https://gerrit.googlesource.com/gerrit to github.
When the URLs in .gitmodules are absolute URLs, this means that if I mirror a superproject, I cannot ask people consuming my mirror to use my mirrors of child projects, too. I cannot publish my copy of the parent project and the one subproject I made changes in and expect people to be able to "git clone --recurse-submodules" the result successfully.
It is as though refs were stored in a .gitrefs file, with all the attendant disadvantages, instead of being a separate component of the repository that a particular repository owner can manipulate without changing history.
To fix this, we could allow additional .gitmodules settings to be put in another ref (perhaps something like "refs/repository/config" to allow sharing additional repository-specific configuration in other files within the same tree --- e.g., branch descriptions). The semantics:
* If there is a gitmodules file in refs/repository/config in the
repository I clone, then the submodule settings from it are stored
locally somewhere that overrides .gitmodules. Perhaps
.git/info/<remotename>/gitmodules?
* Later fetches from the remote would also update this gitmodules
file.
* Settings from this gitmodules file can be overridden locally
using 'git config' until an explicit "git submodule sync" to
override the local configuration.
What do you think?
If two different remotes provide conflicting values for a setting in their gitmodules files, git would error out and ask the user to intervene with a tie-breaking "git config" setting.
Thanks, Jonathan