# A question about git-rev-list

4 messages from 2007-07-16 to 2007-07-17. Participants: David Kastrup, Linus Torvalds, Junio C Hamano.
Thread: https://gitlist.dev/t/9056

## David Kastrup, 2007-07-16 08:55

Subject: A question about git-rev-list
Message-ID: <86wsx0wwvs.fsf@lola.quinscape.zz>
URL: https://gitlist.dev/e/86wsx0wwvs.fsf%40lola.quinscape.zz

```

Hi,

if I do

git-rev-list --remove-empty HEAD --not some-commit -- filename | tail -1

do I have any guarantee that the commit id I get (if any) is a direct
descendant of some-commit?  I _think_ --remove-empty might be
necessary for that option, but have no idea whether this hunch is
correct.  Do I need additional options like --topo-order, or is that
unnecessary?

Thanks,

-- 
David Kastrup

```

## Linus Torvalds, 2007-07-16 20:05

Subject: Re: A question about git-rev-list
Message-ID: <alpine.LFD.0.999.0707161258560.20061@woody.linux-foundation.org>
URL: https://gitlist.dev/e/alpine.LFD.0.999.0707161258560.20061%40woody.linux-foundation.org
In-Reply-To: <86wsx0wwvs.fsf@lola.quinscape.zz>

```


On Mon, 16 Jul 2007, David Kastrup wrote:
> 
> if I do
> 
> git-rev-list --remove-empty HEAD --not some-commit -- filename | tail -1
> 
> do I have any guarantee that the commit id I get (if any) is a direct
> descendant of some-commit?

No. You get the guarantee that

 - it's some kind of parent of HEAD
 - it's *not* a parent of some-commit

But the trivial case is a simple history like

	 /-B-\
	A     D
         \-C-/

(where "A" is the root commit, and "D" is the current HEAD, and there are 
two development lines from A to  D).

If you now do

	git-rev-list HEAD --not C

you would generally see B on the list of commits, even though it's 
obviously not a direct descendant of C.

No amount of flags will change that. Of course, B might not show up 
for _other_ reasons (ie simply because it doesn't change "filename" at 
all), but generally you must always think of git-rev-list (and git log) as 
a _set_ operation.

There are no git operations that will look for "chain of commits from C to 
D" if that is what you want. No such chain necessarily even exists, and 
quite often it is ambiguous when it *does* exist (ie there is not a single 
chain from A to D, there are two chains).

You could add some kind of function that looks for the "shortest chain of 
commits from X to Y", but that would really be something fundamentally 
different from what git-rev-list gives you.

			Linus

```

## David Kastrup, 2007-07-16 21:16

Subject: Re: A question about git-rev-list
Message-ID: <85bqecm4mn.fsf@lola.goethe.zz>
URL: https://gitlist.dev/e/85bqecm4mn.fsf%40lola.goethe.zz
In-Reply-To: <alpine.LFD.0.999.0707161258560.20061@woody.linux-foundation.org>

```
Linus Torvalds <torvalds@linux-foundation.org> writes:

> On Mon, 16 Jul 2007, David Kastrup wrote:
>> 
>> if I do
>> 
>> git-rev-list --remove-empty HEAD --not some-commit -- filename | tail -1
>> 
>> do I have any guarantee that the commit id I get (if any) is a direct
>> descendant of some-commit?
>
> No. You get the guarantee that
>
>  - it's some kind of parent of HEAD
>  - it's *not* a parent of some-commit
>
> But the trivial case is a simple history like
>
> 	 /-B-\
> 	A     D
>        \-C-/
>
> (where "A" is the root commit, and "D" is the current HEAD, and there are 
> two development lines from A to  D).
>
> If you now do
>
> 	git-rev-list HEAD --not C
>
> you would generally see B on the list of commits, even though it's 
> obviously not a direct descendant of C.

Ok, thanks.  As explained in a different posting, I try to tackle this
now with the equivalent of

git-rev-list HEAD --parents --not B -- somefile.c | awk '/ B/{print $1}'

This will give me one descendant if there is one.  The problem I have
with that is that "somefile.c" renders commits uninteresting, but
not if they have interesting parents (what do their parents have to do
with it?).  So if I have

A -> B -> B1 -> C -> HEAD

where somefile.c does not change between B and B1, then
git-rev-list HEAD --not B -- somefile.c
spews out
HEAD
C
and that's it.  Quite as expected.  However, 
git-rev-list HEAD --not B --parents -- somefile.c
spews out
HEAD C
C B1
B1 B

and look and behold, B1 became interesting because of its unlisted
parent B.

There is something wrong with that.

-- 
David Kastrup, Kriemhildstr. 15, 44793 Bochum

```

## Junio C Hamano, 2007-07-17 04:33

Subject: Re: A question about git-rev-list
Message-ID: <7v8x9fbqdu.fsf@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7v8x9fbqdu.fsf%40assigned-by-dhcp.cox.net
In-Reply-To: <85bqecm4mn.fsf@lola.goethe.zz>

```
David Kastrup <dak@gnu.org> writes:

> ...  The problem I have
> with that is that "somefile.c" renders commits uninteresting, but
> not if they have interesting parents (what do their parents have to do
> with it?).  So if I have
>
> A -> B -> B1 -> C -> HEAD
>
> where somefile.c does not change between B and B1, then
> git-rev-list HEAD --not B -- somefile.c
> spews out
> HEAD
> C
> and that's it.  Quite as expected.  However, 
> git-rev-list HEAD --not B --parents -- somefile.c
> spews out
> HEAD C
> C B1
> B1 B
>
> and look and behold, B1 became interesting because of its unlisted
> parent B.
>
> There is something wrong with that.

There indeed is, and that is not what I am seeing.

Running this script in an empty directory gives me:

    #!/bin/sh

    GIT_AUTHOR_NAME='A U Thor'
    GIT_AUTHOR_EMAIL=a.u.thor@example.xz
    GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"
    GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"
    GIT_AUTHOR_DATE='2007-07-16 00:00:00 +0000'
    GIT_COMMITTER_DATE='2007-07-16 00:00:00 +0000'

    export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL \
            GIT_AUTHOR_DATE GIT_COMMITTER_DATE

    rm -fr .git
    git init
    echo A >somefile.c; git add somefile.c; git commit -m 'A'; git tag A
    echo B >somefile.c; git add somefile.c; git commit -m 'B'; git tag B
    echo B1 >another; git add another; git commit -m 'B1'; git tag B1
    echo C >somefile.c; git add somefile.c; git commit -m 'C'; git tag C
    echo H >somefile.c; git add somefile.c; git commit -m 'H'; git tag H

    git rev-list --parents HEAD --not B -- somefile.c |
    git name-rev --tags --stdin

$ sh t000.sh
Initialized empty Git repository in .git/
Created initial commit 7a13cf5: A
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 somefile.c
Created commit b66d40b: B
 1 files changed, 1 insertions(+), 1 deletions(-)
Created commit 5530c91: B1
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 another
Created commit 7ee2b7e: C
 1 files changed, 1 insertions(+), 1 deletions(-)
Created commit 71fafc0: H
 1 files changed, 1 insertions(+), 1 deletions(-)
71fafc0f49ffb82b123c09ec0857f9f458ed32c4 (tags/H) 7ee2b7ed072190c56a2eedda3130f6bb729d0da1 (tags/C)
7ee2b7ed072190c56a2eedda3130f6bb729d0da1 (tags/C) b66d40bd7ed6d7403c16d8e37e6e410852598247 (tags/B)


The commit listed are H and then C; their (rewritten) parents
are C and B, respectively.

```
