Merge lp:~jelmer/bzr/result-mentions-tags into lp:bzr

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merged at revision: 6125
Proposed branch: lp:~jelmer/bzr/result-mentions-tags
Merge into: lp:bzr
Diff against target: 447 lines (+102/-45)
12 files modified
bzrlib/branch.py (+32/-12)
bzrlib/commit.py (+2/-1)
bzrlib/tag.py (+21/-14)
bzrlib/tests/blackbox/test_non_ascii.py (+1/-1)
bzrlib/tests/blackbox/test_pull.py (+11/-1)
bzrlib/tests/blackbox/test_push.py (+3/-1)
bzrlib/tests/per_branch/test_pull.py (+1/-1)
bzrlib/tests/per_branch/test_tags.py (+19/-10)
bzrlib/tests/per_interbranch/test_pull.py (+1/-1)
bzrlib/tests/test_branch.py (+1/-1)
bzrlib/tests/test_tag.py (+4/-2)
doc/en/release-notes/bzr-2.5.txt (+6/-0)
To merge this branch: bzr merge lp:~jelmer/bzr/result-mentions-tags
Reviewer Review Type Date Requested Status
Vincent Ladeuil Needs Fixing
Review via email: mp+73564@code.launchpad.net

Commit message

Mention the number of tags that was pushed/pull, if any.

Description of the change

Mention the number of tags that was pushed/pull, if any.

To post a comment you must log in.
Revision history for this message
Vincent Ladeuil (vila) wrote :

[needsinfo] It seems merge_to changes caused problems in the past
(see bzrlib.tags._merge_tags_if_possible), what's your feeling on
changing the signature again and the possible fallouts ? (loom ?)

Or did I misread the diff and merge_to didn't return anything
before ? Or does it matter nevertheless ?

[needsfixing] There is a lot of duplication between
PullResult.report() and BranchPushResult.report()

But one is using to_file_write.write() and the other
trace.note(). This doesn't feel right, shouldn't they both
provide the same feedback to the user ?

[PEP8 nit]
75 + result.tag_updates, result.tag_conflicts = self.source.tags.merge_to(
76 + self.target.tags, overwrite, ignore_master=not merge_tags_to_master)

lines too long.

[2.4-worthy] Shouldn't that be backported for the benefit of the
package importer ?

review: Needs Fixing
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

I've filed a bug about the output inconsistency between "bzr pull" / "bzr push" and added a note in the code. r=vila on IRC.

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

sent to pqm by email

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

sent to pqm by email

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

sent to pqm by email

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bzrlib/branch.py'
--- bzrlib/branch.py 2011-08-27 16:59:43 +0000
+++ bzrlib/branch.py 2011-09-02 00:55:08 +0000
@@ -3044,6 +3044,7 @@
3044 :ivar local_branch: target branch if there is a Master, else None3044 :ivar local_branch: target branch if there is a Master, else None
3045 :ivar target_branch: Target/destination branch object. (write locked)3045 :ivar target_branch: Target/destination branch object. (write locked)
3046 :ivar tag_conflicts: A list of tag conflicts, see BasicTags.merge_to3046 :ivar tag_conflicts: A list of tag conflicts, see BasicTags.merge_to
3047 :ivar tag_updates: A dict with new tags, see BasicTags.merge_to
3047 """3048 """
30483049
3049 @deprecated_method(deprecated_in((2, 3, 0)))3050 @deprecated_method(deprecated_in((2, 3, 0)))
@@ -3055,11 +3056,18 @@
3055 return self.new_revno - self.old_revno3056 return self.new_revno - self.old_revno
30563057
3057 def report(self, to_file):3058 def report(self, to_file):
3059 tag_conflicts = getattr(self, "tag_conflicts", None)
3060 tag_updates = getattr(self, "tag_updates", None)
3058 if not is_quiet():3061 if not is_quiet():
3059 if self.old_revid == self.new_revid:3062 if self.old_revid != self.new_revid:
3060 to_file.write('No revisions to pull.\n')
3061 else:
3062 to_file.write('Now on revision %d.\n' % self.new_revno)3063 to_file.write('Now on revision %d.\n' % self.new_revno)
3064 if tag_updates:
3065 to_file.write('%d tag(s) updated.\n' % len(tag_updates))
3066 if self.old_revid == self.new_revid and not tag_updates:
3067 if not tag_conflicts:
3068 to_file.write('No revisions or tags to pull.\n')
3069 else:
3070 to_file.write('No revisions to pull.\n')
3063 self._show_tag_conficts(to_file)3071 self._show_tag_conficts(to_file)
30643072
30653073
@@ -3091,11 +3099,22 @@
3091 return self.new_revno - self.old_revno3099 return self.new_revno - self.old_revno
30923100
3093 def report(self, to_file):3101 def report(self, to_file):
3094 """Write a human-readable description of the result."""3102 # TODO: This function gets passed a to_file, but then
3095 if self.old_revid == self.new_revid:3103 # ignores it and calls note() instead. This is also
3096 note('No new revisions to push.')3104 # inconsistent with PullResult(), which writes to stdout.
3097 else:3105 # -- JRV20110901, bug #838853
3098 note('Pushed up to revision %d.' % self.new_revno)3106 tag_conflicts = getattr(self, "tag_conflicts", None)
3107 tag_updates = getattr(self, "tag_updates", None)
3108 if not is_quiet():
3109 if self.old_revid != self.new_revid:
3110 note('Pushed up to revision %d.' % self.new_revno)
3111 if tag_updates:
3112 note('%d tag(s) updated.' % len(tag_updates))
3113 if self.old_revid == self.new_revid and not tag_updates:
3114 if not tag_conflicts:
3115 note('No new revisions or tags to push.')
3116 else:
3117 note('No new revisions to push.')
3099 self._show_tag_conficts(to_file)3118 self._show_tag_conficts(to_file)
31003119
31013120
@@ -3409,8 +3428,8 @@
3409 self._update_revisions(stop_revision, overwrite=overwrite,3428 self._update_revisions(stop_revision, overwrite=overwrite,
3410 graph=graph)3429 graph=graph)
3411 if self.source._push_should_merge_tags():3430 if self.source._push_should_merge_tags():
3412 result.tag_conflicts = self.source.tags.merge_to(self.target.tags,3431 result.tag_updates, result.tag_conflicts = (
3413 overwrite)3432 self.source.tags.merge_to(self.target.tags, overwrite))
3414 result.new_revno, result.new_revid = self.target.last_revision_info()3433 result.new_revno, result.new_revid = self.target.last_revision_info()
3415 return result3434 return result
34163435
@@ -3499,8 +3518,9 @@
3499 # TODO: The old revid should be specified when merging tags, 3518 # TODO: The old revid should be specified when merging tags,
3500 # so a tags implementation that versions tags can only 3519 # so a tags implementation that versions tags can only
3501 # pull in the most recent changes. -- JRV200905063520 # pull in the most recent changes. -- JRV20090506
3502 result.tag_conflicts = self.source.tags.merge_to(self.target.tags,3521 result.tag_updates, result.tag_conflicts = (
3503 overwrite, ignore_master=not merge_tags_to_master)3522 self.source.tags.merge_to(self.target.tags, overwrite,
3523 ignore_master=not merge_tags_to_master))
3504 result.new_revno, result.new_revid = self.target.last_revision_info()3524 result.new_revno, result.new_revid = self.target.last_revision_info()
3505 if _hook_master:3525 if _hook_master:
3506 result.master_branch = _hook_master3526 result.master_branch = _hook_master
35073527
=== modified file 'bzrlib/commit.py'
--- bzrlib/commit.py 2011-06-28 17:25:26 +0000
+++ bzrlib/commit.py 2011-09-02 00:55:08 +0000
@@ -464,7 +464,8 @@
464 # Merge local tags to remote464 # Merge local tags to remote
465 if self.bound_branch:465 if self.bound_branch:
466 self._set_progress_stage("Merging tags to master branch")466 self._set_progress_stage("Merging tags to master branch")
467 tag_conflicts = self.branch.tags.merge_to(self.master_branch.tags)467 tag_updates, tag_conflicts = self.branch.tags.merge_to(
468 self.master_branch.tags)
468 if tag_conflicts:469 if tag_conflicts:
469 warning_lines = [' ' + name for name, _, _ in tag_conflicts]470 warning_lines = [' ' + name for name, _, _ in tag_conflicts]
470 note("Conflicting tags in bound branch:\n" +471 note("Conflicting tags in bound branch:\n" +
471472
=== modified file 'bzrlib/tag.py'
--- bzrlib/tag.py 2011-05-18 16:42:48 +0000
+++ bzrlib/tag.py 2011-09-02 00:55:08 +0000
@@ -68,7 +68,7 @@
6868
69 def merge_to(self, to_tags, overwrite=False, ignore_master=False):69 def merge_to(self, to_tags, overwrite=False, ignore_master=False):
70 # we never have anything to copy70 # we never have anything to copy
71 pass71 return {}, []
7272
73 def rename_revisions(self, rename_map):73 def rename_revisions(self, rename_map):
74 # No tags, so nothing to rename74 # No tags, so nothing to rename
@@ -201,7 +201,10 @@
201 branch (if any). Default is false (so the master will be updated).201 branch (if any). Default is false (so the master will be updated).
202 New in bzr 2.3.202 New in bzr 2.3.
203203
204 :returns: A set of tags that conflicted, each of which is204 :returns: Tuple with tag_updates and tag_conflicts.
205 tag_updates is a dictionary with new tags, None is used for
206 removed tags
207 tag_conflicts is a set of tags that conflicted, each of which is
205 (tagname, source_target, dest_target), or None if no copying was208 (tagname, source_target, dest_target), or None if no copying was
206 done.209 done.
207 """210 """
@@ -211,15 +214,15 @@
211 def _merge_to_operation(self, operation, to_tags, overwrite, ignore_master):214 def _merge_to_operation(self, operation, to_tags, overwrite, ignore_master):
212 add_cleanup = operation.add_cleanup215 add_cleanup = operation.add_cleanup
213 if self.branch == to_tags.branch:216 if self.branch == to_tags.branch:
214 return217 return {}, []
215 if not self.branch.supports_tags():218 if not self.branch.supports_tags():
216 # obviously nothing to copy219 # obviously nothing to copy
217 return220 return {}, []
218 source_dict = self.get_tag_dict()221 source_dict = self.get_tag_dict()
219 if not source_dict:222 if not source_dict:
220 # no tags in the source, and we don't want to clobber anything223 # no tags in the source, and we don't want to clobber anything
221 # that's in the destination224 # that's in the destination
222 return225 return {}, []
223 # We merge_to both master and child individually.226 # We merge_to both master and child individually.
224 #227 #
225 # It's possible for master and child to have differing sets of228 # It's possible for master and child to have differing sets of
@@ -239,21 +242,23 @@
239 master = to_tags.branch.get_master_branch()242 master = to_tags.branch.get_master_branch()
240 if master is not None:243 if master is not None:
241 add_cleanup(master.lock_write().unlock)244 add_cleanup(master.lock_write().unlock)
242 conflicts = self._merge_to(to_tags, source_dict, overwrite)245 updates, conflicts = self._merge_to(to_tags, source_dict, overwrite)
243 if master is not None:246 if master is not None:
244 conflicts += self._merge_to(master.tags, source_dict,247 extra_updates, extra_conflicts = self._merge_to(master.tags,
245 overwrite)248 source_dict, overwrite)
249 updates.update(extra_updates)
250 conflicts += extra_conflicts
246 # We use set() to remove any duplicate conflicts from the master251 # We use set() to remove any duplicate conflicts from the master
247 # branch.252 # branch.
248 return set(conflicts)253 return updates, set(conflicts)
249254
250 def _merge_to(self, to_tags, source_dict, overwrite):255 def _merge_to(self, to_tags, source_dict, overwrite):
251 dest_dict = to_tags.get_tag_dict()256 dest_dict = to_tags.get_tag_dict()
252 result, conflicts = self._reconcile_tags(source_dict, dest_dict,257 result, updates, conflicts = self._reconcile_tags(source_dict,
253 overwrite)258 dest_dict, overwrite)
254 if result != dest_dict:259 if result != dest_dict:
255 to_tags._set_tag_dict(result)260 to_tags._set_tag_dict(result)
256 return conflicts261 return updates, conflicts
257262
258 def rename_revisions(self, rename_map):263 def rename_revisions(self, rename_map):
259 """Rename revisions in this tags dictionary.264 """Rename revisions in this tags dictionary.
@@ -275,19 +280,21 @@
275 * different definitions => if overwrite is False, keep destination280 * different definitions => if overwrite is False, keep destination
276 value and give a warning, otherwise use the source value281 value and give a warning, otherwise use the source value
277282
278 :returns: (result_dict,283 :returns: (result_dict, updates,
279 [(conflicting_tag, source_target, dest_target)])284 [(conflicting_tag, source_target, dest_target)])
280 """285 """
281 conflicts = []286 conflicts = []
287 updates = {}
282 result = dict(dest_dict) # copy288 result = dict(dest_dict) # copy
283 for name, target in source_dict.items():289 for name, target in source_dict.items():
284 if name not in result or overwrite:290 if name not in result or overwrite:
285 result[name] = target291 result[name] = target
292 updates[name] = target
286 elif result[name] == target:293 elif result[name] == target:
287 pass294 pass
288 else:295 else:
289 conflicts.append((name, target, result[name]))296 conflicts.append((name, target, result[name]))
290 return result, conflicts297 return result, updates, conflicts
291298
292299
293def _merge_tags_if_possible(from_branch, to_branch, ignore_master=False):300def _merge_tags_if_possible(from_branch, to_branch, ignore_master=False):
294301
=== modified file 'bzrlib/tests/blackbox/test_non_ascii.py'
--- bzrlib/tests/blackbox/test_non_ascii.py 2011-08-04 00:17:53 +0000
+++ bzrlib/tests/blackbox/test_non_ascii.py 2011-09-02 00:55:08 +0000
@@ -267,7 +267,7 @@
267267
268 expected = osutils.pathjoin(osutils.getcwd(), dirname1)268 expected = osutils.pathjoin(osutils.getcwd(), dirname1)
269 self.assertEqual(u'Using saved parent location: %s/\n'269 self.assertEqual(u'Using saved parent location: %s/\n'
270 'No revisions to pull.\n' % (expected,), txt)270 'No revisions or tags to pull.\n' % (expected,), txt)
271271
272 self.build_tree_contents(272 self.build_tree_contents(
273 [(osutils.pathjoin(dirname1, 'a'), 'and yet more\n')])273 [(osutils.pathjoin(dirname1, 'a'), 'and yet more\n')])
274274
=== modified file 'bzrlib/tests/blackbox/test_pull.py'
--- bzrlib/tests/blackbox/test_pull.py 2011-08-30 08:46:10 +0000
+++ bzrlib/tests/blackbox/test_pull.py 2011-09-02 00:55:08 +0000
@@ -318,7 +318,7 @@
318 # it is legal to attempt to pull an already-merged bundle318 # it is legal to attempt to pull an already-merged bundle
319 out, err = self.run_bzr('pull ../bundle')319 out, err = self.run_bzr('pull ../bundle')
320 self.assertEqual(err, '')320 self.assertEqual(err, '')
321 self.assertEqual(out, 'No revisions to pull.\n')321 self.assertEqual(out, 'No revisions or tags to pull.\n')
322322
323 def test_pull_verbose_no_files(self):323 def test_pull_verbose_no_files(self):
324 """Pull --verbose should not list modified files"""324 """Pull --verbose should not list modified files"""
@@ -533,3 +533,13 @@
533 out = self.run_bzr(['pull','-d','to','from'],retcode=1)533 out = self.run_bzr(['pull','-d','to','from'],retcode=1)
534 self.assertEqual(out,534 self.assertEqual(out,
535 ('No revisions to pull.\nConflicting tags:\n mytag\n', ''))535 ('No revisions to pull.\nConflicting tags:\n mytag\n', ''))
536
537 def test_pull_tag_notification(self):
538 """pulling tags with conflicts will change the exit code"""
539 # create a branch, see that --show-base fails
540 from_tree = self.make_branch_and_tree('from')
541 from_tree.branch.tags.set_tag("mytag", "somerevid")
542 to_tree = self.make_branch_and_tree('to')
543 out = self.run_bzr(['pull', '-d', 'to', 'from'])
544 self.assertEqual(out,
545 ('1 tag(s) updated.\n', ''))
536546
=== modified file 'bzrlib/tests/blackbox/test_push.py'
--- bzrlib/tests/blackbox/test_push.py 2011-08-16 15:03:03 +0000
+++ bzrlib/tests/blackbox/test_push.py 2011-09-02 00:55:08 +0000
@@ -157,7 +157,9 @@
157 self.run_bzr('push -d tree pushed-to')157 self.run_bzr('push -d tree pushed-to')
158 path = t.branch.get_push_location()158 path = t.branch.get_push_location()
159 out, err = self.run_bzr('push', working_dir="tree")159 out, err = self.run_bzr('push', working_dir="tree")
160 self.assertEqual('Using saved push location: %s\nNo new revisions to push.\n' % urlutils.local_path_from_url(path), err)160 self.assertEqual('Using saved push location: %s\n'
161 'No new revisions or tags to push.\n' %
162 urlutils.local_path_from_url(path), err)
161 out, err = self.run_bzr('push -q', working_dir="tree")163 out, err = self.run_bzr('push -q', working_dir="tree")
162 self.assertEqual('', out)164 self.assertEqual('', out)
163 self.assertEqual('', err)165 self.assertEqual('', err)
164166
=== modified file 'bzrlib/tests/per_branch/test_pull.py'
--- bzrlib/tests/per_branch/test_pull.py 2011-08-09 14:18:05 +0000
+++ bzrlib/tests/per_branch/test_pull.py 2011-09-02 00:55:08 +0000
@@ -117,7 +117,7 @@
117 self.assertEqual('P1', result.old_revid)117 self.assertEqual('P1', result.old_revid)
118 self.assertEqual(2, result.new_revno)118 self.assertEqual(2, result.new_revno)
119 self.assertEqual('M1', result.new_revid)119 self.assertEqual('M1', result.new_revid)
120 self.assertEqual(None, result.tag_conflicts)120 self.assertEqual([], result.tag_conflicts)
121121
122 def test_pull_overwrite(self):122 def test_pull_overwrite(self):
123 tree_a = self.make_branch_and_tree('tree_a')123 tree_a = self.make_branch_and_tree('tree_a')
124124
=== modified file 'bzrlib/tests/per_branch/test_tags.py'
--- bzrlib/tests/per_branch/test_tags.py 2011-08-26 23:59:59 +0000
+++ bzrlib/tests/per_branch/test_tags.py 2011-09-02 00:55:08 +0000
@@ -93,17 +93,19 @@
93 # if a tag is in the destination and not in the source, it is not93 # if a tag is in the destination and not in the source, it is not
94 # removed when we merge them94 # removed when we merge them
95 b2.tags.set_tag('in-destination', 'revid')95 b2.tags.set_tag('in-destination', 'revid')
96 result = b1.tags.merge_to(b2.tags)96 updates, conflicts = b1.tags.merge_to(b2.tags)
97 self.assertEquals(list(result), [])97 self.assertEquals(list(conflicts), [])
98 self.assertEquals(updates, {})
98 self.assertEquals(b2.tags.lookup_tag('in-destination'), 'revid')99 self.assertEquals(b2.tags.lookup_tag('in-destination'), 'revid')
99 # if there's a conflicting tag, it's reported -- the command line100 # if there's a conflicting tag, it's reported -- the command line
100 # interface will say "these tags couldn't be copied"101 # interface will say "these tags couldn't be copied"
101 b1.tags.set_tag('conflicts', 'revid-1')102 b1.tags.set_tag('conflicts', 'revid-1')
102 b2.tags.set_tag('conflicts', 'revid-2')103 b2.tags.set_tag('conflicts', 'revid-2')
103 result = b1.tags.merge_to(b2.tags)104 updates, conflicts = b1.tags.merge_to(b2.tags)
104 self.assertEquals(list(result),105 self.assertEquals(list(conflicts),
105 [('conflicts', 'revid-1', 'revid-2')])106 [('conflicts', 'revid-1', 'revid-2')])
106 # and it keeps the same value107 # and it keeps the same value
108 self.assertEquals(updates, {})
107 self.assertEquals(b2.tags.lookup_tag('conflicts'), 'revid-2')109 self.assertEquals(b2.tags.lookup_tag('conflicts'), 'revid-2')
108110
109 def test_unicode_tag(self):111 def test_unicode_tag(self):
@@ -292,9 +294,10 @@
292 child.bind(master)294 child.bind(master)
293 child.update()295 child.update()
294 master.tags.set_tag('foo', 'rev-2')296 master.tags.set_tag('foo', 'rev-2')
295 tag_conflicts = other.tags.merge_to(child.tags, overwrite=True)297 tag_updates, tag_conflicts = other.tags.merge_to(child.tags, overwrite=True)
296 self.assertEquals('rev-1', child.tags.lookup_tag('foo'))298 self.assertEquals('rev-1', child.tags.lookup_tag('foo'))
297 self.assertEquals('rev-1', master.tags.lookup_tag('foo'))299 self.assertEquals('rev-1', master.tags.lookup_tag('foo'))
300 self.assertEquals({"foo": "rev-1"}, tag_updates)
298 self.assertLength(0, tag_conflicts)301 self.assertLength(0, tag_conflicts)
299302
300 def test_merge_to_overwrite_conflict_in_child_and_master(self):303 def test_merge_to_overwrite_conflict_in_child_and_master(self):
@@ -308,9 +311,11 @@
308 child = self.make_branch('child')311 child = self.make_branch('child')
309 child.bind(master)312 child.bind(master)
310 child.update()313 child.update()
311 tag_conflicts = other.tags.merge_to(child.tags, overwrite=True)314 tag_updates, tag_conflicts = other.tags.merge_to(
315 child.tags, overwrite=True)
312 self.assertEquals('rev-1', child.tags.lookup_tag('foo'))316 self.assertEquals('rev-1', child.tags.lookup_tag('foo'))
313 self.assertEquals('rev-1', master.tags.lookup_tag('foo'))317 self.assertEquals('rev-1', master.tags.lookup_tag('foo'))
318 self.assertEquals({u'foo': 'rev-1'}, tag_updates)
314 self.assertLength(0, tag_conflicts)319 self.assertLength(0, tag_conflicts)
315320
316 def test_merge_to_conflict_in_child_only(self):321 def test_merge_to_conflict_in_child_only(self):
@@ -325,13 +330,14 @@
325 child.bind(master)330 child.bind(master)
326 child.update()331 child.update()
327 master.tags.delete_tag('foo')332 master.tags.delete_tag('foo')
328 tag_conflicts = other.tags.merge_to(child.tags)333 tag_updates, tag_conflicts = other.tags.merge_to(child.tags)
329 # Conflict in child, so it is unchanged.334 # Conflict in child, so it is unchanged.
330 self.assertEquals('rev-2', child.tags.lookup_tag('foo'))335 self.assertEquals('rev-2', child.tags.lookup_tag('foo'))
331 # No conflict in the master, so the 'foo' tag equals other's value here.336 # No conflict in the master, so the 'foo' tag equals other's value here.
332 self.assertEquals('rev-1', master.tags.lookup_tag('foo'))337 self.assertEquals('rev-1', master.tags.lookup_tag('foo'))
333 # The conflict is reported.338 # The conflict is reported.
334 self.assertEquals([(u'foo', 'rev-1', 'rev-2')], list(tag_conflicts))339 self.assertEquals([(u'foo', 'rev-1', 'rev-2')], list(tag_conflicts))
340 self.assertEquals({u'foo': 'rev-1'}, tag_updates)
335341
336 def test_merge_to_conflict_in_master_only(self):342 def test_merge_to_conflict_in_master_only(self):
337 """When new_tags.merge_to(child.tags) conflicts with the master but not343 """When new_tags.merge_to(child.tags) conflicts with the master but not
@@ -344,12 +350,13 @@
344 child.bind(master)350 child.bind(master)
345 child.update()351 child.update()
346 master.tags.set_tag('foo', 'rev-2')352 master.tags.set_tag('foo', 'rev-2')
347 tag_conflicts = other.tags.merge_to(child.tags)353 tag_updates, tag_conflicts = other.tags.merge_to(child.tags)
348 # No conflict in the child, so the 'foo' tag equals other's value here.354 # No conflict in the child, so the 'foo' tag equals other's value here.
349 self.assertEquals('rev-1', child.tags.lookup_tag('foo'))355 self.assertEquals('rev-1', child.tags.lookup_tag('foo'))
350 # Conflict in master, so it is unchanged.356 # Conflict in master, so it is unchanged.
351 self.assertEquals('rev-2', master.tags.lookup_tag('foo'))357 self.assertEquals('rev-2', master.tags.lookup_tag('foo'))
352 # The conflict is reported.358 # The conflict is reported.
359 self.assertEquals({u'foo': 'rev-1'}, tag_updates)
353 self.assertEquals([(u'foo', 'rev-1', 'rev-2')], list(tag_conflicts))360 self.assertEquals([(u'foo', 'rev-1', 'rev-2')], list(tag_conflicts))
354361
355 def test_merge_to_same_conflict_in_master_and_child(self):362 def test_merge_to_same_conflict_in_master_and_child(self):
@@ -363,12 +370,13 @@
363 child = self.make_branch('child')370 child = self.make_branch('child')
364 child.bind(master)371 child.bind(master)
365 child.update()372 child.update()
366 tag_conflicts = other.tags.merge_to(child.tags)373 tag_updates, tag_conflicts = other.tags.merge_to(child.tags)
367 # Both master and child conflict, so both stay as rev-2374 # Both master and child conflict, so both stay as rev-2
368 self.assertEquals('rev-2', child.tags.lookup_tag('foo'))375 self.assertEquals('rev-2', child.tags.lookup_tag('foo'))
369 self.assertEquals('rev-2', master.tags.lookup_tag('foo'))376 self.assertEquals('rev-2', master.tags.lookup_tag('foo'))
370 # The conflict is reported exactly once, even though it occurs in both377 # The conflict is reported exactly once, even though it occurs in both
371 # master and child.378 # master and child.
379 self.assertEquals({}, tag_updates)
372 self.assertEquals([(u'foo', 'rev-1', 'rev-2')], list(tag_conflicts))380 self.assertEquals([(u'foo', 'rev-1', 'rev-2')], list(tag_conflicts))
373381
374 def test_merge_to_different_conflict_in_master_and_child(self):382 def test_merge_to_different_conflict_in_master_and_child(self):
@@ -385,11 +393,12 @@
385 # We use the private method _set_tag_dict because normally bzr tries to393 # We use the private method _set_tag_dict because normally bzr tries to
386 # avoid this scenario.394 # avoid this scenario.
387 child.tags._set_tag_dict({'foo': 'rev-3'})395 child.tags._set_tag_dict({'foo': 'rev-3'})
388 tag_conflicts = other.tags.merge_to(child.tags)396 tag_updates, tag_conflicts = other.tags.merge_to(child.tags)
389 # Both master and child conflict, so both stay as they were.397 # Both master and child conflict, so both stay as they were.
390 self.assertEquals('rev-3', child.tags.lookup_tag('foo'))398 self.assertEquals('rev-3', child.tags.lookup_tag('foo'))
391 self.assertEquals('rev-2', master.tags.lookup_tag('foo'))399 self.assertEquals('rev-2', master.tags.lookup_tag('foo'))
392 # Both conflicts are reported.400 # Both conflicts are reported.
401 self.assertEquals({}, tag_updates)
393 self.assertEquals(402 self.assertEquals(
394 [(u'foo', 'rev-1', 'rev-2'), (u'foo', 'rev-1', 'rev-3')],403 [(u'foo', 'rev-1', 'rev-2'), (u'foo', 'rev-1', 'rev-3')],
395 sorted(tag_conflicts))404 sorted(tag_conflicts))
396405
=== modified file 'bzrlib/tests/per_interbranch/test_pull.py'
--- bzrlib/tests/per_interbranch/test_pull.py 2010-06-17 09:23:19 +0000
+++ bzrlib/tests/per_interbranch/test_pull.py 2011-09-02 00:55:08 +0000
@@ -99,7 +99,7 @@
99 self.assertEqual('P1', result.old_revid)99 self.assertEqual('P1', result.old_revid)
100 self.assertEqual(2, result.new_revno)100 self.assertEqual(2, result.new_revno)
101 self.assertEqual('M1', result.new_revid)101 self.assertEqual('M1', result.new_revid)
102 self.assertEqual(None, result.tag_conflicts)102 self.assertEqual([], result.tag_conflicts)
103103
104 def test_pull_overwrite(self):104 def test_pull_overwrite(self):
105 tree_a = self.make_from_branch_and_tree('tree_a')105 tree_a = self.make_from_branch_and_tree('tree_a')
106106
=== modified file 'bzrlib/tests/test_branch.py'
--- bzrlib/tests/test_branch.py 2011-05-26 08:04:46 +0000
+++ bzrlib/tests/test_branch.py 2011-09-02 00:55:08 +0000
@@ -709,5 +709,5 @@
709 r.new_revid = "same-revid"709 r.new_revid = "same-revid"
710 f = StringIO()710 f = StringIO()
711 r.report(f)711 r.report(f)
712 self.assertEqual("No revisions to pull.\n", f.getvalue())712 self.assertEqual("No revisions or tags to pull.\n", f.getvalue())
713713
714714
=== modified file 'bzrlib/tests/test_tag.py'
--- bzrlib/tests/test_tag.py 2011-08-06 07:32:51 +0000
+++ bzrlib/tests/test_tag.py 2011-09-02 00:55:08 +0000
@@ -109,12 +109,14 @@
109 self.assertRaises(errors.NoSuchTag, a.tags.lookup_tag, 'tag-2')109 self.assertRaises(errors.NoSuchTag, a.tags.lookup_tag, 'tag-2')
110 # conflicting merge110 # conflicting merge
111 a.tags.set_tag('tag-2', 'z')111 a.tags.set_tag('tag-2', 'z')
112 conflicts = a.tags.merge_to(b.tags)112 updates, conflicts = a.tags.merge_to(b.tags)
113 self.assertEqual({}, updates)
113 self.assertEqual(list(conflicts), [('tag-2', 'z', 'y')])114 self.assertEqual(list(conflicts), [('tag-2', 'z', 'y')])
114 self.assertEqual('y', b.tags.lookup_tag('tag-2'))115 self.assertEqual('y', b.tags.lookup_tag('tag-2'))
115 # overwrite conflicts116 # overwrite conflicts
116 conflicts = a.tags.merge_to(b.tags, overwrite=True)117 updates, conflicts = a.tags.merge_to(b.tags, overwrite=True)
117 self.assertEqual(list(conflicts), [])118 self.assertEqual(list(conflicts), [])
119 self.assertEqual({u'tag-1': 'x', u'tag-2': 'z'}, updates)
118 self.assertEqual('z', b.tags.lookup_tag('tag-2'))120 self.assertEqual('z', b.tags.lookup_tag('tag-2'))
119121
120122
121123
=== modified file 'doc/en/release-notes/bzr-2.5.txt'
--- doc/en/release-notes/bzr-2.5.txt 2011-09-01 18:11:38 +0000
+++ doc/en/release-notes/bzr-2.5.txt 2011-09-02 00:55:08 +0000
@@ -102,6 +102,9 @@
102 Entering an empty commit message in the message editor still triggers102 Entering an empty commit message in the message editor still triggers
103 an error. (Jelmer Vernooij)103 an error. (Jelmer Vernooij)
104104
105* ``bzr pull`` will now mention how many tags it has updated.
106 (Jelmer Vernooij, #164450)
107
105* ``bzr tag`` no longer errors if a tag already exists but refers to the108* ``bzr tag`` no longer errors if a tag already exists but refers to the
106 same revision. (Jelmer Vernooij)109 same revision. (Jelmer Vernooij)
107110
@@ -214,6 +217,9 @@
214 value in SI format (i.e. "20MB", "1GB") into its integer equivalent. 217 value in SI format (i.e. "20MB", "1GB") into its integer equivalent.
215 (Shannon Weyrick)218 (Shannon Weyrick)
216219
220* ``Tags.merge_to`` now returns a dictionary with the updated tags
221 and a set of conflicts, rather than just conflicts. (Jelmer Vernooij)
222
217* ``Transport`` now has a ``_parsed_url`` attribute instead of223* ``Transport`` now has a ``_parsed_url`` attribute instead of
218 separate ``_user``, ``_password``, ``_port``, ``_scheme``, ``_host``224 separate ``_user``, ``_password``, ``_port``, ``_scheme``, ``_host``
219 and ``_path`` attributes. Proxies are provided for the moment but225 and ``_path`` attributes. Proxies are provided for the moment but