Subject: Re: RFC: Making submodules "track" branches

From: Johan Herland <[email-masked]>
Date: Tue, 08 Jun 2010 23:52:37 +0200

On Tuesday 08 June 2010, Jens Lehmann wrote:
> Am 08.06.2010 09:12, schrieb Johan Herland:
> > - When switching branches in the superrepo, you sometimes also want to
> > switch branches in the submodule. This is signalled by changing the
> > submodules.subthing.branch variable in .gitmodules between the two
> > branches. However, it means that the submodule's update/pull operation
> > must also be done on 'checkout' in the superrepo.
> 
> Hm, I always want the submodules to switch branches along with the super-
> project (I posted a RFC patch for that), but i can see other people don't
> want that at all or just for some submodules. But am I wrong assuming
> that it's either "switch branches in submodules too every time" or
> "never do that" for a single submodule?

Well, the good thing is that keeping this config/info in .gitmodules (which 
is versioned-controlled along with the rest of the project) enables you to 
choose one or the other, or anything in between. For example, given a 
submodule "foo", say I want to keep it on its "master" branch when the 
super-repo is on _its_ master branch. The .gitmodules file on the super-
repo's "master" branch would contain:

    [submodule "foo"]
        path = foo
        url = git://url/to/foo/upstream
        branch = master

Now, if I create a new branch "topic" in the super-repo, the submodule would 
by default keep on tracking its "master" branch. If I want to track another 
branch, called "subtopic", inside "foo", I change .gitmodules on my super-
repo's "topic" branch to say:

    [submodule "foo"]
        path = foo
        url = git://url/to/foo/upstream
        branch = subtopic

Finally, if I have a branch "release" in the super-repo, in which I want to 
pin submodule "foo" to a specific commit, I change .gitmodules on the super-
repo's "release" branch to say:

    [submodule "foo"]
        path = foo
        url = git://url/to/foo/upstream

(i.e. no branch tracking), and then record the appropriate submodule commit 
the "old-fashioned" way.

The good thing with Ævar's approach is that this is all configurable per 
branch (indeed, per commit[1]) by editing your .gitmodules file.

> > - When you track submodule branches instead of commits, the actual
> > commit referenced in the superrepo is no longer as important (provided
> > it's part of the ancestry of the submodule branch you're tracking).
> > However, diff/status will still list the submodule as changed because
> > you checked out a different commit from what Git has recorded. This
> > raises two concerns: (1) What _should_ be considered "changed" from
> > the diff/status perspective when tracking submodule branches? and (2)
> > When do you update the commit reference in the submodule? "never"
> > would work (since you're checking out a different commit anyway),
> > "always" would also work (for the same reason), but would litter the
> > superrepo history with submodule updates. There may be a better
> > alternative somewhere in between.
> 
> Don't record a commit in the first place, following a branch is not bound
> to a special commit, so pretending to do that might do more harm than
> good. Just putting the 0-hash there might be the solution.

Interesting. Will the object parsing machinery handle that without hiccups? 
What if an older Git version tries to checkout/update a submodule with a 0-
hash?

> > - If you want to give the illusion of "one big repo" then maybe it
> > should also be possible to trigger submodule commits from a superrepo
> > commit? (i.e. having a single toplevel "git commit" also trigger
> > commits in submodules). Some users will want to specify the commit
> > message for each submodule separately (IMHO the better approach),
> > while some will want to give only one commit message that is reused in
> > every submodule commit.
> 
> Hm, personally I am fine with first committing in the submodules and then
> in the superproject.

Me too, but I suspect that if you draw the "one big repo" approach to its 
logical conclusion, there will be some demand for recursive commits.

Have fun! :)

...Johan

[1]: Say your submodule usually tracks a branch, but you're creating some 
tag in the super-repo, and you want that tag to uniquely identify the 
submodule. You achieve this by making sure the tagged commit removes the 
relevant "branch = whatever" line from .gitmodules, and records the 
appropriate submodule version in the super-repo tree. Then, you can revert 
the .gitmodules change on the next commit to resume tracking the submodule 
branch.

Now, whenever you checkout the tag, you will always get the exact same 
version of the submodule, although the submodule otherwise tracks some 
branch.

-- 
Johan Herland, <[email-masked]>
www.herland.net