Merge lp:~amanica/bzr/325618_log_returns_too_much into lp:bzr

Proposed by Marius Kruger
Status: Merged
Approved by: Ian Clatworthy
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~amanica/bzr/325618_log_returns_too_much
Merge into: lp:bzr
Diff against target: 103 lines (+54/-1)
4 files modified
NEWS (+3/-0)
bzrlib/branch.py (+14/-1)
bzrlib/tests/blackbox/test_log.py (+15/-0)
bzrlib/tests/per_branch/test_iter_merge_sorted_revisions.py (+22/-0)
To merge this branch: bzr merge lp:~amanica/bzr/325618_log_returns_too_much
Reviewer Review Type Date Requested Status
Ian Clatworthy Approve
bzr-core Pending
Review via email: mp+14275@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Marius Kruger (amanica) wrote :

Ian Clatworthy wrote on 2009-10-20
> Sorry for taking months and months to get to this review. It's been a crazy time for me. I'll try to find some time now to work with you towards a solution we're both happy with.

Thanks a lot, without feedback I couldn't really continue. I've also been a bit occupied (holiday/work/studies).

> To be honest, I use qlog almost exclusively these days so I'm less passionate than what I was about how log behaves on the command line. I do agree that #325618 is a real bug, though I'm not sure I'm comfortable changing default behaviour to fix it. I certainly think "bzr log -n0 -rX" ought to show the merged revisions for X, so if this patch alters that, I'd vote against it.

ehm, I mis-analysed the problem and fixed it the wrong way the first time around.
In stead of chopping off all parents after the stop-revision, I now allow
the "merged revisions" of the stop-revision. I think that clears up all the
controversy and all the tests I mangled before could be restored to their
previous glory.
BTW. your phrasing here in the feedback helped the penny to drop. thanks again.

> On a semi-related topic, if we are going to allow/encourage alternative behaviour wrt revision range semantics in log, I like the idea of adding an option called something like --exclude-lower as Eric suggested.

Great, I added a draft spec now, to keep track of all this:
http://bazaar-vcs.org/DraftSpecs/NewLogBehaviour

> In your opinion, is it possible to fix this bug without changing semantics?
Yes. this merge-proposal should be self-sufficient now. i.e. I don't think
it needs any of the other proposed changes to be useful and bearable.

For the last time thanks for the feedback, it inspired me to start completing this stuff, finally.

Revision history for this message
Ian Clatworthy (ian-clatworthy) wrote :

Hi Marius,

This is looking a much better approach. The big issue right now is that the new test passes *without* the code change which means that the new test isn't triggering the bug you're fixing, right?

Also, I'm not 100% sold on the proposed change yet though for a few reasons:

* I'd prefer to keep the term left_parent (as opposed to mainline_stop_rev) because a user can log a "development line" which isn't the mainline, e.g. log -ra.b.x..a.b.y

* The inner if statement can go at the same level as the outer one???

* Do we need to test reached_top_revision_id in the inner if clause???

Does all that make sense?

FWIW, I'm about to look at a similar bug in log so I may end up using your code to do that. Perhaps we can pool our efforts and solve this batch of bugs together in coming days?

review: Needs Fixing
Revision history for this message
Andrew Bennetts (spiv) wrote :

Btw, I see that the reporter of bug 484109 says this branch works better for them (than trunk), so that's a good sign that this patch is on the right track.

Revision history for this message
Marius Kruger (amanica) wrote :

2009/11/20 Ian Clatworthy <email address hidden>:
> Review: Needs Fixing
> This is looking a much better approach. The big issue right now is that the new test passes *without* the code change which means that the new test isn't triggering the bug you're fixing, right?

whoops. I think this tested my first approach which would have stopped
at rev 1.1.2 .
Anyway with the new approach I had to change it to something which used to work.
Since I wrote it already I think it can stay, so I'm leaving it in.
You can delete it when merging if you want.

>
> Also, I'm not 100% sold on the proposed change yet though for a few reasons:
>
> * I'd prefer to keep the term left_parent (as opposed to mainline_stop_rev) because a user can log a "development line" which isn't the mainline, e.g. log -ra.b.x..a.b.y

mainline made more sense to me in order to understand the concept, but
I see your point.
I changed it to left_parent again (the fact that it is actually the
revision we want to stop logging at
was important for me to understand the code, so I added a comment to
that effect).

> * The inner if statement can go at the same level as the outer one???

not sure which inner you refer to here, but assume "if rev.parent_ids" ,
yes it can move up but I'm avoiding unnecessary calls to
repository.get_revision() which looks expensive to me.

> * Do we need to test reached_top_revision_id in the inner if clause???

yes, I only want to extend the whitelist with the parents of stop_rev.

2009/11/26 Ian Clatworthy <email address hidden>:
> Here's what I'd like you to do: add tests for the changes you've made
> down at the branch.iter_merge_sorted_revisions() level. That's actually
> the important tests in this case, rather than higher level log ones. If
> branch.iter_merge_sorted_revisions() works, then log will work. :-)

your right, since we're using TDD.
I was just copying existing tests and thinking about the behaviour I'd
like to see,
which is by the way the BDD[1] way which I came to love.

> The current tests can be found here:

> bzrlib/tests/per_branch/iter_merge_sorted_revisions.py

added two tests here now, of which one fails without my fix.

> I hope the existing tests are well written and easy to copy-and-paste
> from.

it took some digging but it is nice and clean.

> Let me know if you run into problems. I'm around this week but
> back on chemo next week (so around but brain dead then).

Hope it goes well.
Thanks for your efforts and patience.

launchpad doesn't want me to push now, so I'll leave a `sleep 3600 &&
bzr push` on and go to bed. Also attaching patch for good measure.

[1] http://en.wikipedia.org/wiki/Behavior_driven_development

--
sorry it took so long.
<>< Marius ><>

# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: marius.kruger@enerweb.co.za-20091203235357-\
# 1po7aapt4nljf9h9
# target_branch: file:///stf/prj/bzr/bzr.repo/bzr.dev/
# testament_sha1: 82dca80bec3cd38186a5f8a0ca7ad460cc301ed6
# timestamp: 2009-12-04 02:29:00 +0200
# base_revision_id: pqm@pqm.ubuntu.com-20091120185110-7muay17qmdqvrg7z
#
# Begin patch
=== modified file 'NEWS'
--- NEWS 2009-11-20 16:42:28 +0000
+++ NEWS 2009-12-03 23:53:57 +0000
@@ -35,6 +35,9 @@
3535
36* ``bzr ignore /`` no longer causes an IndexError. (Gorder Tyler, #456036)36* ``bzr ignore /`` no longer causes an IndexError. (Gorder Tyler, #456036)
3737
38* ``bzr log -n0 -rN`` should not return revisions beyond its merged revisions.
39 (#325618, #484109, Marius Kruger)
40
38* ``bzr mv --quiet`` really is quiet now. (Gordon Tyler, #271790)41* ``bzr mv --quiet`` really is quiet now. (Gordon Tyler, #271790)
3942
40* Lots of bugfixes for the test suite on Windows. We should once again43* Lots of bugfixes for the test suite on Windows. We should once again
4144
=== modified file 'bzrlib/branch.py'
--- bzrlib/branch.py 2009-10-15 02:11:18 +0000
+++ bzrlib/branch.py 2009-11-21 16:12:55 +0000
@@ -503,12 +503,25 @@
503 left_parent = stop_rev.parent_ids[0]503 left_parent = stop_rev.parent_ids[0]
504 else:504 else:
505 left_parent = _mod_revision.NULL_REVISION505 left_parent = _mod_revision.NULL_REVISION
506 # left_parent is the actual revision we want to stop logging at,
507 # since we want to show the merged revisions after the stop_rev too
508 reached_stop_revision_id = False
509 revision_id_whitelist = []
506 for node in rev_iter:510 for node in rev_iter:
507 rev_id = node.key[-1]511 rev_id = node.key[-1]
508 if rev_id == left_parent:512 if rev_id == left_parent:
513 # reached the left parent after the stop_revision
509 return514 return
510 yield (rev_id, node.merge_depth, node.revno,515 if (not reached_stop_revision_id or
516 rev_id in revision_id_whitelist):
517 yield (rev_id, node.merge_depth, node.revno,
511 node.end_of_merge)518 node.end_of_merge)
519 if reached_stop_revision_id or rev_id == stop_revision_id:
520 # only do the merged revs of rev_id from now on
521 rev = self.repository.get_revision(rev_id)
522 if rev.parent_ids:
523 reached_stop_revision_id = True
524 revision_id_whitelist.extend(rev.parent_ids)
512 else:525 else:
513 raise ValueError('invalid stop_rule %r' % stop_rule)526 raise ValueError('invalid stop_rule %r' % stop_rule)
514527
515528
=== modified file 'bzrlib/tests/blackbox/test_log.py'
--- bzrlib/tests/blackbox/test_log.py 2009-06-10 03:56:49 +0000
+++ bzrlib/tests/blackbox/test_log.py 2009-11-01 03:45:20 +0000
@@ -536,6 +536,21 @@
536"""536"""
537 self.check_log(expected, ['-n0', '-r1.1.1..1.1.2'])537 self.check_log(expected, ['-n0', '-r1.1.1..1.1.2'])
538538
539 def test_merges_partial_range_ignore_before_lower_bound(self):
540 """Dont show revisions before the lower bound's merged revs"""
541 expected = """\
542 2 Lorem Ipsum\t2005-11-22 [merge]
543 merge branch level1
544
545 1.1.2 Lorem Ipsum\t2005-11-22 [merge]
546 merge branch level2
547
548 1.2.1 Lorem Ipsum\t2005-11-22
549 in branch level2
550
551"""
552 self.check_log(expected, ['--short', '-n0', '-r1.1.2..2'])
553
539554
540class TestLogDiff(TestLog):555class TestLogDiff(TestLog):
541556
542557
=== modified file 'bzrlib/tests/per_branch/test_iter_merge_sorted_revisions.py'
--- bzrlib/tests/per_branch/test_iter_merge_sorted_revisions.py 2009-07-10 05:49:34 +0000
+++ bzrlib/tests/per_branch/test_iter_merge_sorted_revisions.py 2009-12-03 23:34:38 +0000
@@ -84,6 +84,28 @@
84 ], list(the_branch.iter_merge_sorted_revisions(84 ], list(the_branch.iter_merge_sorted_revisions(
85 stop_revision_id='rev-3', stop_rule='with-merges')))85 stop_revision_id='rev-3', stop_rule='with-merges')))
8686
87 def test_merge_sorted_range_stop_with_merges_can_show_non_parents(self):
88 tree = self.create_tree_with_merge()
89 the_branch = tree.bzrdir.open_branch()
90 # rev-1.1.1 gets logged before the end revision is reached.
91 # so it is returned even though rev-1.1.1 is not a parent of rev-2.
92 self.assertEqual([
93 ('rev-3', 0, (3,), False),
94 ('rev-1.1.1', 1, (1,1,1), True),
95 ('rev-2', 0, (2,), False),
96 ], list(the_branch.iter_merge_sorted_revisions(
97 stop_revision_id='rev-2', stop_rule='with-merges')))
98
99 def test_merge_sorted_range_stop_with_merges_ignore_non_parents(self):
100 tree = self.create_tree_with_merge()
101 the_branch = tree.bzrdir.open_branch()
102 # rev-2 is not a parent of rev-1.1.1 so it must not be returned
103 self.assertEqual([
104 ('rev-3', 0, (3,), False),
105 ('rev-1.1.1', 1, (1,1,1), True),
106 ], list(the_branch.iter_merge_sorted_revisions(
107 stop_revision_id='rev-1.1.1', stop_rule='with-merges')))
108
87 def test_merge_sorted_single_stop_exclude(self):109 def test_merge_sorted_single_stop_exclude(self):
88 # from X..X exclusive is an empty result110 # from X..X exclusive is an empty result
89 tree = self.create_tree_with_merge()111 tree = self.create_tree_with_merge()
90112
# Begin bundle
91IyBCYXphYXIgcmV2aXNpb24gYnVuZGxlIHY0CiMKQlpoOTFBWSZTWep9X6YAIFF/gFVUREBY///3113IyBCYXphYXIgcmV2aXNpb24gYnVuZGxlIHY0CiMKQlpoOTFBWSZTWep9X6YAIFF/gFVUREBY///3
92fz+fjv////BgJZ68o8+z3fdn1221cvRfVXUVvdt131k7e7pwDHZ0fXffcGgW+dEo7YDmx9bs9Buz114fz+fjv////BgJZ68o8+z3fdn1221cvRfVXUVvdt131k7e7pwDHZ0fXffcGgW+dEo7YDmx9bs9Buz
93p7718NjCePW72XFvcOe7j7eduvd7Vz6ca+fHPvVkSipktZgha2bWrR7vd50okhKICMgIwUwCaU2o115p7718NjCePW72XFvcOe7j7eduvd7Vz6ca+fHPvVkSipktZgha2bWrR7vd50okhKICMgIwUwCaU2o
949TIepso9QAAaNA0ASSAAIIgiZEynqemo9IemoAGgAAABKEwiE0aU9BTTE0fpQPKGgAGgAAAASEhC1169TIepso9QAAaNA0ASSAAIIgiZEynqemo9IemoAGgAAABKEwiE0aU9BTTE0fpQPKGgAGgAAAASEhC
95aEmZGjRGhTHqTamm9SZABgjQAGmgRSIBNTGgmE1PST8mqMB6Ro1T0nhTTZQNAZPU/VBFIQAmU0xG117aEmZGjRGhTHqTamm9SZABgjQAGmgRSIBNTGgmE1PST8mqMB6Ro1T0nhTTZQNAZPU/VBFIQAmU0xG
96h6k2o0eponqHqamgyAAaaGgC7WjGpGAEwnCa5UCSevrigoI6pbt9XEQ8X7xiT/To9jp/zH0r61/D118h6k2o0eponqHqamgyAAaaGgC7WjGpGAEwnCa5UCSevrigoI6pbt9XEQ8X7xiT/To9jp/zH0r61/D
97pQTmvDYlSK0Ynbdhe5CAoV461+T1SpXZZz7Kc6rE/k3f+pe2BwttK0qOzP7H8/uPujZfqbwdRaeq119pQTmvDYlSK0Ynbdhe5CAoV461+T1SpXZZz7Kc6rE/k3f+pe2BwttK0qOzP7H8/uPujZfqbwdRaeq
982x1K1op1PT6J14h551njZh0Z1n9vZe/J3SZs3rDYctzUZ+rGuHkuXIPyFM6qc86/ZAuo66aFIU2O1202x1K1op1PT6J14h551njZh0Z1n9vZe/J3SZs3rDYctzUZ+rGuHkuXIPyFM6qc86/ZAuo66aFIU2O
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
Revision history for this message
Ian Clatworthy (ian-clatworthy) wrote :

Marius Kruger wrote:

> your right, since we're using TDD.
> I was just copying existing tests and thinking about the behaviour I'd
> like to see,
> which is by the way the BDD[1] way which I came to love.

I'm all for BDD. (I prefer it to TDD fwiw.)

> launchpad doesn't want me to push now, so I'll leave a `sleep 3600 &&
> bzr push` on and go to bed. Also attaching patch for good measure.

Thanks. I've reviewed this now and it looks ready to merge IMO.

Ian C.

Revision history for this message
Ian Clatworthy (ian-clatworthy) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'NEWS'
--- NEWS 2009-12-04 08:07:56 +0000
+++ NEWS 2009-12-04 10:09:11 +0000
@@ -35,6 +35,9 @@
3535
36* ``bzr ignore /`` no longer causes an IndexError. (Gorder Tyler, #456036)36* ``bzr ignore /`` no longer causes an IndexError. (Gorder Tyler, #456036)
3737
38* ``bzr log -n0 -rN`` should not return revisions beyond its merged revisions.
39 (#325618, #484109, Marius Kruger)
40
38* ``bzr mv --quiet`` really is quiet now. (Gordon Tyler, #271790)41* ``bzr mv --quiet`` really is quiet now. (Gordon Tyler, #271790)
3942
40* ``bzr serve`` is more clear about the risk of supplying --allow-writes.43* ``bzr serve`` is more clear about the risk of supplying --allow-writes.
4144
=== modified file 'bzrlib/branch.py'
--- bzrlib/branch.py 2009-12-03 02:24:54 +0000
+++ bzrlib/branch.py 2009-12-04 10:09:11 +0000
@@ -503,12 +503,25 @@
503 left_parent = stop_rev.parent_ids[0]503 left_parent = stop_rev.parent_ids[0]
504 else:504 else:
505 left_parent = _mod_revision.NULL_REVISION505 left_parent = _mod_revision.NULL_REVISION
506 # left_parent is the actual revision we want to stop logging at,
507 # since we want to show the merged revisions after the stop_rev too
508 reached_stop_revision_id = False
509 revision_id_whitelist = []
506 for node in rev_iter:510 for node in rev_iter:
507 rev_id = node.key[-1]511 rev_id = node.key[-1]
508 if rev_id == left_parent:512 if rev_id == left_parent:
513 # reached the left parent after the stop_revision
509 return514 return
510 yield (rev_id, node.merge_depth, node.revno,515 if (not reached_stop_revision_id or
516 rev_id in revision_id_whitelist):
517 yield (rev_id, node.merge_depth, node.revno,
511 node.end_of_merge)518 node.end_of_merge)
519 if reached_stop_revision_id or rev_id == stop_revision_id:
520 # only do the merged revs of rev_id from now on
521 rev = self.repository.get_revision(rev_id)
522 if rev.parent_ids:
523 reached_stop_revision_id = True
524 revision_id_whitelist.extend(rev.parent_ids)
512 else:525 else:
513 raise ValueError('invalid stop_rule %r' % stop_rule)526 raise ValueError('invalid stop_rule %r' % stop_rule)
514527
515528
=== modified file 'bzrlib/tests/blackbox/test_log.py'
--- bzrlib/tests/blackbox/test_log.py 2009-06-10 03:56:49 +0000
+++ bzrlib/tests/blackbox/test_log.py 2009-12-04 10:09:11 +0000
@@ -536,6 +536,21 @@
536"""536"""
537 self.check_log(expected, ['-n0', '-r1.1.1..1.1.2'])537 self.check_log(expected, ['-n0', '-r1.1.1..1.1.2'])
538538
539 def test_merges_partial_range_ignore_before_lower_bound(self):
540 """Dont show revisions before the lower bound's merged revs"""
541 expected = """\
542 2 Lorem Ipsum\t2005-11-22 [merge]
543 merge branch level1
544
545 1.1.2 Lorem Ipsum\t2005-11-22 [merge]
546 merge branch level2
547
548 1.2.1 Lorem Ipsum\t2005-11-22
549 in branch level2
550
551"""
552 self.check_log(expected, ['--short', '-n0', '-r1.1.2..2'])
553
539554
540class TestLogDiff(TestLog):555class TestLogDiff(TestLog):
541556
542557
=== modified file 'bzrlib/tests/per_branch/test_iter_merge_sorted_revisions.py'
--- bzrlib/tests/per_branch/test_iter_merge_sorted_revisions.py 2009-07-10 05:49:34 +0000
+++ bzrlib/tests/per_branch/test_iter_merge_sorted_revisions.py 2009-12-04 10:09:11 +0000
@@ -84,6 +84,28 @@
84 ], list(the_branch.iter_merge_sorted_revisions(84 ], list(the_branch.iter_merge_sorted_revisions(
85 stop_revision_id='rev-3', stop_rule='with-merges')))85 stop_revision_id='rev-3', stop_rule='with-merges')))
8686
87 def test_merge_sorted_range_stop_with_merges_can_show_non_parents(self):
88 tree = self.create_tree_with_merge()
89 the_branch = tree.bzrdir.open_branch()
90 # rev-1.1.1 gets logged before the end revision is reached.
91 # so it is returned even though rev-1.1.1 is not a parent of rev-2.
92 self.assertEqual([
93 ('rev-3', 0, (3,), False),
94 ('rev-1.1.1', 1, (1,1,1), True),
95 ('rev-2', 0, (2,), False),
96 ], list(the_branch.iter_merge_sorted_revisions(
97 stop_revision_id='rev-2', stop_rule='with-merges')))
98
99 def test_merge_sorted_range_stop_with_merges_ignore_non_parents(self):
100 tree = self.create_tree_with_merge()
101 the_branch = tree.bzrdir.open_branch()
102 # rev-2 is not a parent of rev-1.1.1 so it must not be returned
103 self.assertEqual([
104 ('rev-3', 0, (3,), False),
105 ('rev-1.1.1', 1, (1,1,1), True),
106 ], list(the_branch.iter_merge_sorted_revisions(
107 stop_revision_id='rev-1.1.1', stop_rule='with-merges')))
108
87 def test_merge_sorted_single_stop_exclude(self):109 def test_merge_sorted_single_stop_exclude(self):
88 # from X..X exclusive is an empty result110 # from X..X exclusive is an empty result
89 tree = self.create_tree_with_merge()111 tree = self.create_tree_with_merge()