log can show too few revs
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Bazaar |
Confirmed
|
High
|
Unassigned | ||
Breezy |
Triaged
|
High
|
Unassigned |
Bug Description
Depending on the shape of the history graph, doing "log" on a directory can yield very unexpected results.
This is a very long explanation. I don't have time to make it shorter :(
--
The graph is convoluted enough you probably want to use qlog to look at it. However, here's a quick overview:
7 Matthew Fuller 2012-10-28
Nada
6 Matthew Fuller 2012-10-28 [merge]
Merge C:1
1.2.4 Matthew Fuller 2012-10-28 [merge]
1.2.3 Matthew Fuller 2012-10-28
1.2.2 Matthew Fuller 2012-10-28 [merge]
A foo/
A foo/bar
1.2.1 Matthew Fuller 2012-10-28
5 Matthew Fuller 2012-10-28
Nada
4 Matthew Fuller 2012-10-28
Empty to force merge
3 Matthew Fuller 2012-10-28
Edit bar
M foo/bar
2 Matthew Fuller 2012-10-28 [merge]
Merge B:1
A foo/
A foo/bar
1.1.1 Matthew Fuller 2012-10-28
A foo/
A foo/bar
1 Matthew Fuller 2012-10-28
Init
C started at (1). The A:1 merge landed (2,3,4), and A:2 landed (5).
--
Now, depending on minor alterations I make, mostly to revs that don't touch foo, I get differing results from log.
The various permutations of running the script below look like this:
------
------
Without -n0, I only ever see
"Edit bar" (3)
"Merge B:1" (2)
which is probably what's expected.
------
------
If I uncomment the mk_dir= at [3] to make foo a file rather than a
directory, I get
"Edit bar" (3)
"Merge B:1" (2)
"Create foo" (1.1.1)
which may possibly be the "right" answer (though see below), and none of the below changes have any effect.
--
If, however, I run a "log -v" instead, I see only
"Merge A:1" (1.2.2)
just like the directory version below, and the described alterations have the same effects.
------
------
However, with foo/ as a directory (the presence/absence of -v makes no difference in this case):
Running the whole thing, I get only
"Merge A:1" (1.2.2)
which is the *least* useful possible answer, since it tells me nothing at all about most of the revs that touched files in the dir, only the merge into C of the "nothing" -> "final state" transition.
--
If I take out any one of the Nada's labelled [1] I get
"Merge A:1" (1.2.2)
"Edit bar" (3)
which means I see the above "everything rolled up" merge, plus the edit rev. But I never see the rev that added foo/bar in its original form.
--
If I take out any 2 of [1], or uncomment the "exit" to skip the [2] block, I get
"Merge A:1" (1.2.2)
"Edit bar" (3)
"Merge B:1" (2)
which means in addition to the above, I now see the merge of the original creation, though not the creation itself.
--
If I take out any 3 or more of [1], or 1+ of the [1] AND the whole [2] block, I
get
"Merge A:1" (1.2.2)
"Edit bar" (3)
"Merge B:1" (2)
"Create foo" (1.1.1)
which now gives me every rev that changes, relative to its left-hand parent, something in foo/.
--
I believe either the 3-rev version shown without -v for the file version (3, 2, 1.1.1) OR the 4-rev version for dirs with several deletions (1.2.2, 3, 2, 1.1.1) are "correct"; I'm not sure which is "better".
However, I'm _quite_ sure all the 1- and 2-rev versions, and that the 3-rev in the deletions (1.2.2, 3, 2) are wrong wrong wrong. And very unpleasant to run across, since you may not realize bzr is lying to you and take log at face value.
I checked this with bzr.dev, 2.5.1, and the latest 2.0; all acted identically.
------
------
Creation script (inline):
#!/bin/sh -e
#bzr="/
bzr="/usr/
if [ -d "test" ]; then
echo "test/ already exists"
exit
fi
mk_dir=true
# [3]
#mk_dir=false
${bzr} init-repo test
(
cd test
# First, create a branch with a rev
${bzr} init A
(
cd A
${bzr} ci --unchanged -m 'Init'
)
# Now work on a file
${bzr} branch A B
(
cd B
if $mk_dir; then
mkdir foo
echo bar > foo/bar
else
touch foo
fi
${bzr} add
${bzr} ci -m 'Create foo'
)
# Merge that
(
cd A
${bzr} merge ../B
${bzr} ci -m "Merge B:1"
if $mk_dir; then
echo baz > foo/bar
else
echo baz > foo
fi
${bzr} ci --unchanged -m 'Edit bar'
# [1]
${bzr} ci --unchanged -m 'Nada'
)
# Now make another branch from the start of A, and merge later stuff
# from A
${bzr} branch -r1 A C
(
cd C
# [1]
${bzr} ci --unchanged -m 'Nada'
${bzr} merge ../A
${bzr} ci -m 'Merge A:1'
# [1]
${bzr} ci --unchanged -m 'Nada'
)
# Make another change, and merge it into C
# [2]
(
#exit
cd A
${bzr} ci --unchanged -m 'Empty to force merge'
cd ../C
${bzr} merge ../A
${bzr} ci -m 'Merge A:2'
)
# Now land those changes back on A
(
cd A
# [1]
${bzr} ci --unchanged -m 'Nada'
${bzr} merge ../C
${bzr} ci -m "Merge C:1"
# [1]
${bzr} ci --unchanged -m 'Nada'
)
# Now see when foo was touched.
(
cd A
${bzr} log -n0 foo
#${bzr} log -n0 -v foo
)
)
description: | updated |
description: | updated |
Changed in bzr: | |
status: | New → Confirmed |
tags: | added: check-for-breezy |
Changed in brz: | |
status: | New → Triaged |
importance: | Undecided → High |
milestone: | none → 3.0.0 |
tags: | removed: check-for-breezy |
tags: | added: log |
Changed in brz: | |
milestone: | 3.0.0 → 3.1.0 |
Repro script as attachment, for easier grabbing.