Given the history
X-Y <- feature
/
A-B-C-D-E <- master
I want to get the descendants of a given commit. One solution seems to be:
git log --all --ancestry-path <ref>^!
However, the behaviour is a bit strange:
<rev>
is C
, the result is CDEXY
<rev>
is D
or X
, the result is DEXY
(weird!)<rev>
is E
, the result is E
My understanding is that the command does not get all children of <rev>
; instead, it gets all children of parent-of(ref). Am I right?
This is unintuitive, error prone, and, quite frankly, irritating. How command should I run instead, in order to limit the log to the descendants of a given commit.
By Amount. The most basic filtering option for git log is to limit the number of commits that are displayed. When you're only interested in the last few commits, this saves you the trouble of viewing all the commits in a page. You can limit git log 's output by including the - option.
The git log command displays all of the commits in a repository's history.
Find what file changed in a commit To find out which files changed in a given commit, use the git log --raw command. It's the fastest and simplest way to get insight into which files a commit affects.
By default git diff will show you any uncommitted changes since the last commit.
As far as I know, there is no built-in Git command to do that. However, you're almost there. Try
git log --all --ancestry-path ^<rev>
instead. That should limit the log to the descendants of <rev>
; note that, strictly speaking, <rev>
is not a child of itself, so it doesn't get listed.
For instance, in my toy repo (I replicated yours; see the bottom of my answer),
git log --all --ancestry-path ^D
limits the log to commit E
, and
git log --all --ancestry-path ^X
limits the log to commit Y
.
git log --all --ancestry-path D^!
?My understanding is that the command does not get all children of
<rev>
; instead, it gets all children of parent-of(ref). Am I right?
Yes; your bottom commit is off by one.
Because, in your example, commits D
and X
are symmetric, let's just focus on commit D
and deconstruct the command
git log --all --ancestry-path D^!
According to the relevant Git man page,
A suffix
^
followed by an exclamation mark is the same as giving commit<rev>
and then all its parents prefixed with^
to exclude them (and their ancestors).
Furthermore, according to the git-log
man page,
--all
Pretend as if all the refs in refs/ are listed on the command line as
<commit>
.
Therefore, in your case
git log --all --ancestry-path D^!
is equivalent to
git log --ancestry-path D ^C feature master
Moreover, because D
is reachable from master
, the latter command reduces to
git log --ancestry-path ^C feature master
This gives a log of all the commits reachable from either feature
or master, but excluding C
or any of its ancestors, and you get commits D
, E
, X
, and Y
.
As you can see, your bottom commit is off by one. What you really want to run
git log --ancestry-path ^D feature master
which is the same as
git log --all --ancestry-path ^D
The following commands recreate your toy repo:
$ mkdir gittest
$ cd gittest/
$ git init
$ printf "A\n" > README
$ git add README
$ git commit -m "A"
$ printf "B\n" >> README
$ git commit -am "B"
$ printf "C\n" >> README
$ git commit -am "C"
$ git branch feature
$ printf "D\n" >> README
$ git commit -am "D"
$ printf "E\n" >> README
$ git commit -am "E"
$ git checkout feature
$ printf "X\n" >> README
$ git commit -am "X"
$ printf "Y\n" >> README
$ git commit -am "Y"
$ git log --all --oneline --graph --decorate
* e234427 (HEAD -> feature) Y
* cf98c6b X
| * b3d493a (master) E
| * e2bb266 D
|/
* dfe0267 C
* 0be7d42 B
* 674356e A
(Note that commits D
and X
can be referred to by their SHAs, or more simply, by master~
and feature~
, respectively.)
The command you suggested (I've added the --oneline
flag, to reduce the output) indeed does not limit the log to the descendants of the given commit:
# master~ = D
$ git log --all --ancestry-path --oneline master~^!
e234427 Y
cf98c6b X
b3d493a E
e2bb266 D
# feature~ == X
$ git log --all --ancestry-path --oneline feature~^!
e234427 Y
cf98c6b X
b3d493a E
e2bb266 D
but the one I suggest does:
# master~ == D
$ git log --all --ancestry-path --oneline ^master~
b3d493a E
# feature~ == X
$ git log --all --ancestry-path --oneline ^feature~
e234427 Y
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With