Merge lp:~mhammond/bzr/update-r into lp:~bzr/bzr/trunk-old
- update-r
- Merge into 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 | ||||
Related bugs: |
|
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.
Commit message
Description of the change
To post a comment you must log in.
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
1 | === modified file 'NEWS' |
2 | --- NEWS 2009-08-30 23:51:10 +0000 |
3 | +++ NEWS 2009-08-31 04:37:51 +0000 |
4 | @@ -1,5 +1,6 @@ |
5 | #################### |
6 | Bazaar Release Notes |
7 | +<<<<<<< TREE |
8 | #################### |
9 | |
10 | |
11 | @@ -3486,6 +3487,68 @@ |
12 | * Fix a regression in knit => pack fetching. We had a logic |
13 | inversion, causing the fetch to insert fulltexts in random order, |
14 | rather than preserving deltas. (John Arbash Meinel, #256757) |
15 | +======= |
16 | +-------------------- |
17 | + |
18 | +.. contents:: |
19 | + |
20 | +IN DEVELOPMENT |
21 | +-------------- |
22 | + |
23 | + CHANGES: |
24 | + |
25 | + * ``bzr export`` can now export a subdirectory of a project. |
26 | + (Robert Collins) |
27 | + |
28 | + * ``bzr rm`` will now scan for files that are missing and remove just |
29 | + them automatically, much as ``bzr add`` scans for new files that |
30 | + are not ignored and adds them automatically. (Robert Collins) |
31 | + |
32 | + IMPROVEMENTS: |
33 | + |
34 | + * ``bzr init`` and ``bzr init-repo`` will now print out the same as |
35 | + ``bzr info`` if it completed successfully. |
36 | + (Marius Kruger) |
37 | + |
38 | + * ``bzr uncommit`` logs the old tip revision id, and displays how to |
39 | + restore the branch to that tip using ``bzr pull``. This allows you |
40 | + to recover if you realize you uncommitted the wrong thing. |
41 | + (John Arbash Meinel) |
42 | + |
43 | + * ``bzr update`` now takes a ``--revision`` argument. This lets you |
44 | + change the revision of the working tree to any revision in the |
45 | + ancestry of the current or master branch. (Matthieu Moy, #45719) |
46 | + |
47 | + BUG FIXES: |
48 | + |
49 | + * ``bzr rm`` is now aliased to ``bzr del`` for the convenience of svn |
50 | + users. (Robert Collins, #205416) |
51 | + |
52 | + * ``WorkingTree4`` trees will now correctly report missing-and-new |
53 | + paths in the output of ``iter_changes``. (Robert Collins) |
54 | + |
55 | + API CHANGES: |
56 | + |
57 | + * Exporters now take 4 parameters. (Robert Collins) |
58 | + |
59 | + * ``Tree.iter_changes`` will now return False for the content change |
60 | + field when a file is missing in the basis tree and not present in |
61 | + the target tree. Previously it returned True unconditionally. |
62 | + (Robert Collins) |
63 | + |
64 | + TESTING: |
65 | + |
66 | + * ``addCleanup`` now takes ``*arguments`` and ``**keyword_arguments`` |
67 | + which are then passed to the cleanup callable as it is run. In |
68 | + addition, addCleanup no longer requires that the callables passed to |
69 | + it be unique. (Jonathan Lange) |
70 | + |
71 | + INTERNALS: |
72 | + |
73 | + * ``bzrlib.diff.DiffTree.show_diff`` now skips changes where the kind |
74 | + is unknown in both source and target. |
75 | + (Robert Collins, Aaron Bentley) |
76 | +>>>>>>> MERGE-SOURCE |
77 | |
78 | |
79 | bzr 1.6rc3 2008-08-14 |
80 | |
81 | === modified file 'bzrlib/builtins.py' |
82 | --- bzrlib/builtins.py 2009-08-28 05:00:33 +0000 |
83 | +++ bzrlib/builtins.py 2009-08-31 04:37:52 +0000 |
84 | @@ -1385,12 +1385,17 @@ |
85 | |
86 | _see_also = ['pull', 'working-trees', 'status-flags'] |
87 | takes_args = ['dir?'] |
88 | + takes_options = ['revision'] |
89 | aliases = ['up'] |
90 | |
91 | - def run(self, dir='.'): |
92 | + def run(self, dir='.', revision=None): |
93 | + if revision is not None and len(revision) != 1: |
94 | + raise errors.BzrCommandError( |
95 | + "bzr update --revision takes exactly one revision") |
96 | tree = WorkingTree.open_containing(dir)[0] |
97 | + branch = tree.branch |
98 | possible_transports = [] |
99 | - master = tree.branch.get_master_branch( |
100 | + master = branch.get_master_branch( |
101 | possible_transports=possible_transports) |
102 | if master is not None: |
103 | tree.lock_write() |
104 | @@ -1398,6 +1403,7 @@ |
105 | tree.lock_tree_write() |
106 | try: |
107 | existing_pending_merges = tree.get_parent_ids()[1:] |
108 | +<<<<<<< TREE |
109 | last_rev = _mod_revision.ensure_null(tree.last_revision()) |
110 | if last_rev == _mod_revision.ensure_null( |
111 | tree.branch.last_revision()): |
112 | @@ -1413,6 +1419,44 @@ |
113 | view_info=view_info), possible_transports=possible_transports) |
114 | revno = tree.branch.revision_id_to_revno( |
115 | _mod_revision.ensure_null(tree.last_revision())) |
116 | +======= |
117 | + # potentially get new revisions from the master branch. |
118 | + # needed for the case where -r N is given, with N not yet |
119 | + # in the local branch for a heavyweight checkout. |
120 | + if revision is not None: |
121 | + try: |
122 | + rev = revision[0].in_history(branch).rev_id |
123 | + # no need to run branch.update() |
124 | + old_tip = None |
125 | + except (errors.NoSuchRevision, errors.InvalidRevisionSpec): |
126 | + # revision was not there, but is maybe in the master. |
127 | + old_tip = branch.update(possible_transports) |
128 | + rev = revision[0].in_history(branch).rev_id |
129 | + else: |
130 | + if master is None: |
131 | + old_tip = None |
132 | + else: |
133 | + old_tip = branch.update(possible_transports) |
134 | + rev = branch.last_revision() |
135 | + if rev == _mod_revision.ensure_null(tree.last_revision()): |
136 | + revno = branch.revision_id_to_revno(rev) |
137 | + note("Tree is up to date at revision %d." % (revno,)) |
138 | + return 0 |
139 | + try: |
140 | + conflicts = tree.update( |
141 | + delta._ChangeReporter(unversioned_filter=tree.is_ignored), |
142 | + possible_transports=possible_transports, |
143 | + revision=rev, |
144 | + old_tip=old_tip) |
145 | + except errors.NoSuchRevision, e: |
146 | + raise errors.BzrCommandError( |
147 | + "branch has no revision %s\n" |
148 | + "bzr update --revision only works" |
149 | + " for a revision in the branch history" |
150 | + % (e.revision)) |
151 | + revno = branch.revision_id_to_revno( |
152 | + _mod_revision.ensure_null(rev)) |
153 | +>>>>>>> MERGE-SOURCE |
154 | note('Updated to revision %d.' % (revno,)) |
155 | if tree.get_parent_ids()[1:] != existing_pending_merges: |
156 | note('Your local commits will now show as pending merges with ' |
157 | |
158 | === modified file 'bzrlib/tests/blackbox/test_update.py' |
159 | --- bzrlib/tests/blackbox/test_update.py 2009-03-23 14:59:43 +0000 |
160 | +++ bzrlib/tests/blackbox/test_update.py 2009-08-31 04:37:52 +0000 |
161 | @@ -209,3 +209,74 @@ |
162 | lightweight=True) |
163 | tree.commit('empty commit') |
164 | self.run_bzr('update checkout') |
165 | + |
166 | + def test_update_dash_r(self): |
167 | + # Test that 'bzr update' works correctly when you have |
168 | + # an update in the master tree, and a lightweight checkout |
169 | + # which has merged another branch |
170 | + master = self.make_branch_and_tree('master') |
171 | + os.chdir('master') |
172 | + self.build_tree(['./file1']) |
173 | + master.add(['file1']) |
174 | + master.commit('one', rev_id='m1') |
175 | + self.build_tree(['./file2']) |
176 | + master.add(['file2']) |
177 | + master.commit('two', rev_id='m2') |
178 | + |
179 | + out, err = self.run_bzr('update -r 1') |
180 | + self.assertEqual('', out) |
181 | + self.assertEqual('-D file2\nAll changes applied successfully.\n' |
182 | + 'Updated to revision 1.\n', err) |
183 | + self.failUnlessExists('./file1') |
184 | + self.failIfExists('./file2') |
185 | + # hrm - the below doesn't look correct for all formats... |
186 | + #self.check_file_contents('.bzr/checkout/last-revision', |
187 | + # 'm1') |
188 | + |
189 | + def test_update_dash_r_outside_history(self): |
190 | + # Test that 'bzr update' works correctly when you have |
191 | + # an update in the master tree, and a lightweight checkout |
192 | + # which has merged another branch |
193 | + master = self.make_branch_and_tree('master') |
194 | + self.build_tree(['master/file1']) |
195 | + master.add(['file1']) |
196 | + master.commit('one', rev_id='m1') |
197 | + |
198 | + # Create a second branch, with an extra commit |
199 | + other = master.bzrdir.sprout('other').open_workingtree() |
200 | + self.build_tree(['other/file2']) |
201 | + other.add(['file2']) |
202 | + other.commit('other2', rev_id='o2') |
203 | + |
204 | + os.chdir('master') |
205 | + self.run_bzr('merge ../other') |
206 | + master.commit('merge', rev_id='merge') |
207 | + |
208 | + out, err = self.run_bzr('update -r revid:o2', |
209 | + retcode=3) |
210 | + self.assertEqual('', out) |
211 | + self.assertEqual('bzr: ERROR: branch has no revision o2\n' |
212 | + 'bzr update --revision only works' |
213 | + ' for a revision in the branch history\n', |
214 | + err) |
215 | + |
216 | + def test_update_dash_r_in_master(self): |
217 | + # Test that 'bzr update' works correctly when you have |
218 | + # an update in the master tree, |
219 | + master = self.make_branch_and_tree('master') |
220 | + self.build_tree(['master/file1']) |
221 | + master.add(['file1']) |
222 | + master.commit('one', rev_id='m1') |
223 | + |
224 | + self.run_bzr('checkout master checkout') |
225 | + |
226 | + # add a revision in the master. |
227 | + self.build_tree(['master/file2']) |
228 | + master.add(['file2']) |
229 | + master.commit('two', rev_id='m2') |
230 | + |
231 | + os.chdir('checkout') |
232 | + out, err = self.run_bzr('update -r revid:m2') |
233 | + self.assertEqual('', out) |
234 | + self.assertEqual('+N file2\nAll changes applied successfully.\n' |
235 | + 'Updated to revision 2.\n', err) |
236 | |
237 | === modified file 'bzrlib/workingtree.py' |
238 | --- bzrlib/workingtree.py 2009-08-26 05:38:16 +0000 |
239 | +++ bzrlib/workingtree.py 2009-08-31 04:37:52 +0000 |
240 | @@ -2177,7 +2177,10 @@ |
241 | """ |
242 | raise NotImplementedError(self.unlock) |
243 | |
244 | - def update(self, change_reporter=None, possible_transports=None): |
245 | + _marker = object() |
246 | + |
247 | + def update(self, change_reporter=None, possible_transports=None, |
248 | + revision=None, old_tip=_marker): |
249 | """Update a working tree along its branch. |
250 | |
251 | This will update the branch if its bound too, which means we have |
252 | @@ -2201,10 +2204,16 @@ |
253 | - Merge current state -> basis tree of the master w.r.t. the old tree |
254 | basis. |
255 | - Do a 'normal' merge of the old branch basis if it is relevant. |
256 | + |
257 | + :param revision: The target revision to update to. Must be in the |
258 | + revision history. |
259 | + :param old_tip: If branch.update() has already been run, the value it |
260 | + returned (old tip of the branch or None). _marker is used |
261 | + otherwise. |
262 | """ |
263 | if self.branch.get_bound_location() is not None: |
264 | self.lock_write() |
265 | - update_branch = True |
266 | + update_branch = (old_tip is self._marker) |
267 | else: |
268 | self.lock_tree_write() |
269 | update_branch = False |
270 | @@ -2212,13 +2221,14 @@ |
271 | if update_branch: |
272 | old_tip = self.branch.update(possible_transports) |
273 | else: |
274 | - old_tip = None |
275 | - return self._update_tree(old_tip, change_reporter) |
276 | + if old_tip is self._marker: |
277 | + old_tip = None |
278 | + return self._update_tree(old_tip, change_reporter, revision) |
279 | finally: |
280 | self.unlock() |
281 | |
282 | @needs_tree_write_lock |
283 | - def _update_tree(self, old_tip=None, change_reporter=None): |
284 | + def _update_tree(self, old_tip=None, change_reporter=None, revision=None): |
285 | """Update a tree to the master branch. |
286 | |
287 | :param old_tip: if supplied, the previous tip revision the branch, |
288 | @@ -2239,12 +2249,17 @@ |
289 | last_rev = self.get_parent_ids()[0] |
290 | except IndexError: |
291 | last_rev = _mod_revision.NULL_REVISION |
292 | - if last_rev != _mod_revision.ensure_null(self.branch.last_revision()): |
293 | - # merge tree state up to new branch tip. |
294 | + if revision is None: |
295 | + revision = self.branch.last_revision() |
296 | + else: |
297 | + if revision not in self.branch.revision_history(): |
298 | + raise errors.NoSuchRevision(self.branch, revision) |
299 | + if last_rev != _mod_revision.ensure_null(revision): |
300 | + # merge tree state up to specified revision. |
301 | basis = self.basis_tree() |
302 | basis.lock_read() |
303 | try: |
304 | - to_tree = self.branch.basis_tree() |
305 | + to_tree = self.branch.repository.revision_tree(revision) |
306 | if basis.inventory.root is None: |
307 | self.set_root_id(to_tree.get_root_id()) |
308 | self.flush() |
309 | @@ -2254,11 +2269,12 @@ |
310 | basis, |
311 | this_tree=self, |
312 | change_reporter=change_reporter) |
313 | + self.set_last_revision(revision) |
314 | finally: |
315 | basis.unlock() |
316 | # TODO - dedup parents list with things merged by pull ? |
317 | # reuse the tree we've updated to to set the basis: |
318 | - parent_trees = [(self.branch.last_revision(), to_tree)] |
319 | + parent_trees = [(revision, to_tree)] |
320 | merges = self.get_parent_ids()[1:] |
321 | # Ideally we ask the tree for the trees here, that way the working |
322 | # tree can decide whether to give us the entire tree or give us a |
323 | @@ -2294,8 +2310,7 @@ |
324 | # should be able to remove this extra flush. |
325 | self.flush() |
326 | graph = self.branch.repository.get_graph() |
327 | - base_rev_id = graph.find_unique_lca(self.branch.last_revision(), |
328 | - old_tip) |
329 | + base_rev_id = graph.find_unique_lca(revision, old_tip) |
330 | base_tree = self.branch.repository.revision_tree(base_rev_id) |
331 | other_tree = self.branch.repository.revision_tree(old_tip) |
332 | result += merge.merge_inner( |
I just resubmitted this, because I wanted it to generate a diff that I could then look over to actually do a review.