Git development
 help / color / mirror / Atom feed
From: Martin Atukunda <matlads@dsmagic.com>
To: git@vger.kernel.org
Subject: Re: Notes on Subproject Support
Date: Mon, 23 Jan 2006 15:50:13 +0300	[thread overview]
Message-ID: <20060123125013.GA4472@igloo.ds.co.ug> (raw)
In-Reply-To: <7v3bjfafql.fsf@assigned-by-dhcp.cox.net>

This proposal doesn't seem to cator for the event when a directory is
renamed or moved to a different location, or am I missing something?

- Martin -
On Sun, Jan 22, 2006 at 05:35:14PM -0800, Junio C Hamano wrote:
> This is still a draft/WIP, but "release early" is a good
> discipline, so...
> 
> -- >8 --
> 
> Notes on Subproject Support
> ===========================
> Junio C Hamano <junkio@cox.net>
> v1.0 January 22, 2006
> 
> Scenario
> --------
> 
> The examples in the following discussion show how this proposal
> plans to help this:
> 
> . A project to build an embedded Linux appliance "gadget" is
>   maintained with git.
> 
> . The project uses linux-2.6 kernel as its subcomponent.  It
>   starts from a particular version of the mainline kernel, but
>   adds its own code and build infrastructure to fit the
>   appliance's needs.
> 
> . The working tree of the project is laid out this way:
> +
> ------------
>  Makefile       - Builds the whole thing.
>  linux-2.6/     - The kernel, perhaps modified for the project.
>  appliance/     - Applications that run on the appliance, and
>                   other bits.
> ------------
> 
> . The project is willing to maintain its own changes out of tree
>   of the Linux kernel project, but would want to be able to feed
>   the changes upstream, and incorporate upstream changes to its
>   own tree, taking advantage of the fact that both itself and
>   the Linux kernel project are version controlled with git.
> 
> The idea here is to:
> 
> . Keep `linux-2.6/` part as an independent project.  The work by
>   the project on the kernel part can be naturally exchanged with
>   the other kernel developers this way.  Specifically, a tree
>   object contained in commit objects belonging to this project
>   does *not* have linux-2.6/ directory at the top.
> 
> . Keep the `appliance/` part as another independent project.
>   Applications are supposed to be more or less independent from
>   the kernel version, but some other bits might be tied to a
>   specific kernel version.  Again, a tree object contained in
>   commit objects belonging to this project does *not* have
>   appliance/ directory at the top.
> 
> . Have another project that combines the whole thing together,
>   so that the project can keep track of which versions of the
>   parts are built together.
> 
> We will call the project that binds things together the
> 'toplevel project'.  Other projects that hold `linux-2.6/` part
> and `appliance/` part are called 'subprojects'.
> 
> Notice that `Makefile` at the top is part of the toplevel
> project in this example, but it is not necessary.  We could
> instead have the appliance subproject include this file.  In
> such a setup, the appliance subproject would have had `Makefile`
> and `appliance/` directory at the toplevel.
> 
> 
> Setting up
> ----------
> 
> Let's say we have been working on the appliance software,
> independently version controlled with git.  Also the kernel part
> has been version controlled separately, like this:
> ------------
> $ ls -dF current/*/.git current/*
> current/Makefile    current/appliance/.git/  current/linux-2.6/.git/
> current/appliance/  current/linux-2.6/
> ------------
> 
> Now we would want to get a combined project.  First we would
> clone from these repositories (which is not strictly needed --
> we could use `$GIT_ALTERNATE_OBJECT_DIRECTORIES` instead):
> 
> ------------
> $ mkdir combined && cd combined
> $ cp ../current/Makefile .
> $ git init-db
> $ mkdir -p .git/refs/subs/{kernel,gadget}/{heads,tags}
> $ git clone-pack ../current/linux-2.6/ master | read kernel_commit junk
> $ git clone-pack ../current/appliance/ master | read gadget_commit junk
> ------------
> 
> We will introduce a new command to set up a combined project:
> 
> ------------
> $ git bind-projects \
> 	$kernel_commit linux-2.6/ \
> 	$gadget_commit appliance/
> ------------
> 
> This would do an equivalent of:
> 
> ------------
> $ git read-tree --prefix=linux-2.6/ $kernel_commit
> $ git read-tree --prefix=appliance/ $gadget_commit
> ------------
> [NOTE]
> ============
> Earlier outlines sent to the git mailing list talked
> about `$GIT_DIR/bind` to record what subproject are bound to
> which subtree in the curent working tree and index.  This
> proposal instead records that information in the index file
> when `--prefix=linux-2.6/` is given to `read-tree`.
> 
> Also note that in this round of proposal, there is no separate
> branches that keep track of heads of subprojects.
> ============
> 
> Let's not forget to add the `Makefile`, and check the whole
> thing out from the index file.
> ------------
> $ git add Makefile
> $ git checkout-index -f -u -q -a
> ------------
> 
> Now our directory should be identical with the `current`
> directory.  After making sure of that, we should be able to
> commit the whole thing:
> 
> ------------
> $ diff -x .git -r ../current ../combined
> $ git commit -m 'Initial toplevel project commit'
> ------------
> 
> Which should create a new commit object that records what is in
> the index file as its tree, with `bind` lines to record which
> subproject commit objects are bound at what subdirectory, and
> updates the `$GIT_DIR/refs/heads/master`.  Such a commit object
> might look like this:
> ------------
> tree 04803b09c300c8325258ccf2744115acc4c57067
> bind 5b2bcc7b2d546c636f79490655b3347acc91d17f linux-2.6/
> bind 0bdd79af62e8621359af08f0afca0ce977348ac7 appliance/
> author Junio C Hamano <junio@kernel.org> 1137965565 -0800
> committer Junio C Hamano <junio@kernel.org> 1137965565 -0800
> 
> Initial toplevel project commit
> ------------
> 
> 
> Making further commits
> ----------------------
> 
> The easiest case is when you updated the Makefile without
> changing anything in the subprojects.  In such a case, we just
> need to create a new commmit object that records the new tree
> with the current `HEAD` as its parent, and with the same set of
> `bind` lines.
> 
> When we have changes to the subproject part, we would make a
> separate commit to the subproject part and then record the whole
> thing by making a commit to the toplevel project.  The user
> interaction might go this way:
> ------------
> $ git commit
> error: you have changes to the subproject bound at linux-2.6/.
> $ git commit --subproject linux-2.6/
> $ git commit
> ------------
> 
> With the new `--subproject` option, the directory structure
> rooted at `linux-2.6/` part is written out as a tree, and a new
> commit object that records that tree object with the commit
> bound to that portion of the tree (`5b2bcc7b` in the above
> example) as its parent is created.  Then the final `git commit`
> would record the whole tree with updated `bind` line for the
> `linux-2.6/` part.
> 
> 
> Checking out
> ------------
> 
> After cloning such a toplevel project, `git clone` without `-n`
> option would check out the working tree.  This is done by
> reading the tree object recorded in the commit object (which
> records the whole thing), and adding the information from the
> "bind" line to the index file.
> 
> ------------
> $ cd ..
> $ git clone -n combined cloned ;# clone the one we created earlier
> $ cd cloned
> $ git checkout
> ------------
> 
> This round of proposal does not maintain separate branch heads
> for subprojects.  The bound commits and their subdirectories
> are recorded in the index file from the commit object, so there
> is no need to do anything other than updating the index and the
> working tree.
> 
> 
> Switching branches
> ------------------
> 
> Along with the traditional two-way merge by `read-tree -m -u`,
> we would need to look at:
> 
> . `bind` lines in the current `HEAD` commit.
> 
> . `bind` lines in the commit we are switching to.
> 
> . subproject binding information in the index file.
> 
> to make sure we do sensible things.
> 
> Just like until very recently we did not allow switching
> branches when two-way merge would lose local changes, we can
> start by refusing to switch branches when the subprojects bound
> in the index do not match what is recorded in the `HEAD` commit.
> 
> Because in this round of the proposal we do not use the
> `$GIT_DIR/bind` file nor separate branches to keep track of
> heads of the subprojects, there is nothing else other than the
> working tree and the index file that needs to be updated when
> switching branches.
> 
> 
> Merging
> -------
> 
> Merging two branches of the toplevel projects can use the
> traditional merging mechanism mostly unchanged.  The merge base
> computation can be done using the `parent` ancestry information
> taken from the two toplevel project branch heads being merged,
> and merging of the whole tree can be done with a three-way merge
> of the whole tree using the merge base and two head commits.
> For reasons described later, we would not merge the subproject
> parts of the trees during this step, though.
> 
> When the two branch heads use different versions of subproject,
> things get a bit tricky.  First, let's forget for a moment about
> the case where they bind the same project at different location.
> We would refuse if they do not have the same number of `bind`
> lines that bind something at the same subdirectories.
> 
> ------------
> $ git merge 'Merge in a side branch' HEAD side
> error: the merged heads have subprojects bound at different places.
>  ours:
> 	linux-2.6/
> 	appliance/
>  theirs:
> 	kernel/
> 	gadget/
> 	manual/
> ------------
> 
> Such renaming can be handled by first moving the bind points in
> our branch, and redoing the merge (this is a rare operation
> anyway).  It might go like this:
> 
> ------------
> $ git bind-projects \
> 	$kernel_commit kernel/ \
> 	$gadget_commit gadget/
> $ git commit -m 'Prepare for merge with side branch'
> $ git merge 'Merge in a side branch' HEAD side
> error: the merged heads have subprojects bound at different places.
>  ours:
> 	kernel/
> 	gadget/
>  theirs:
> 	kernel/
> 	gadget/
> 	manual/
> ------------
> 
> Their branch added another subproject, so this did not work (or
> it could be the other way around -- we might have been the one
> with `manual/` subproject while they didn't).  This suggests
> that we may want an option to `git merge` to allow taking a
> union of subprojects.  Again, this is a rare operation, and
> always taking a union would have created a toplevel project that
> had both `kernel/` and `linux-2.6/` bound to the same Linux
> kernel project from possibly different vintage, so it would be
> prudent to require the set of bound subprojects to exactly match
> and give the user an option to take a union.
> 
> ------------
> $ git merge --union-subprojects 'Merge in a side branch HEAD side
> error: the subproject at `kernel/` needs to be merged first.
> ------------
> 
> Here, the version of the Linux kernel project in the `side`
> branch was different from what our branch had on our `bind`
> line.  On what kind of difference should we give this error?
> Initially, I think we could require one is the fast forward of
> the other (ours might be ahead of theirs, or the other way
> around), and take the descendant.
> 
> Or we could do an independent merge of subprojects heads, using
> the `parent` ancestry of the bound subproject heads to find
> their merge-base and doing a three-way merge.  This would leave
> the merge result in the subproject part of the working tree and
> the index.
> 
> [NOTE]
> This is the reason we did not do the whole-tree three way merge
> earlier.  The subproject commit bound to the merge base commit
> used for the toplevel project may not be the merge base between
> the subproject commits bound to the two toplevel project
> commits.
> 
> So let's deal with the case to merge only a subproject part into
> our tree first.
> 
> 
> Merging subprojects
> -------------------
> 
> An operation of more practical importance is to be able to merge
> in changes done outside to the projects bound to our toplevel
> project.
> 
> ------------
> $ git pull --subproject=kernel/ git://git.kernel.org/.../linux-2.6/
> ------------
> 
> might do:
> 
> . fetch the current `HEAD` commit from Linus.
> . find the subproject commit bound at kernel/ subtree.
> . perform the usual three-way merge of these two commits, in
>   `kernel/` part of the working tree.
> 
> After that, `git commit \--subproject` option would be needed to
> make a commit.
> 
> [NOTE]
> This suggests that we would need to have something similar to
> `MERGE_HEAD` for merging the subproject part.
> 
> 
> -
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
Due to a shortage of devoted followers, the production of great leaders has been discontinued.

  parent reply	other threads:[~2006-01-23 12:50 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-01-23  1:35 Notes on Subproject Support Junio C Hamano
2006-01-23  3:50 ` Daniel Barkalow
2006-01-23  4:36   ` Junio C Hamano
2006-01-23  5:48     ` Junio C Hamano
2006-01-23  6:06       ` Alexander Litvinov
2006-01-23 16:48         ` Daniel Barkalow
2006-01-23  8:38       ` Junio C Hamano
2006-01-23 17:57       ` Daniel Barkalow
2006-01-24  1:50         ` Junio C Hamano
2006-01-23 16:31     ` Daniel Barkalow
2006-01-24  1:50       ` Junio C Hamano
2006-01-24  4:22         ` Daniel Barkalow
2006-01-23  8:00 ` Junio C Hamano
2006-01-23 12:50 ` Martin Atukunda [this message]
2006-01-23 19:30   ` Junio C Hamano
2006-01-28  4:55 ` Horst von Brand
2006-01-28 21:43   ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20060123125013.GA4472@igloo.ds.co.ug \
    --to=matlads@dsmagic.com \
    --cc=git@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox