Subject: Re: [PATCH v2 2/3] Teach mv to move submodules using a gitfile

From: Junio C Hamano <[email-masked]>
Date: Thu, 11 Apr 2013 11:43:10 -0700

Ramkumar Ramachandra <[email-masked]> writes:

> Jens Lehmann wrote:
>> When moving a submodule which uses a gitfile to point to the git directory
>> stored in .git/modules/<name> of the superproject two changes must be made
>> to make the submodule work: the .git file and the core.worktree setting
>> must be adjusted to point from work tree to git directory and back.
>
> Isn't it untrue that the git directory is stored in
> .git/modules/<name>: it is stored in .git/modules/path/to/module.
>
> I thought the whole point of this complex scheme was to avoid name
> conflicts with submodules with the same name in other directories.

I think Jens is right on this one.  There are three things the code needs
to know about a submodule: its name, path and URL.

A canonical use case to think about is a project that builds an
appliance:

 * Its zero-th version only has the sources to the userspace for the
   appliance.

 * The first version adds the Linux kernel as a submodule bound at
   kernel/, taking it from git://k.org/linux-2.6.git/.

 * The second version adds a choice to build the appliance with the
   BSD kernel, and the project reorganizes the source tree to have
   Linux kernel at path linux/ and adds the bsd kernel at path bsd/.

 * By the time the third version is released, the URL to the Linux
   has migrated to git://k.org/linux.git/; it is still logically
   the same (i.e. continuation of) the old 2.6.git repository [*1*].

We would want to make it possible to "git checkout" smoothly between
these four versions.  Switching from v1 to v0 would have to remove
the submodule working tree at kernel/ but the user may want to
switch back to v1 without having to re-download the kernel
submodule, so the kernel/.git repository needs to be stashed away
somewhere.  Somewhere in $GIT_DIR of the superproject, but where?
Switching from v1 to v2 would need to move kernel/ to linux/ and
move kernel/.git to linux/.git.  The design choice made long time
ago (if you recall the collection of old threads I gave you some
time ago, this is what was called "Steven's three-level thing") was
to give a stable "logical" name for the Linux kernel component, so
that no matter where in the working tree the version that happens to
be at the tip of the current branch has it, we know where in the
superproject's .git/modules it is found.

So at the second version when we move the submodule that used to be
at kernel/ to linux/, we move the working tree of it, adjust the
"path" of the submodule, but keep the name.  And that name gives an
identity to the submodule, and that is what is used as a key inside
$GIT_DIR of the superproject to decide where the repository
(together with its object store) of the submodule is stashed away.

[Footnote]

*1* I mentioned the URL thing only for completeness; it does not
come into play in the "checkout" scenario, but when you start
thinking about remote interactions, you need to be aware of how that
value and the one copied to the configuration upon "submodule init"
need to be managed. Which is a separate topic but is an integral
part of the canonical example.

Ideally, a user who has followed along the life of this project
should:

 * first encounter git://k.org/linux-2.6.git/ in v1; "git submodule
   init" would copy it to her .git/config in the superproject.

 * later notice that .gitmodules has git://k.org/linux.git/ location
   that she hasn't seen for the submodule, and is given a chance to
   have the URL entry updated in her .git/config.

This is becuase even when she checks out an older branch that has
2.6 in .gitmodules, "git submodule update" _should_ go to the new
URL, not to the defunct 2.6 URL.  We do the "copy initially", but do
not do the latter "offer a chance to update when seeing a new one"
(at least, not yet).