Re: [PATCH] tag: add -i and --introduced modifier for --contains

4 messages, 4 authors, 2016-06-15 · open the first message on its own page

Re: [PATCH] tag: add -i and --introduced modifier for --contains

From: Junio C Hamano <hidden>
Date: 2016-06-15 23:00:43

"Luis R. Rodriguez" [off-list ref] writes:
quoted
And between v3.4 and v3.5-rc1, the latter is a closer anchor point
for that commit (v3.5-rc1 only needs about 200 hops to reach the
commit, while from v3.4 you would need close to 500 hops),
Ah! Thanks for explaining this mysterious puzzle to me. I'm a bit
perplexed why still. Can I trouble you for a little elaboration here?
How could one view from a commit merged on v3.4 possibly yield more
commits to v3.4 than to v3.5 ? Is it because it starts counting on the
merge's parent (v3.3) ?
The reason is very simple, once you realize that in a distributed
environment it is very common to fork off a new branch from an
ancient commit and then merging the result to a newer release
without merging it all the way down to older maintenance releases.

Try this sequence:

    1. start from say v3.4~1^2~2
    $ git checkout -b side v3.4~1^2~2

The history near v3.4 proper looks like this:

    $ git log --oneline -3 v3.4
    76e10d1 Linux 3.4
    d6c77973 Merge tag 'parisc-fixes' of git://git.kernel.o...
    5d12045 Merge branch 'x86/ld-fix' of git://git.kernel.o...

and the last merge before v3.4 brings three commits in to the
history:

    $ git log --oneline d6c77973^1..d6c77973^2
    b3cb867 [PARISC] fix panic on prefetch(NULL) on PA7300LC
    207f583 [PARISC] fix crash in flush_icache_page_asm on PA1.1
    5e18558 [PARISC] fix PA1.1 oops on boot

We just forked a new "side" branch off of the bottom one (5e18558).

    2. pretend a new development on this old codebase
    $ git commit --allow-empty -m "[PARISC] another"

    3. let's merge this to v3.5 and call the result v9.0
    $ git checkout v3.5
    $ git merge --no-edit side
    $ git tag -a -m 'Nine' v9.0

Think what just happened to v3.4~1^2~2, the fork-point of this new
side branch (I am not asking what *should* happen. This exercise is
only to illustrate how the commit v3.5-rc1~120^3~76^2 can be closer
to v3.5-rc1 than to v3.4 when it is reachable from both).

Here is how the topology looks like:

                   v3.4                  v9.0
             ---M---X---------------------Y
               /                         /
   ---A---B---C                         /
       \                               / 
        ------------------------------D (side)

where X is v3.4, M is d6c77973, A thru C are the PARISC patches,
D is the "another", and Y is the phoney version Nine we just made.
We are trying to "describe --contains" commit A.

If you start counting from the new tag v9.0, it is on the merged
side branch that brought in one new commit D, and in fact it is the
direct parent of it, so even without asking "describe --contains",
we know that it is v9.0^2~1.  That is 2 hops from v9.0 tag.  If you
count from v3.4, it is 4 hops.

And both of these tags X and Y contain the commit A.

Now, as to what *SHOULD* happen, I think the above exercise shows us
a way to define what the desired semantics is, without resorting to
heuristics (e.g. "which tag has older timestamp?" or "which tag's
name sorts older under Linux version naming convention?").

Commit A can be described in terms of both v3.4 and v9.0, and it may
be closer to v9.0 than v3.4, and under that definition "we pick the
closest tag", the current "describe --contains" behaviour may be
correct, but from the human point of view, it is *WRONG*.

It is wrong because v9.0 can reach v3.4.  So perhaps the rule should
be updated to do something like:

    - find candidate tags that can be used to "describe --contains"
      the commit A, yielding v3.4, v3.5 (not shown), and v9.0;

    - among the candidate tags, cull the ones that contain another
      candidate tag, rejecting v3.5 (not shown) and v9.0;

    - among the surviving tags, pick the closest.

Hmm?

Re: [PATCH] tag: add -i and --introduced modifier for --contains

From: Jeff King <hidden>
Date: 2016-06-15 23:00:44

On Thu, Apr 17, 2014 at 10:04:52AM -0700, Junio C Hamano wrote:
Commit A can be described in terms of both v3.4 and v9.0, and it may
be closer to v9.0 than v3.4, and under that definition "we pick the
closest tag", the current "describe --contains" behaviour may be
correct, but from the human point of view, it is *WRONG*.

It is wrong because v9.0 can reach v3.4.  So perhaps the rule should
be updated to do something like:

    - find candidate tags that can be used to "describe --contains"
      the commit A, yielding v3.4, v3.5 (not shown), and v9.0;

    - among the candidate tags, cull the ones that contain another
      candidate tag, rejecting v3.5 (not shown) and v9.0;

    - among the surviving tags, pick the closest.

Hmm?
Interesting.  I think that would cover some cases, but there are others
in which the tags are not direct descendants. For example, imagine you
have both a "master" and a "maint" branch. You fork a topic from an old
commit that both branches contain, and then independently merge the
topic to each branch. You then cut a release for each. So your graph
might look like:

 ---A---B---C-----D---E---F (maint, v3.4)
     \   \       /
      \   ---G-----H---I (master, v4.0)
       \       /  /
        ------J---

The fix is J, and it got merged up to maint at D, and to master at H.
v4.0 does not contain v3.4. What's the best description of J?

By the rules above, we hit the third rule "pick the closest". Which
means we choose v3.4 or v4.0 based solely on how many commits are
between the topic's merge and the tag release. Which has nothing at all
to do with the topic itself.

In this case we'd show v4.0 (because "J-H-I" is shorter than "J-D-E-F").
But I suspect most users would want to know v3.4, because they want to
know the "oldest" release they can move up to that contains the commit.
But that notion of oldness is not conveyed by the graph above; it's only
an artifact of the tag names.

So you can solve this by actually representing the relationship with a
merge. IOW, by merging v3.4 into v4.0 to say "yes, v4.0 is a superset".
And that's generally what we do in git.git, merging maint into master
periodically. But I imagine there are other possible workflows where
people do not do that "merge up", and the maint and master branches
diverge (and maybe they even cherry-pick from each other, but sometimes
merge if the fix can be based on a common ancestor, as in this case).

-Peff

Re: [PATCH] tag: add -i and --introduced modifier for --contains

From: Luis R. Rodriguez <hidden>
Date: 2016-06-15 23:00:44

On Thu, Apr 17, 2014 at 10:04 AM, Junio C Hamano [off-list ref] wrote:
"Luis R. Rodriguez" [off-list ref] writes:
quoted
quoted
And between v3.4 and v3.5-rc1, the latter is a closer anchor point
for that commit (v3.5-rc1 only needs about 200 hops to reach the
commit, while from v3.4 you would need close to 500 hops),
Ah! Thanks for explaining this mysterious puzzle to me. I'm a bit
perplexed why still. Can I trouble you for a little elaboration here?
< Junio gives a great huge example>

Phew! Thanks for the elaborate explanation, this makes perfect sense now!
Now, as to what *SHOULD* happen, I think the above exercise shows us
a way to define what the desired semantics is, without resorting to
heuristics (e.g. "which tag has older timestamp?" or "which tag's
name sorts older under Linux version naming convention?").
I think ultimately this reveals that given that tags *can* be
arbitrary and subjective, and given that clocks can also pretty much
arbitrary 'git describe --contains' can and probably only should do
best effort (TM) and perhaps one thing to help is documenting this
issue well and provide a set of best practices that are supported for
tagging schemes. I can't describe how many libraries I've reviewed
about software versioning schemes and most of them support a huge
array of things, and funny enough the Linux versioning scheme, was not
supported well, for something so simple as versioning sort. This is
ultimately why I had to implement my own sort solution on rel-html. If
we agree on this we could just for example take on the Linux
versioning scheme as an emum and document that well both on code and a
wiki. More on this below.

With regards to timestamps: care must be taken given that we'd be
assuming that clocks are synchronized, this can likely yield incorrect
results on a distributed development environment with different time
zones, and it can also be easily cheated, which is why I was concerned
over using timestamps. Its still certainly something that can be
considered, but I've heard enough rants of a few maintainers about
crazy dates on patches which makes me believe this could actually be
an issue, specially if we speed up development and need higher degree
of resolution.

I know the above example but its perhaps worth mentioning how Linux
does not follow the above development model for merging stable fixes
or changes though, but it does not prevent folks from branching off of
older tags to do development which Linux will then pull. In Ingo's
case the issue then points then I think to another mild issue -- the
commit was developed on a v3.3 based tag, which is why 'git describe
--first-parent c5905afb' yields v3.3-rc1-41-gc5905af and not v3.4,
which *can also* be a bit perplexing if one does not understand the
above example you provided can be used for a development work flow for
code sent out to Linus. That said then, since we don't follow the
model you laid out it still reveals another issue, and I am not yet
sure I still understand why --contains yields a v3.5 tag in that case
since we ensured commits on v3.5 were already piled up on older
releases, or were being introduced newly on its own release. It smells
to me that the commit's first parent (which can be anything) is used
somehow here as a shortcut ?

This doesn't mean we can't use the work flow above for merging changes
from say a v3.4.x onto a v3.5 -- but we don't -- and perhaps as part
of the documentation about a scheme for Linux, we should advise
against such practices. In any case the closest thing I see we can use
upstream on Linux is 'git cherry-pick -x <commit-id>' but Greg doesn't
seem to use this and instead appends the commit with the respective
commit ID of the upstream gitsum. Both strategies yield different
commit IDs anyway, so neither practice should interrupt the 'git
describe --contains' practice. In the stable branches to find out when
a commit was introduced one would not rely on the commit ID on the
stable branch but instead of the commit ID of the 'upstream
reference'.
Commit A can be described in terms of both v3.4 and v9.0,
And in the real example case, why *would* c5905afb' be be described in
terms of v3.5 instead of v3.4 ?
and it may
be closer to v9.0 than v3.4, and under that definition "we pick the
closest tag", the current "describe --contains" behaviour may be
correct, but from the human point of view, it is *WRONG*.
Yeap, if a development work flow does not follow a strict pattern
(maybe a .git/config variable?) perhaps 'git describe --contains'
should spit out a the few tags it does have?
It is wrong because v9.0 can reach v3.4.  So perhaps the rule should
be updated to do something like:

    - find candidate tags that can be used to "describe --contains"
      the commit A, yielding v3.4, v3.5 (not shown), and v9.0;
Sure.
    - among the candidate tags, cull the ones that contain another
      candidate tag, rejecting v3.5 (not shown) and v9.0;
Sounds good to me but that seems to stick the output to a scheme, ie,
would it support schemes without a v prefix for tags? In other words,
perhaps do this only for Linux scheme?
    - among the surviving tags, pick the closest.

Hmm?
Sounds good to me!

  Luis

Re: [PATCH] tag: add -i and --introduced modifier for --contains

From: Jan Kara <jack@suse.cz>
Date: 2016-06-15 23:00:46

On Thu 17-04-14 10:04:52, Junio C Hamano wrote:
So perhaps the rule should be updated to do something like:

    - find candidate tags that can be used to "describe --contains"
      the commit A, yielding v3.4, v3.5 (not shown), and v9.0;

    - among the candidate tags, cull the ones that contain another
      candidate tag, rejecting v3.5 (not shown) and v9.0;

    - among the surviving tags, pick the closest.
  I guess all parties agree with the first two points (and actually I would
prefer not to assume anything about tag names and consider v3.4-rc1 as good
as v3.4). Regarding the strategy what to select when there are several
remaining tags after first two steps I would prefer to output all such
tags. As people have mentioned in this thread it varies a lot between
projects what people want to see (and in some cases I can imagine people
really *want* to see all the tags). So printing all such tags would let
them select the desired tag with grep or some more elaborate scripting...
Just a thought.

								Honza
-- 
Jan Kara [off-list ref]
SUSE Labs, CR
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help