Merge lp:~mhammond/bzr/update-r into lp:~bzr/bzr/trunk-old

Proposed by John A Meinel
Status: Rejected
Rejected by: Martin Pool
Proposed branch: lp:~mhammond/bzr/update-r
Merge into: lp:~bzr/bzr/trunk-old
Diff against target: 332 lines (has conflicts)
Text conflict in NEWS
Text conflict in bzrlib/builtins.py
To merge this branch: bzr merge lp:~mhammond/bzr/update-r
Reviewer Review Type Date Requested Status
John A Meinel Needs Information
Review via email: mp+6980@code.launchpad.net

This proposal supersedes a proposal from 2008-08-24.

To post a comment you must log in.
Revision history for this message
John A Meinel (jameinel) wrote :

I just resubmitted this, because I wanted it to generate a diff that I could then look over to actually do a review.

review: Needs Information
Revision history for this message
Martin Pool (mbp) wrote :

It would be good to merge this feature.

One comment - the code in cmd_update is getting large enough that it might be good to move it to a non-cli-specific place, so that method does not get too large and so that it can be reused by other interfaces.

Revision history for this message
Martin Pool (mbp) wrote :

I'll close this patch, but work on it myself as (kinda) patch pilot.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'NEWS'
--- NEWS 2009-08-30 23:51:10 +0000
+++ NEWS 2009-08-31 04:37:51 +0000
@@ -1,5 +1,6 @@
1####################1####################
2Bazaar Release Notes2Bazaar Release Notes
3<<<<<<< TREE
3####################4####################
45
56
@@ -3486,6 +3487,68 @@
3486* Fix a regression in knit => pack fetching. We had a logic3487* Fix a regression in knit => pack fetching. We had a logic
3487 inversion, causing the fetch to insert fulltexts in random order,3488 inversion, causing the fetch to insert fulltexts in random order,
3488 rather than preserving deltas. (John Arbash Meinel, #256757)3489 rather than preserving deltas. (John Arbash Meinel, #256757)
3490=======
3491--------------------
3492
3493.. contents::
3494
3495IN DEVELOPMENT
3496--------------
3497
3498 CHANGES:
3499
3500 * ``bzr export`` can now export a subdirectory of a project.
3501 (Robert Collins)
3502
3503 * ``bzr rm`` will now scan for files that are missing and remove just
3504 them automatically, much as ``bzr add`` scans for new files that
3505 are not ignored and adds them automatically. (Robert Collins)
3506
3507 IMPROVEMENTS:
3508
3509 * ``bzr init`` and ``bzr init-repo`` will now print out the same as
3510 ``bzr info`` if it completed successfully.
3511 (Marius Kruger)
3512
3513 * ``bzr uncommit`` logs the old tip revision id, and displays how to
3514 restore the branch to that tip using ``bzr pull``. This allows you
3515 to recover if you realize you uncommitted the wrong thing.
3516 (John Arbash Meinel)
3517
3518 * ``bzr update`` now takes a ``--revision`` argument. This lets you
3519 change the revision of the working tree to any revision in the
3520 ancestry of the current or master branch. (Matthieu Moy, #45719)
3521
3522 BUG FIXES:
3523
3524 * ``bzr rm`` is now aliased to ``bzr del`` for the convenience of svn
3525 users. (Robert Collins, #205416)
3526
3527 * ``WorkingTree4`` trees will now correctly report missing-and-new
3528 paths in the output of ``iter_changes``. (Robert Collins)
3529
3530 API CHANGES:
3531
3532 * Exporters now take 4 parameters. (Robert Collins)
3533
3534 * ``Tree.iter_changes`` will now return False for the content change
3535 field when a file is missing in the basis tree and not present in
3536 the target tree. Previously it returned True unconditionally.
3537 (Robert Collins)
3538
3539 TESTING:
3540
3541 * ``addCleanup`` now takes ``*arguments`` and ``**keyword_arguments``
3542 which are then passed to the cleanup callable as it is run. In
3543 addition, addCleanup no longer requires that the callables passed to
3544 it be unique. (Jonathan Lange)
3545
3546 INTERNALS:
3547
3548 * ``bzrlib.diff.DiffTree.show_diff`` now skips changes where the kind
3549 is unknown in both source and target.
3550 (Robert Collins, Aaron Bentley)
3551>>>>>>> MERGE-SOURCE
34893552
34903553
3491bzr 1.6rc3 2008-08-143554bzr 1.6rc3 2008-08-14
34923555
=== modified file 'bzrlib/builtins.py'
--- bzrlib/builtins.py 2009-08-28 05:00:33 +0000
+++ bzrlib/builtins.py 2009-08-31 04:37:52 +0000
@@ -1385,12 +1385,17 @@
13851385
1386 _see_also = ['pull', 'working-trees', 'status-flags']1386 _see_also = ['pull', 'working-trees', 'status-flags']
1387 takes_args = ['dir?']1387 takes_args = ['dir?']
1388 takes_options = ['revision']
1388 aliases = ['up']1389 aliases = ['up']
13891390
1390 def run(self, dir='.'):1391 def run(self, dir='.', revision=None):
1392 if revision is not None and len(revision) != 1:
1393 raise errors.BzrCommandError(
1394 "bzr update --revision takes exactly one revision")
1391 tree = WorkingTree.open_containing(dir)[0]1395 tree = WorkingTree.open_containing(dir)[0]
1396 branch = tree.branch
1392 possible_transports = []1397 possible_transports = []
1393 master = tree.branch.get_master_branch(1398 master = branch.get_master_branch(
1394 possible_transports=possible_transports)1399 possible_transports=possible_transports)
1395 if master is not None:1400 if master is not None:
1396 tree.lock_write()1401 tree.lock_write()
@@ -1398,6 +1403,7 @@
1398 tree.lock_tree_write()1403 tree.lock_tree_write()
1399 try:1404 try:
1400 existing_pending_merges = tree.get_parent_ids()[1:]1405 existing_pending_merges = tree.get_parent_ids()[1:]
1406<<<<<<< TREE
1401 last_rev = _mod_revision.ensure_null(tree.last_revision())1407 last_rev = _mod_revision.ensure_null(tree.last_revision())
1402 if last_rev == _mod_revision.ensure_null(1408 if last_rev == _mod_revision.ensure_null(
1403 tree.branch.last_revision()):1409 tree.branch.last_revision()):
@@ -1413,6 +1419,44 @@
1413 view_info=view_info), possible_transports=possible_transports)1419 view_info=view_info), possible_transports=possible_transports)
1414 revno = tree.branch.revision_id_to_revno(1420 revno = tree.branch.revision_id_to_revno(
1415 _mod_revision.ensure_null(tree.last_revision()))1421 _mod_revision.ensure_null(tree.last_revision()))
1422=======
1423 # potentially get new revisions from the master branch.
1424 # needed for the case where -r N is given, with N not yet
1425 # in the local branch for a heavyweight checkout.
1426 if revision is not None:
1427 try:
1428 rev = revision[0].in_history(branch).rev_id
1429 # no need to run branch.update()
1430 old_tip = None
1431 except (errors.NoSuchRevision, errors.InvalidRevisionSpec):
1432 # revision was not there, but is maybe in the master.
1433 old_tip = branch.update(possible_transports)
1434 rev = revision[0].in_history(branch).rev_id
1435 else:
1436 if master is None:
1437 old_tip = None
1438 else:
1439 old_tip = branch.update(possible_transports)
1440 rev = branch.last_revision()
1441 if rev == _mod_revision.ensure_null(tree.last_revision()):
1442 revno = branch.revision_id_to_revno(rev)
1443 note("Tree is up to date at revision %d." % (revno,))
1444 return 0
1445 try:
1446 conflicts = tree.update(
1447 delta._ChangeReporter(unversioned_filter=tree.is_ignored),
1448 possible_transports=possible_transports,
1449 revision=rev,
1450 old_tip=old_tip)
1451 except errors.NoSuchRevision, e:
1452 raise errors.BzrCommandError(
1453 "branch has no revision %s\n"
1454 "bzr update --revision only works"
1455 " for a revision in the branch history"
1456 % (e.revision))
1457 revno = branch.revision_id_to_revno(
1458 _mod_revision.ensure_null(rev))
1459>>>>>>> MERGE-SOURCE
1416 note('Updated to revision %d.' % (revno,))1460 note('Updated to revision %d.' % (revno,))
1417 if tree.get_parent_ids()[1:] != existing_pending_merges:1461 if tree.get_parent_ids()[1:] != existing_pending_merges:
1418 note('Your local commits will now show as pending merges with '1462 note('Your local commits will now show as pending merges with '
14191463
=== modified file 'bzrlib/tests/blackbox/test_update.py'
--- bzrlib/tests/blackbox/test_update.py 2009-03-23 14:59:43 +0000
+++ bzrlib/tests/blackbox/test_update.py 2009-08-31 04:37:52 +0000
@@ -209,3 +209,74 @@
209 lightweight=True)209 lightweight=True)
210 tree.commit('empty commit')210 tree.commit('empty commit')
211 self.run_bzr('update checkout')211 self.run_bzr('update checkout')
212
213 def test_update_dash_r(self):
214 # Test that 'bzr update' works correctly when you have
215 # an update in the master tree, and a lightweight checkout
216 # which has merged another branch
217 master = self.make_branch_and_tree('master')
218 os.chdir('master')
219 self.build_tree(['./file1'])
220 master.add(['file1'])
221 master.commit('one', rev_id='m1')
222 self.build_tree(['./file2'])
223 master.add(['file2'])
224 master.commit('two', rev_id='m2')
225
226 out, err = self.run_bzr('update -r 1')
227 self.assertEqual('', out)
228 self.assertEqual('-D file2\nAll changes applied successfully.\n'
229 'Updated to revision 1.\n', err)
230 self.failUnlessExists('./file1')
231 self.failIfExists('./file2')
232 # hrm - the below doesn't look correct for all formats...
233 #self.check_file_contents('.bzr/checkout/last-revision',
234 # 'm1')
235
236 def test_update_dash_r_outside_history(self):
237 # Test that 'bzr update' works correctly when you have
238 # an update in the master tree, and a lightweight checkout
239 # which has merged another branch
240 master = self.make_branch_and_tree('master')
241 self.build_tree(['master/file1'])
242 master.add(['file1'])
243 master.commit('one', rev_id='m1')
244
245 # Create a second branch, with an extra commit
246 other = master.bzrdir.sprout('other').open_workingtree()
247 self.build_tree(['other/file2'])
248 other.add(['file2'])
249 other.commit('other2', rev_id='o2')
250
251 os.chdir('master')
252 self.run_bzr('merge ../other')
253 master.commit('merge', rev_id='merge')
254
255 out, err = self.run_bzr('update -r revid:o2',
256 retcode=3)
257 self.assertEqual('', out)
258 self.assertEqual('bzr: ERROR: branch has no revision o2\n'
259 'bzr update --revision only works'
260 ' for a revision in the branch history\n',
261 err)
262
263 def test_update_dash_r_in_master(self):
264 # Test that 'bzr update' works correctly when you have
265 # an update in the master tree,
266 master = self.make_branch_and_tree('master')
267 self.build_tree(['master/file1'])
268 master.add(['file1'])
269 master.commit('one', rev_id='m1')
270
271 self.run_bzr('checkout master checkout')
272
273 # add a revision in the master.
274 self.build_tree(['master/file2'])
275 master.add(['file2'])
276 master.commit('two', rev_id='m2')
277
278 os.chdir('checkout')
279 out, err = self.run_bzr('update -r revid:m2')
280 self.assertEqual('', out)
281 self.assertEqual('+N file2\nAll changes applied successfully.\n'
282 'Updated to revision 2.\n', err)
212283
=== modified file 'bzrlib/workingtree.py'
--- bzrlib/workingtree.py 2009-08-26 05:38:16 +0000
+++ bzrlib/workingtree.py 2009-08-31 04:37:52 +0000
@@ -2177,7 +2177,10 @@
2177 """2177 """
2178 raise NotImplementedError(self.unlock)2178 raise NotImplementedError(self.unlock)
21792179
2180 def update(self, change_reporter=None, possible_transports=None):2180 _marker = object()
2181
2182 def update(self, change_reporter=None, possible_transports=None,
2183 revision=None, old_tip=_marker):
2181 """Update a working tree along its branch.2184 """Update a working tree along its branch.
21822185
2183 This will update the branch if its bound too, which means we have2186 This will update the branch if its bound too, which means we have
@@ -2201,10 +2204,16 @@
2201 - Merge current state -> basis tree of the master w.r.t. the old tree2204 - Merge current state -> basis tree of the master w.r.t. the old tree
2202 basis.2205 basis.
2203 - Do a 'normal' merge of the old branch basis if it is relevant.2206 - Do a 'normal' merge of the old branch basis if it is relevant.
2207
2208 :param revision: The target revision to update to. Must be in the
2209 revision history.
2210 :param old_tip: If branch.update() has already been run, the value it
2211 returned (old tip of the branch or None). _marker is used
2212 otherwise.
2204 """2213 """
2205 if self.branch.get_bound_location() is not None:2214 if self.branch.get_bound_location() is not None:
2206 self.lock_write()2215 self.lock_write()
2207 update_branch = True2216 update_branch = (old_tip is self._marker)
2208 else:2217 else:
2209 self.lock_tree_write()2218 self.lock_tree_write()
2210 update_branch = False2219 update_branch = False
@@ -2212,13 +2221,14 @@
2212 if update_branch:2221 if update_branch:
2213 old_tip = self.branch.update(possible_transports)2222 old_tip = self.branch.update(possible_transports)
2214 else:2223 else:
2215 old_tip = None2224 if old_tip is self._marker:
2216 return self._update_tree(old_tip, change_reporter)2225 old_tip = None
2226 return self._update_tree(old_tip, change_reporter, revision)
2217 finally:2227 finally:
2218 self.unlock()2228 self.unlock()
22192229
2220 @needs_tree_write_lock2230 @needs_tree_write_lock
2221 def _update_tree(self, old_tip=None, change_reporter=None):2231 def _update_tree(self, old_tip=None, change_reporter=None, revision=None):
2222 """Update a tree to the master branch.2232 """Update a tree to the master branch.
22232233
2224 :param old_tip: if supplied, the previous tip revision the branch,2234 :param old_tip: if supplied, the previous tip revision the branch,
@@ -2239,12 +2249,17 @@
2239 last_rev = self.get_parent_ids()[0]2249 last_rev = self.get_parent_ids()[0]
2240 except IndexError:2250 except IndexError:
2241 last_rev = _mod_revision.NULL_REVISION2251 last_rev = _mod_revision.NULL_REVISION
2242 if last_rev != _mod_revision.ensure_null(self.branch.last_revision()):2252 if revision is None:
2243 # merge tree state up to new branch tip.2253 revision = self.branch.last_revision()
2254 else:
2255 if revision not in self.branch.revision_history():
2256 raise errors.NoSuchRevision(self.branch, revision)
2257 if last_rev != _mod_revision.ensure_null(revision):
2258 # merge tree state up to specified revision.
2244 basis = self.basis_tree()2259 basis = self.basis_tree()
2245 basis.lock_read()2260 basis.lock_read()
2246 try:2261 try:
2247 to_tree = self.branch.basis_tree()2262 to_tree = self.branch.repository.revision_tree(revision)
2248 if basis.inventory.root is None:2263 if basis.inventory.root is None:
2249 self.set_root_id(to_tree.get_root_id())2264 self.set_root_id(to_tree.get_root_id())
2250 self.flush()2265 self.flush()
@@ -2254,11 +2269,12 @@
2254 basis,2269 basis,
2255 this_tree=self,2270 this_tree=self,
2256 change_reporter=change_reporter)2271 change_reporter=change_reporter)
2272 self.set_last_revision(revision)
2257 finally:2273 finally:
2258 basis.unlock()2274 basis.unlock()
2259 # TODO - dedup parents list with things merged by pull ?2275 # TODO - dedup parents list with things merged by pull ?
2260 # reuse the tree we've updated to to set the basis:2276 # reuse the tree we've updated to to set the basis:
2261 parent_trees = [(self.branch.last_revision(), to_tree)]2277 parent_trees = [(revision, to_tree)]
2262 merges = self.get_parent_ids()[1:]2278 merges = self.get_parent_ids()[1:]
2263 # Ideally we ask the tree for the trees here, that way the working2279 # Ideally we ask the tree for the trees here, that way the working
2264 # tree can decide whether to give us the entire tree or give us a2280 # tree can decide whether to give us the entire tree or give us a
@@ -2294,8 +2310,7 @@
2294 # should be able to remove this extra flush.2310 # should be able to remove this extra flush.
2295 self.flush()2311 self.flush()
2296 graph = self.branch.repository.get_graph()2312 graph = self.branch.repository.get_graph()
2297 base_rev_id = graph.find_unique_lca(self.branch.last_revision(),2313 base_rev_id = graph.find_unique_lca(revision, old_tip)
2298 old_tip)
2299 base_tree = self.branch.repository.revision_tree(base_rev_id)2314 base_tree = self.branch.repository.revision_tree(base_rev_id)
2300 other_tree = self.branch.repository.revision_tree(old_tip)2315 other_tree = self.branch.repository.revision_tree(old_tip)
2301 result += merge.merge_inner(2316 result += merge.merge_inner(