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.
next prev 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