I don't think this is directly possible (unless you know in advance the exact list to include/exclude, which negates the purpose of walking the DAG)
Actually, the OP Ken Hirakawa managed to get the expected linear history by:
git log --pretty=format:"%h%n" --ancestry-path --reverse $prev_commit..$end_commit
And for each commit, making sure it is a direct child of the previous commit.
Here is the script writtten by Ken Hirakawa.
Here is my script to create the DAG mentioned in the History Simplification section of the git log man page, for --ancestry-path
:
You will find at the end the bash script I used to create a similar history (call it with the name of the root dir, and your username).
I define:
$ git config --global alias.lgg "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative"
I get:
$ git lgg
* d7c4459 - (HEAD, M, fromA) M <VonC>
* 82b011d - (L) Merge commit 'J' into fromA <VonC>
|\
| * 190265b - (J, master) J <VonC>
| * ef8e325 - (I) Merge commit 'F' <VonC>
| |\
| | * 4b6d976 - (F, fromB) F <VonC>
| * | 45a5d4d - (H) H <VonC>
| * | 834b239 - (G) Merge commit 'E' <VonC>
| |\ \
| | |/
| | * f8e9272 - (E) E <VonC>
| | * 96b5538 - (D) D <VonC>
| * | 49eff7f - (C) C <VonC>
| |/
| * 02c3ef4 - (B) B <VonC>
* | c0d9e1e - (K) K <VonC>
|/
* 6530d79 - (A) A <VonC>
From there, I cannot exclude one of the parents of commit I.
The ancestry-path does return:
$ git lgg --ancestry-path D..M
* d7c4459 - (HEAD, M, fromA) M <VonC>
* 82b011d - (L) Merge commit 'J' into fromA <VonC>
* 190265b - (J, master) J <VonC>
* ef8e325 - (I) Merge commit 'F' <VonC>
|\
| * 4b6d976 - (F, fromB) F <VonC>
* | 45a5d4d - (H) H <VonC>
* | 834b239 - (G) Merge commit 'E' <VonC>
|/
* f8e9272 - (E) E <VonC>
which is consistent with the log man page:
A regular D..M
computes the set of commits that are ancestors of M
, but excludes the ones that are ancestors of D
.
This is useful to see what happened to the history leading to M
since D
, in the sense that "what does M
have that did not exist in D
".
The result in this example would be all the commits, except A
and B
(and D
itself, of course).
When we want to find out what commits in M
are contaminated with the bug introduced by D
and need fixing, however, we might want to view only the subset of D..M
that are actually descendants of D
, i.e. excluding C
and K
.
This is exactly what the --ancestry-path
option does.
#!/bin/bash
function makeCommit() {
local letter=$1
if [[ `git tag -l $letter` == "" ]] ; then
echo $letter > $root/$letter
git add .
git commit -m "${letter}"
git tag -m "${letter}" $letter
else
echo "commit $letter already there"
fi
}
function makeMerge() {
local letter=$1
local from=$2
if [[ `git tag -l $letter` == "" ]] ; then
git merge $from
git tag -m "${letter}" $letter
else
echo "merge $letter already done"
fi
}
function makeBranch() {
local branch=$1
local from=$2
if [[ "$(git branch|grep $1)" == "" ]] ; then
git checkout -b $branch $from
else
echo "branch $branch already created"
git checkout $branch
fi
}
root=$1
user=$2
if [[ ! -e $root/.git ]] ; then
git init $root
fi
export GIT_WORK_TREE="./$root"
export GIT_DIR="./$root/.git"
git config --local user.name $2
makeCommit "A"
makeCommit "B"
makeCommit "C"
makeBranch "fromB" "B"
makeCommit "D"
makeCommit "E"
makeCommit "F"
git checkout master
makeMerge "G" "E"
makeCommit "H"
makeMerge "I" "F"
makeCommit "J"
makeBranch "fromA" "A"
makeCommit "K"
makeMerge "L" "J"
makeCommit "M"