Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Jakub Narebski <jnareb@xxxxxxxxx> writes:

>  * "prior" - heads that represent topic branch merges

This is not any different from usual "parent" at all (but you
have to think about it a bit to realize it).

Before talking about making a new commit object that links to
other related commits, let's first talk about what it means to
update the branch head ($GIT_DIR/refs/heads/<branch>) from
commit A to commit B.  Understanding what it means is more
fundamental.

A git "branch" points at the tip of one possible history of a
development.  As the often-used word "topic branch" tells you, a
"branch", i.e. that history, has a specific purpose.  The
purpose of my "master" branch is to give reasonably stable new
feature set and bugfixes, "next" to give testable ones, and "pu"
to collect remaining bits that are worthy of discussion.

When your branch head points at commit A and you update the head
to point at a different commit B, you are making this statement:

	The commit B suits the purpose of the branch better
	than the commit A.

Notice there may or may not be ancestry relation between these
two commits at this point of the discussion.  B may be a direct
child of commit A, a merge that has A as its first parent, a
merge that has A as its one of its parent (but not necessarily
the first), or a Nth-generation descendant if the update was a
fast forward merge from another branch.  It might even be an
ancestor if the update rewinds the history.

Among the above cases (and there may be others), in only two
cases you actually create a new commit to record that
statement [*1*].

The simplest case is when commit B is a direct, single-parent
child of commit A, and that statement is in your commit log
message.  "I started out from the commit A, and the result is
this tree.  The result suits what I am doing better than the
previous commit and I made the world a better place." -- the "I
started out from the commit A" part is on the parent header and
the rest is in the free-text.

When you are creating a merge of N parents, the principle is the
same.  Although in pure core-git terms all parents are equal, in
practice, the first parent has somewhat special meaning to you.
When the parents of commit B are A and X, you started out from
the commit A.  Then what are other parents?  You can read such a
commit this way:

	I started out from commit A and came up with this tree,
	which suits my purpose better.  While doing so, I have
	also considered what X has; and this result, commit B,
	suits my purpose better than X, too.

This is why a later merge with another branch that further
builds on top of X works so well.

    ----A----B
            /
       ----X----Y

If somebody built Y on X independently from us, when we merge
with Y, we say the merge base is X because B says "I've already
considered what X has" to do a 3-way merge.  While that is what
happens at the mechanical level, what is happening at the
philosophical level is we are taking "I consider that B is
better than X", part of the message seriously, which means "I
want to keep changes I made between X B".  Also the other person
who made Y made a similar statement that she considers Y is
better than X, and we try to preserve the changes between X and
Y in the automated part of the merge while preparing the tree to
commit the merge between B and Y.

Once you start reading the commit parent to mean " considering
what all of these commits have, what this new commit has suits
my purpose better", it becomes clear that the "previous" pointer
for a branch like my "pu" is just another "parent".

I rebuild "pu" from the tip of then-current "next", and merge
other topics in, and discard the previous "pu".  So it results
in this kind of graph:

                         o---o---o---o---o (updated "pu")
                        /   /   /   /  
        ---o---o---o---o
            \               \   \   \   \
             o---------------o---o---o---o (previous "pu")

But theoretically, I could include the previous "pu" tip as one
of the parents of the updated "pu" branch.

At the mechanical level, I start from then-current "next" and
merge each topic branch one-by-one on top of it.  But at the
philosophical level, what I am doing is to publish material that
shows a set of proposed changes that are more appropriate for
review by the curious than the previous round of "pu" head used
to have.  So the previous "pu" _is_ in the consideration while I
publish the updated "pu", although it is _not_ recorded anywhere.

After I come up with a fully merged tree, I could make a fake
Octopus that has the previous "pu" as its first parent and each
of the topic branch heads merged as second and subsequent
parents, with the resulting tree.  That would be more "honest"
at the philosophical level.

I am not going to actually suggest anybody doing this as a good
practice, but we can make such a commit with the current tool
like this:

        git checkout pu
	git tag -f prev-pu		;# remember where we were
	git reset --hard next		;# start at next
        git pull . topic-1		;# merge all remaining topics
        git pull . topic-2		;# ...
        git pull . topic-3
        ...
        git tag -f next-pu		;# this tree is what we want
        git reset --hard prev-pu	;# start from previous
        git pull --no-commit -s ours . next topic-1 topic-2 ...
	git read-tree -m -u next-pu	;# record a merge whose first
	git commit			;# parent is previous pu and
					;# has all the topics merged.
        

[Footnote]

*1* IOW, we _are_ losing some information by not recording the
fact that fast-forward was done while doing so.  

That record should _not_ be in the commit chain.  At the
mechanical level, recording that in the commit chain means two
criss-crossing branches never converge at the commit chain
level, which is already bad.  At the philosophical level, the
commit chain is a mesh of many possible "global" histories, and
the record that somebody (a particular branch in a particular
repository) was at what point in the mesh at given time does not
belong there.

But from the repository-owner's point of view, that _might_ be a
useful information to keep.  I am just saying this preemptively
so that if somebody wants to record it, that should not be
recorded in the commit object.


-
: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]