threads / discuss / 11782

--first-parent plus path limiting

Subject: --first-parent plus path limiting

## tl;dr

6 messages between Jan 29, 2008 and Jan 29, 2008.

replies: 5people: 2as markdown or json

Johannes Sixt· Jan 29, 2008, 08:29 UTC · lore

While trying to find out when builtin-fetch.c was merged into master, I noticed that this:

$ git log --first-parent --pretty=oneline -- builtin-fetch.c

lists b888d61c (Make fetch a builtin), which I did not expect. This one doesn't list it, as expected:

$ git log --first-parent --pretty=oneline
-- Hannes
Junio C Hamano· Jan 29, 2008, 08:47 UTC · re: Johannes Sixt · lore

Re: --first-parent plus path limiting

Johannes Sixt <j.sixt@viscovery.net> writes:
Show 6 quoted lines
> While trying to find out when builtin-fetch.c was merged into master, I
> noticed that this:
>
> $ git log --first-parent --pretty=oneline -- builtin-fetch.c
>
> lists b888d61c (Make fetch a builtin), which I did not expect.
Why didn't you?
> This one
> doesn't list it, as expected:
>
> $ git log --first-parent --pretty=oneline

Why did you expect that? This tells "follow only the first parent chain, ignoring all merges".

As most everything that is nontrivial is developed on a topic branch in git.git, "Make fetch a builtin" will not be on the first parent chain of the "master".

The former is about "First simplify the history with respect to builtin-fetch.c, and then follow the first-parent of the simplified history.

As the builtin-fetch topic was worked on for some time on its own topic, like this:

 ---o---o---o---...---o---A---M--- master
     \                       /
      o---o---X---...---o---B

So if a commit M has two parents A and B, and the file in M is the same as the file in B, the history simplifies commit A and the side branch that leads to it away. Perhaps commit A was the first parent and B was the last commit of the fetch-pack series, and "Make fetch a builtin" was an ancestor of B, like X above.

$ gitk b888d61c^..v1.5.4-rc5 -- builtin-fetch.c
is somewhat interesting to view.
Johannes Sixt· Jan 29, 2008, 09:05 UTC · re: Junio C Hamano · lore

Re: --first-parent plus path limiting

Junio C Hamano schrieb:
Show 10 quoted lines
> Johannes Sixt <j.sixt@viscovery.net> writes:
> 
>> While trying to find out when builtin-fetch.c was merged into master, I
>> noticed that this:
>>
>> $ git log --first-parent --pretty=oneline -- builtin-fetch.c
>>
>> lists b888d61c (Make fetch a builtin), which I did not expect.
> 
> Why didn't you?
Because ... [see below]
Show 7 quoted lines
>> This one
>> doesn't list it, as expected:
>>
>> $ git log --first-parent --pretty=oneline
> 
> Why did you expect that?  This tells "follow only the first
> parent chain, ignoring all merges".

With "as expected" I actually meant "as expected", not "contrary to expectations" ;) So, I did expect *not* to see the commit when the path is not limited.

> The former is about "First simplify the history with respect to
> builtin-fetch.c, and then follow the first-parent of the
> simplified history.

I was expecting that it works like "First follow the first-parent, and then simplify the history with respect to builtin-fetch.c." But that's certainly a matter of definition. In this case, I would have found my interpretation more useful, but then I don't use --first-parent that often...

Thanks for your clarifications, -- Hannes

Junio C Hamano· Jan 29, 2008, 09:11 UTC · re: Johannes Sixt · lore

Re: --first-parent plus path limiting

Johannes Sixt <j.sixt@viscovery.net> writes:
> I was expecting that it works like "First follow the first-parent, and
> then simplify the history with respect to builtin-fetch.c."

If you first follow the first-parent, the result will by definition not have any merges, so there is nothing left to simplify. History simplification is about merge removal, looking at all parents.

Removing commits from a single strand of pearls that do not touch the specified pathspecs is called "--dense" (which is on the default) and can be disabled with "--sparse".

So, no, it is not a matter of definition, as "first follow the first-parent then simplify" does not make much sense.

Johannes Sixt· Jan 29, 2008, 09:18 UTC · re: Junio C Hamano · lore

Re: --first-parent plus path limiting

Junio C Hamano schrieb:
Show 16 quoted lines
> Johannes Sixt <j.sixt@viscovery.net> writes:
> 
>> I was expecting that it works like "First follow the first-parent, and
>> then simplify the history with respect to builtin-fetch.c."
> 
> If you first follow the first-parent, the result will by
> definition not have any merges, so there is nothing left to
> simplify.  History simplification is about merge removal,
> looking at all parents.
> 
> Removing commits from a single strand of pearls that do not
> touch the specified pathspecs is called "--dense" (which is on
> the default) and can be disabled with "--sparse".
> 
> So, no, it is not a matter of definition, as "first follow the
> first-parent then simplify" does not make much sense.
OK.

Is there a combination of options that does --first-parent on the full history, but then --dense on the resulting strand of pearls with respect to a certain path?

-- Hannes
Junio C Hamano· Jan 29, 2008, 20:03 UTC · re: Johannes Sixt · lore

Re: --first-parent plus path limiting

Johannes Sixt <j.sixt@viscovery.net> writes:
> Is there a combination of options that does --first-parent on the full
> history, but then --dense on the resulting strand of pearls with respect
> to a certain path?

The way these features are combined in the revision walker is pretty much hardwired.

Marking commits that do not change the tree with respect to set of paths as irrelevant (i.e. REV_TREE_SAME) comes first, and the merge simplification happens about the same time. Following first-parent-chain only works on the result of that. If you tell a single-tree form of diff-tree to be applied to the resulting commit (i.e. give -p/--stat/--name-status and friends to "git log"), they work on the resulting commit with the same pathspec unless --full-diff is given.

	Side note: incidentally, this is why you do not get "git
	log $single_pathspec" to notice a file that matches the
	single pathspec was created by copying or renaming.

But there is a deeper issue between "first-parent" and the simplification (both merge history simplification and dense processing) with pathspec. They are based on quite different viewpoint to what the history is.

The first-parent view is about what was seen by who made merges. If you follow a branch that never fast-forwards (e.g. my "next" is that way) using --first-parent, you will see the evolution of the branch: "I merged updates to this topic, then I merged updates to that topic, etc." Even though there is no meaning to the concept of "branch" other than "a sticky label that moves around, mostly going forward, on a possible DAG of commits", it makes you pretend that one person and nobody else "owns" the branch and grows it, and ask only about what that one person did and saw. It is probably against the distributed nature of git history that fast-forward merge can happen anytime and there is no true mainline nor owner of the branch.

On the other hand, history simplification based on pathspecs is about what changed the area. It does not matter the feature was cooked in a side branch (which is a second class citizen in the world view "first-parent" takes) --- if "the mainline" did not touch that area and the changes to the area were merged from a side branch, the history on that side branch is much more interesting than the history of the mainline when you are inspecting the changes to the area specified by a set of paths. The philosophy is more natural to the distributed nature of git history.

These two inherently do not mesh well.

Having said that, culling with first-parent first and then applying pathspecs may have its own use. You will be asking this question:

    I do not care about the details of what other people did.
    Among the actions that was made to this branch of mine, find
    the ones that change the area.

This will not find the "Make fetch built-in" commit if you dig from 'master' (because that was not something that happened on "master"), but will find the merge to the "mainline" that touched the file.

← back to recent threads