Merge lp:~vila/bzr/440631-has-changes-no-param into lp:bzr

Proposed by Vincent Ladeuil
Status: Merged
Approved by: John A Meinel
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~vila/bzr/440631-has-changes-no-param
Merge into: lp:bzr
Diff against target: 399 lines
15 files modified
NEWS (+11/-3)
bzrlib/builtins.py (+7/-6)
bzrlib/bundle/apply_bundle.py (+2/-1)
bzrlib/foreign.py (+1/-2)
bzrlib/merge.py (+10/-1)
bzrlib/mutabletree.py (+11/-3)
bzrlib/reconfigure.py (+1/-3)
bzrlib/send.py (+2/-3)
bzrlib/tests/blackbox/test_merge.py (+1/-1)
bzrlib/tests/blackbox/test_uncommit.py (+2/-2)
bzrlib/tests/test_msgeditor.py (+1/-1)
bzrlib/tests/test_mutabletree.py (+30/-9)
bzrlib/tests/test_reconfigure.py (+14/-1)
bzrlib/tests/test_status.py (+1/-1)
bzrlib/workingtree.py (+4/-4)
To merge this branch: bzr merge lp:~vila/bzr/440631-has-changes-no-param
Reviewer Review Type Date Requested Status
John A Meinel Approve
Review via email: mp+12924@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Vincent Ladeuil (vila) wrote :

This patch changes MutableTree.has_changes() to stop requiring a tree parameter and default
to the basis tree instead. It also add a check for pending merges.

I've made the '_from_tree' parameter to keep the existing tests or I would have need to rewrite
them all (~20, none of them trivial).

I've updated all the call sites and fixed the test failures.
The later led to a discussion with John and Aaron that prompted the deprecations
of check_basis() and friends since they are not used anymore (and sometimes not tested).

I've also used has_changes() for reconfigure where the pending merges weren't checked,
and added the corresponding test.

Revision history for this message
John A Meinel (jameinel) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Vincent Ladeuil wrote:
> Vincent Ladeuil has proposed merging lp:~vila/bzr/440631-has-changes-no-param into lp:bzr.
>
> Requested reviews:
> bzr-core (bzr-core)
> Related bugs:
> #440631 mutable_tree.has_changes() should not take a parameter but always check against basis
> https://bugs.launchpad.net/bugs/440631
>
>
> This patch changes MutableTree.has_changes() to stop requiring a tree parameter and default
> to the basis tree instead. It also add a check for pending merges.
>
> I've made the '_from_tree' parameter to keep the existing tests or I would have need to rewrite
> them all (~20, none of them trivial).
>
> I've updated all the call sites and fixed the test failures.
> The later led to a discussion with John and Aaron that prompted the deprecations
> of check_basis() and friends since they are not used anymore (and sometimes not tested).
>
> I've also used has_changes() for reconfigure where the pending merges weren't checked,
> and added the corresponding test.
>

Everything looks good, except I don't see any new tests that *don't*
pass the parameter to "has_changes()". It is certainly tested indirectly
 via the blackbox tests. So certainly don't change all 20, but maybe 1
or 2 to get a simple unit test of it? Up to you.

 review: approve
 merge: approve

John
=:->

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkrLYYMACgkQJdeBCYSNAAMDXgCglJ/A/WjOtwkdyb/AG4TipX5h
+O8AnipiyUVF4S0v86hxRJJoHtye0y95
=WI34
-----END PGP SIGNATURE-----

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS'
2--- NEWS 2009-10-06 02:38:44 +0000
3+++ NEWS 2009-10-06 16:40:25 +0000
4@@ -160,9 +160,6 @@
5 API Changes
6 ***********
7
8-* ``ProgressTask.note`` is deprecated.
9- (Martin Pool)
10-
11 * ``bzrlib.user_encoding`` has been removed; use
12 ``bzrlib.osutils.get_user_encoding`` instead. (Martin Pool)
13
14@@ -172,6 +169,17 @@
15 * ``bzrlib.trace.log_error``, ``error`` and ``info`` have been deprecated.
16 (Martin Pool)
17
18+* ``MutableTree.has_changes()`` does not require a tree parameter anymore. It
19+ now defaults to comparing to the basis tree. It now checks for pending
20+ merges too. ``Merger.check_basis`` has been deprecated and replaced by the
21+ corresponding has_changes() calls. ``Merge.compare_basis``,
22+ ``Merger.file_revisions`` and ``Merger.ensure_revision_trees`` have also
23+ been deprecated.
24+ (Vincent Ladeuil, #440631)
25+
26+* ``ProgressTask.note`` is deprecated.
27+ (Martin Pool)
28+
29 Internals
30 *********
31
32
33=== modified file 'bzrlib/builtins.py'
34--- bzrlib/builtins.py 2009-09-24 19:51:37 +0000
35+++ bzrlib/builtins.py 2009-10-06 16:40:25 +0000
36@@ -461,8 +461,7 @@
37 raise errors.BzrCommandError("You cannot remove the working tree"
38 " of a remote path")
39 if not force:
40- if (working.has_changes(working.basis_tree())
41- or len(working.get_parent_ids()) > 1):
42+ if (working.has_changes()):
43 raise errors.UncommittedChanges(working)
44
45 working_path = working.bzrdir.root_transport.base
46@@ -1109,8 +1108,7 @@
47 else:
48 revision_id = None
49 if strict and tree is not None and revision_id is None:
50- if (tree.has_changes(tree.basis_tree())
51- or len(tree.get_parent_ids()) > 1):
52+ if (tree.has_changes()):
53 raise errors.UncommittedChanges(
54 tree, more='Use --no-strict to force the push.')
55 if tree.last_revision() != tree.branch.last_revision():
56@@ -3663,7 +3661,7 @@
57
58 # die as quickly as possible if there are uncommitted changes
59 if not force:
60- if tree.has_changes(basis_tree) or len(tree.get_parent_ids()) > 1:
61+ if tree.has_changes():
62 raise errors.UncommittedChanges(tree)
63
64 view_info = _get_view_info_for_change_reporter(tree)
65@@ -3720,7 +3718,10 @@
66 merger.other_rev_id)
67 result.report(self.outf)
68 return 0
69- merger.check_basis(False)
70+ if merger.this_basis is None:
71+ raise errors.BzrCommandError(
72+ "This branch has no commits."
73+ " (perhaps you would prefer 'bzr pull')")
74 if preview:
75 return self._do_preview(merger, cleanups)
76 elif interactive:
77
78=== modified file 'bzrlib/bundle/apply_bundle.py'
79--- bzrlib/bundle/apply_bundle.py 2009-03-23 14:59:43 +0000
80+++ bzrlib/bundle/apply_bundle.py 2009-10-06 16:40:25 +0000
81@@ -56,7 +56,8 @@
82 change_reporter=change_reporter)
83 merger.pp = pp
84 merger.pp.next_phase()
85- merger.check_basis(check_clean, require_commits=False)
86+ if check_clean and tree.has_changes():
87+ raise errors.UncommittedChanges(self)
88 merger.other_rev_id = reader.target
89 merger.other_tree = merger.revision_tree(reader.target)
90 merger.other_basis = reader.target
91
92=== modified file 'bzrlib/foreign.py'
93--- bzrlib/foreign.py 2009-10-02 09:11:43 +0000
94+++ bzrlib/foreign.py 2009-10-06 16:40:24 +0000
95@@ -305,8 +305,7 @@
96 ).get_user_option_as_bool('dpush_strict')
97 if strict is None: strict = True # default value
98 if strict and source_wt is not None:
99- if (source_wt.has_changes(source_wt.basis_tree())
100- or len(source_wt.get_parent_ids()) > 1):
101+ if (source_wt.has_changes()):
102 raise errors.UncommittedChanges(
103 source_wt, more='Use --no-strict to force the push.')
104 if source_wt.last_revision() != source_wt.branch.last_revision():
105
106=== modified file 'bzrlib/merge.py'
107--- bzrlib/merge.py 2009-10-06 12:25:59 +0000
108+++ bzrlib/merge.py 2009-10-06 16:40:25 +0000
109@@ -35,6 +35,10 @@
110 ui,
111 versionedfile
112 )
113+from bzrlib.symbol_versioning import (
114+ deprecated_in,
115+ deprecated_method,
116+ )
117 # TODO: Report back as changes are merged in
118
119
120@@ -226,6 +230,7 @@
121 revision_id = _mod_revision.ensure_null(revision_id)
122 return branch, self.revision_tree(revision_id, branch)
123
124+ @deprecated_method(deprecated_in((2, 1, 0)))
125 def ensure_revision_trees(self):
126 if self.this_revision_tree is None:
127 self.this_basis_tree = self.revision_tree(self.this_basis)
128@@ -239,6 +244,7 @@
129 other_rev_id = self.other_basis
130 self.other_tree = other_basis_tree
131
132+ @deprecated_method(deprecated_in((2, 1, 0)))
133 def file_revisions(self, file_id):
134 self.ensure_revision_trees()
135 def get_id(tree, file_id):
136@@ -252,6 +258,7 @@
137 trees = (self.this_basis_tree, self.other_tree)
138 return [get_id(tree, file_id) for tree in trees]
139
140+ @deprecated_method(deprecated_in((2, 1, 0)))
141 def check_basis(self, check_clean, require_commits=True):
142 if self.this_basis is None and require_commits is True:
143 raise errors.BzrCommandError(
144@@ -262,6 +269,7 @@
145 if self.this_basis != self.this_rev_id:
146 raise errors.UncommittedChanges(self.this_tree)
147
148+ @deprecated_method(deprecated_in((2, 1, 0)))
149 def compare_basis(self):
150 try:
151 basis_tree = self.revision_tree(self.this_tree.last_revision())
152@@ -274,7 +282,8 @@
153 self.interesting_files = file_list
154
155 def set_pending(self):
156- if not self.base_is_ancestor or not self.base_is_other_ancestor or self.other_rev_id is None:
157+ if (not self.base_is_ancestor or not self.base_is_other_ancestor
158+ or self.other_rev_id is None):
159 return
160 self._add_parent()
161
162
163=== modified file 'bzrlib/mutabletree.py'
164--- bzrlib/mutabletree.py 2009-10-06 12:25:59 +0000
165+++ bzrlib/mutabletree.py 2009-10-06 16:40:24 +0000
166@@ -233,12 +233,20 @@
167 raise NotImplementedError(self._gather_kinds)
168
169 @needs_read_lock
170- def has_changes(self, from_tree):
171- """Quickly check that the tree contains at least one change.
172+ def has_changes(self, _from_tree=None):
173+ """Quickly check that the tree contains at least one commitable change.
174+
175+ :param _from_tree: tree to compare against to find changes (default to
176+ the basis tree and is intended to be used by tests).
177
178 :return: True if a change is found. False otherwise
179 """
180- changes = self.iter_changes(from_tree)
181+ # Check pending merges
182+ if len(self.get_parent_ids()) > 1:
183+ return True
184+ if _from_tree is None:
185+ _from_tree = self.basis_tree()
186+ changes = self.iter_changes(_from_tree)
187 try:
188 change = changes.next()
189 # Exclude root (talk about black magic... --vila 20090629)
190
191=== modified file 'bzrlib/reconfigure.py'
192--- bzrlib/reconfigure.py 2009-07-24 03:15:56 +0000
193+++ bzrlib/reconfigure.py 2009-10-06 16:40:25 +0000
194@@ -265,9 +265,7 @@
195
196 def _check(self):
197 """Raise if reconfiguration would destroy local changes"""
198- if self._destroy_tree:
199- # XXX: What about pending merges ? -- vila 20090629
200- if self.tree.has_changes(self.tree.basis_tree()):
201+ if self._destroy_tree and self.tree.has_changes():
202 raise errors.UncommittedChanges(self.tree)
203 if self._create_reference and self.local_branch is not None:
204 reference_branch = branch.Branch.open(self._select_bind_location())
205
206=== modified file 'bzrlib/send.py'
207--- bzrlib/send.py 2009-07-17 14:41:02 +0000
208+++ bzrlib/send.py 2009-10-06 16:40:24 +0000
209@@ -115,14 +115,13 @@
210 ).get_user_option_as_bool('send_strict')
211 if strict is None: strict = True # default value
212 if strict and tree is not None:
213- if (tree.has_changes(tree.basis_tree())
214- or len(tree.get_parent_ids()) > 1):
215+ if (tree.has_changes()):
216 raise errors.UncommittedChanges(
217 tree, more='Use --no-strict to force the send.')
218 if tree.last_revision() != tree.branch.last_revision():
219 # The tree has lost sync with its branch, there is little
220 # chance that the user is aware of it but he can still force
221- # the push with --no-strict
222+ # the send with --no-strict
223 raise errors.OutOfDateTree(
224 tree, more='Use --no-strict to force the send.')
225 revision_id = branch.last_revision()
226
227=== modified file 'bzrlib/tests/blackbox/test_merge.py'
228--- bzrlib/tests/blackbox/test_merge.py 2009-09-09 15:43:52 +0000
229+++ bzrlib/tests/blackbox/test_merge.py 2009-10-06 16:40:24 +0000
230@@ -605,7 +605,7 @@
231
232 def test_merge_force(self):
233 self.tree_a.commit('empty change to allow merge to run')
234- # Second merge on top if the uncommitted one
235+ # Second merge on top of the uncommitted one
236 self.run_bzr(['merge', '../a', '--force'], working_dir='b')
237
238
239
240=== modified file 'bzrlib/tests/blackbox/test_uncommit.py'
241--- bzrlib/tests/blackbox/test_uncommit.py 2009-04-04 02:50:01 +0000
242+++ bzrlib/tests/blackbox/test_uncommit.py 2009-10-06 16:40:24 +0000
243@@ -233,14 +233,14 @@
244 tree3.commit('unchanged', rev_id='c3')
245
246 wt.merge_from_branch(tree2.branch)
247- wt.merge_from_branch(tree3.branch)
248+ wt.merge_from_branch(tree3.branch, force=True)
249 wt.commit('merge b3, c3', rev_id='a3')
250
251 tree2.commit('unchanged', rev_id='b4')
252 tree3.commit('unchanged', rev_id='c4')
253
254 wt.merge_from_branch(tree3.branch)
255- wt.merge_from_branch(tree2.branch)
256+ wt.merge_from_branch(tree2.branch, force=True)
257 wt.commit('merge b4, c4', rev_id='a4')
258
259 self.assertEqual(['a4'], wt.get_parent_ids())
260
261=== modified file 'bzrlib/tests/test_msgeditor.py'
262--- bzrlib/tests/test_msgeditor.py 2009-08-20 04:09:58 +0000
263+++ bzrlib/tests/test_msgeditor.py 2009-10-06 16:40:24 +0000
264@@ -93,7 +93,7 @@
265 tree3.commit('Feature Y, based on initial X work.',
266 timestamp=1233285960, timezone=0)
267 tree.merge_from_branch(tree2.branch)
268- tree.merge_from_branch(tree3.branch)
269+ tree.merge_from_branch(tree3.branch, force=True)
270 return tree
271
272 def test_commit_template_pending_merges(self):
273
274=== modified file 'bzrlib/tests/test_mutabletree.py'
275--- bzrlib/tests/test_mutabletree.py 2009-09-07 23:14:05 +0000
276+++ bzrlib/tests/test_mutabletree.py 2009-10-06 16:40:24 +0000
277@@ -19,15 +19,18 @@
278 Most functionality of MutableTree is tested as part of WorkingTree.
279 """
280
281-from bzrlib.tests import TestCase
282-from bzrlib.mutabletree import MutableTree, MutableTreeHooks
283-
284-class TestHooks(TestCase):
285+from bzrlib import (
286+ mutabletree,
287+ tests,
288+ )
289+
290+
291+class TestHooks(tests.TestCase):
292
293 def test_constructor(self):
294 """Check that creating a MutableTreeHooks instance has the right
295 defaults."""
296- hooks = MutableTreeHooks()
297+ hooks = mutabletree.MutableTreeHooks()
298 self.assertTrue("start_commit" in hooks,
299 "start_commit not in %s" % hooks)
300 self.assertTrue("post_commit" in hooks,
301@@ -36,7 +39,25 @@
302 def test_installed_hooks_are_MutableTreeHooks(self):
303 """The installed hooks object should be a MutableTreeHooks."""
304 # the installed hooks are saved in self._preserved_hooks.
305- self.assertIsInstance(self._preserved_hooks[MutableTree][1],
306- MutableTreeHooks)
307-
308-
309+ self.assertIsInstance(self._preserved_hooks[mutabletree.MutableTree][1],
310+ mutabletree.MutableTreeHooks)
311+
312+
313+class TestHasChanges(tests.TestCaseWithTransport):
314+
315+ def setUp(self):
316+ super(TestHasChanges, self).setUp()
317+ self.tree = self.make_branch_and_tree('tree')
318+
319+ def test_with_uncommitted_changes(self):
320+ self.build_tree(['tree/file'])
321+ self.tree.add('file')
322+ self.assertTrue(self.tree.has_changes())
323+
324+ def test_with_pending_merges(self):
325+ other_tree = self.tree.bzrdir.sprout('other').open_workingtree()
326+ self.build_tree(['other/file'])
327+ other_tree.add('file')
328+ other_tree.commit('added file')
329+ self.tree.merge_from_branch(other_tree.branch)
330+ self.assertTrue(self.tree.has_changes())
331
332=== modified file 'bzrlib/tests/test_reconfigure.py'
333--- bzrlib/tests/test_reconfigure.py 2009-04-28 20:12:44 +0000
334+++ bzrlib/tests/test_reconfigure.py 2009-10-06 16:40:25 +0000
335@@ -1,4 +1,4 @@
336-# Copyright (C) 2007 Canonical Ltd
337+# Copyright (C) 2007, 2008, 2009 Canonical Ltd
338 #
339 # This program is free software; you can redistribute it and/or modify
340 # it under the terms of the GNU General Public License as published by
341@@ -44,6 +44,19 @@
342 self.assertRaises(errors.NoWorkingTree, workingtree.WorkingTree.open,
343 'tree')
344
345+ def test_tree_with_pending_merge_to_branch(self):
346+ tree = self.make_branch_and_tree('tree')
347+ other_tree = tree.bzrdir.sprout('other').open_workingtree()
348+ self.build_tree(['other/file'])
349+ other_tree.add('file')
350+ other_tree.commit('file added')
351+ tree.merge_from_branch(other_tree.branch)
352+ reconfiguration = reconfigure.Reconfigure.to_branch(tree.bzrdir)
353+ self.assertRaises(errors.UncommittedChanges, reconfiguration.apply)
354+ reconfiguration.apply(force=True)
355+ self.assertRaises(errors.NoWorkingTree, workingtree.WorkingTree.open,
356+ 'tree')
357+
358 def test_branch_to_branch(self):
359 branch = self.make_branch('branch')
360 self.assertRaises(errors.AlreadyBranch,
361
362=== modified file 'bzrlib/tests/test_status.py'
363--- bzrlib/tests/test_status.py 2009-08-20 04:09:58 +0000
364+++ bzrlib/tests/test_status.py 2009-10-06 16:40:24 +0000
365@@ -53,7 +53,7 @@
366 tree2.commit('commit 3b', timestamp=1196796819, timezone=0)
367 tree3.commit('commit 3c', timestamp=1196796819, timezone=0)
368 tree.merge_from_branch(tree2.branch)
369- tree.merge_from_branch(tree3.branch)
370+ tree.merge_from_branch(tree3.branch, force=True)
371 return tree
372
373 def test_multiple_pending(self):
374
375=== modified file 'bzrlib/workingtree.py'
376--- bzrlib/workingtree.py 2009-08-26 05:38:16 +0000
377+++ bzrlib/workingtree.py 2009-10-06 16:40:25 +0000
378@@ -896,7 +896,7 @@
379
380 @needs_write_lock # because merge pulls data into the branch.
381 def merge_from_branch(self, branch, to_revision=None, from_revision=None,
382- merge_type=None):
383+ merge_type=None, force=False):
384 """Merge from a branch into this working tree.
385
386 :param branch: The branch to merge from.
387@@ -911,9 +911,9 @@
388 merger = Merger(self.branch, this_tree=self, pb=pb)
389 merger.pp = ProgressPhase("Merge phase", 5, pb)
390 merger.pp.next_phase()
391- # check that there are no
392- # local alterations
393- merger.check_basis(check_clean=True, require_commits=False)
394+ # check that there are no local alterations
395+ if not force and self.has_changes():
396+ raise errors.UncommittedChanges(self)
397 if to_revision is None:
398 to_revision = _mod_revision.ensure_null(branch.last_revision())
399 merger.other_rev_id = to_revision