Merge lp:~jelmer/bzr/uncommit-remove-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: 6094
Proposed branch: lp:~jelmer/bzr/uncommit-remove-tags
Merge into: lp:bzr
Diff against target: 231 lines (+89/-13)
7 files modified
bzrlib/builtins.py (+9/-6)
bzrlib/tests/blackbox/test_uncommit.py (+16/-2)
bzrlib/tests/test_uncommit.py (+27/-0)
bzrlib/uncommit.py (+26/-1)
bzrlib/vf_repository.py (+4/-4)
doc/en/release-notes/bzr-2.5.txt (+4/-0)
doc/en/user-guide/undoing_mistakes.txt (+3/-0)
To merge this branch: bzr merge lp:~jelmer/bzr/uncommit-remove-tags
Reviewer Review Type Date Requested Status
Martin Pool Approve
Review via email: mp+72403@code.launchpad.net

Commit message

Remove tags in `bzr uncommit`.

Description of the change

Finishing off some code that I still had around in my working area...

Remove tags when uncommitting revisions. A new option --keep-tags prevents
this behaviour.

To post a comment you must log in.
Revision history for this message
Martin Pool (mbp) wrote :

That's good.

[tweak] It's a bit safer to add new keyword parameters at the end.

[tweak] Please mention it in the user guide under uncommit.

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

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

On 8/24/2011 7:30 AM, Martin Pool wrote:
> Review: Approve That's good.
>
> [tweak] It's a bit safer to add new keyword parameters at the end.
>
> [tweak] Please mention it in the user guide under uncommit.

I'm a bit concerned that we do a graph search to find what tags to
remove. I guess we've only been doing a linear search to resolve what
revisions to display?

John
=:->

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

iEYEARECAAYFAk5UyAIACgkQJdeBCYSNAAPBegCfVrVDCtKFCvmBgJ7OEg7WGgWc
k8oAoNeYK5humf4yWFpI2lD+t4oh2GbX
=j8AV
-----END PGP SIGNATURE-----

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

On 08/24/2011 11:46 AM, John A Meinel wrote:
> On 8/24/2011 7:30 AM, Martin Pool wrote:
>> Review: Approve That's good.
>>
>> [tweak] It's a bit safer to add new keyword parameters at the end.
>>
>> [tweak] Please mention it in the user guide under uncommit.
> I'm a bit concerned that we do a graph search to find what tags to
> remove. I guess we've only been doing a linear search to resolve what
> revisions to display?
>
Yep. We could potentially avoid redoing the get_parent_map calls for the
revisions on the mainline, but at the cost of more code complexity.

Cheers,

Jelmer

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

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

On 8/24/2011 12:10 PM, Jelmer Vernooij wrote:
> On 08/24/2011 11:46 AM, John A Meinel wrote:
>> On 8/24/2011 7:30 AM, Martin Pool wrote:
>>> Review: Approve That's good.
>>>
>>> [tweak] It's a bit safer to add new keyword parameters at the
>>> end.
>>>
>>> [tweak] Please mention it in the user guide under uncommit.
>> I'm a bit concerned that we do a graph search to find what tags
>> to remove. I guess we've only been doing a linear search to
>> resolve what revisions to display?
>>
> Yep. We could potentially avoid redoing the get_parent_map calls
> for the revisions on the mainline, but at the cost of more code
> complexity.
>
> Cheers,
>
> Jelmer
>

Right, if we only know about mainline, it isn't worth worrying about.
As long as things are well cached, etc.

I'd worry a bit about performance, but uncommit should usually be
local enough in scope it should be ok. Though I wish our
find_unique_ancestors code didn't have some really bad behaviors
(landing bzr-2.1 into bzr-2.4 causes a lot of graph searching, though
some of that is just because we are 'skipping over' 2 years of history.)

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

iEYEARECAAYFAk5U1J8ACgkQJdeBCYSNAAP8LwCeJYZt9z82Vc0tH6bYzSy6kStN
eI0An09oAtrCdzasSV4UVpFNZ1GlhogZ
=qfkU
-----END PGP SIGNATURE-----

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bzrlib/builtins.py'
--- bzrlib/builtins.py 2011-08-19 22:26:03 +0000
+++ bzrlib/builtins.py 2011-08-24 09:34:52 +0000
@@ -4979,6 +4979,8 @@
4979 takes_options = ['verbose', 'revision',4979 takes_options = ['verbose', 'revision',
4980 Option('dry-run', help='Don\'t actually make changes.'),4980 Option('dry-run', help='Don\'t actually make changes.'),
4981 Option('force', help='Say yes to all questions.'),4981 Option('force', help='Say yes to all questions.'),
4982 Option('keep-tags',
4983 help='Keep tags that point to removed revisions.'),
4982 Option('local',4984 Option('local',
4983 help="Only remove the commits from the local branch"4985 help="Only remove the commits from the local branch"
4984 " when in a checkout."4986 " when in a checkout."
@@ -4988,9 +4990,8 @@
4988 aliases = []4990 aliases = []
4989 encoding_type = 'replace'4991 encoding_type = 'replace'
49904992
4991 def run(self, location=None,4993 def run(self, location=None, dry_run=False, verbose=False,
4992 dry_run=False, verbose=False,4994 revision=None, force=False, local=False, keep_tags=False):
4993 revision=None, force=False, local=False):
4994 if location is None:4995 if location is None:
4995 location = u'.'4996 location = u'.'
4996 control, relpath = bzrdir.BzrDir.open_containing(location)4997 control, relpath = bzrdir.BzrDir.open_containing(location)
@@ -5005,9 +5006,11 @@
5005 self.add_cleanup(tree.lock_write().unlock)5006 self.add_cleanup(tree.lock_write().unlock)
5006 else:5007 else:
5007 self.add_cleanup(b.lock_write().unlock)5008 self.add_cleanup(b.lock_write().unlock)
5008 return self._run(b, tree, dry_run, verbose, revision, force, local=local)5009 return self._run(b, tree, dry_run, verbose, revision, force,
5010 local, keep_tags)
50095011
5010 def _run(self, b, tree, dry_run, verbose, revision, force, local=False):5012 def _run(self, b, tree, dry_run, verbose, revision, force, local,
5013 keep_tags):
5011 from bzrlib.log import log_formatter, show_log5014 from bzrlib.log import log_formatter, show_log
5012 from bzrlib.uncommit import uncommit5015 from bzrlib.uncommit import uncommit
50135016
@@ -5059,7 +5062,7 @@
5059 mutter('Uncommitting from {%s} to {%s}',5062 mutter('Uncommitting from {%s} to {%s}',
5060 last_rev_id, rev_id)5063 last_rev_id, rev_id)
5061 uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,5064 uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
5062 revno=revno, local=local)5065 revno=revno, local=local, keep_tags=keep_tags)
5063 self.outf.write('You can restore the old tip by running:\n'5066 self.outf.write('You can restore the old tip by running:\n'
5064 ' bzr pull . -r revid:%s\n' % last_rev_id)5067 ' bzr pull . -r revid:%s\n' % last_rev_id)
50655068
50665069
=== modified file 'bzrlib/tests/blackbox/test_uncommit.py'
--- bzrlib/tests/blackbox/test_uncommit.py 2010-09-15 09:35:42 +0000
+++ bzrlib/tests/blackbox/test_uncommit.py 2011-08-24 09:34:52 +0000
@@ -18,9 +18,9 @@
1818
19import os19import os
2020
21from bzrlib import uncommit, workingtree21from bzrlib import uncommit
22from bzrlib.bzrdir import BzrDirMetaFormat122from bzrlib.bzrdir import BzrDirMetaFormat1
23from bzrlib.errors import BzrError, BoundBranchOutOfDate23from bzrlib.errors import BoundBranchOutOfDate
24from bzrlib.tests import TestCaseWithTransport24from bzrlib.tests import TestCaseWithTransport
25from bzrlib.tests.script import (25from bzrlib.tests.script import (
26 run_script,26 run_script,
@@ -280,3 +280,17 @@
280 tree.commit(u'\u1234 message')280 tree.commit(u'\u1234 message')
281 out, err = self.run_bzr('uncommit --force tree', encoding='ascii')281 out, err = self.run_bzr('uncommit --force tree', encoding='ascii')
282 self.assertContainsRe(out, r'\? message')282 self.assertContainsRe(out, r'\? message')
283
284 def test_uncommit_removes_tags(self):
285 tree = self.make_branch_and_tree('tree')
286 revid = tree.commit('message')
287 tree.branch.tags.set_tag("atag", revid)
288 out, err = self.run_bzr('uncommit --force tree')
289 self.assertEquals({}, tree.branch.tags.get_tag_dict())
290
291 def test_uncommit_keep_tags(self):
292 tree = self.make_branch_and_tree('tree')
293 revid = tree.commit('message')
294 tree.branch.tags.set_tag("atag", revid)
295 out, err = self.run_bzr('uncommit --keep-tags --force tree')
296 self.assertEquals({"atag": revid}, tree.branch.tags.get_tag_dict())
283297
=== modified file 'bzrlib/tests/test_uncommit.py'
--- bzrlib/tests/test_uncommit.py 2011-05-13 12:51:05 +0000
+++ bzrlib/tests/test_uncommit.py 2011-08-24 09:34:52 +0000
@@ -96,3 +96,30 @@
96 # If this tree isn't bound, local=True raises an exception96 # If this tree isn't bound, local=True raises an exception
97 self.assertRaises(errors.LocalRequiresBoundBranch,97 self.assertRaises(errors.LocalRequiresBoundBranch,
98 uncommit.uncommit, tree.branch, tree=tree, local=True)98 uncommit.uncommit, tree.branch, tree=tree, local=True)
99
100 def test_uncommit_remove_tags(self):
101 tree, history = self.make_linear_tree()
102 self.assertEqual(history[1], tree.last_revision())
103 self.assertEqual((2, history[1]), tree.branch.last_revision_info())
104 tree.branch.tags.set_tag(u"pointsatexisting", history[0])
105 tree.branch.tags.set_tag(u"pointsatremoved", history[1])
106 uncommit.uncommit(tree.branch, tree=tree)
107 self.assertEqual(history[0], tree.last_revision())
108 self.assertEqual((1, history[0]), tree.branch.last_revision_info())
109 self.assertEqual({
110 "pointsatexisting": history[0]
111 }, tree.branch.tags.get_tag_dict())
112
113 def test_uncommit_keep_tags(self):
114 tree, history = self.make_linear_tree()
115 self.assertEqual(history[1], tree.last_revision())
116 self.assertEqual((2, history[1]), tree.branch.last_revision_info())
117 tree.branch.tags.set_tag(u"pointsatexisting", history[0])
118 tree.branch.tags.set_tag(u"pointsatremoved", history[1])
119 uncommit.uncommit(tree.branch, tree=tree, keep_tags=True)
120 self.assertEqual(history[0], tree.last_revision())
121 self.assertEqual((1, history[0]), tree.branch.last_revision_info())
122 self.assertEqual({
123 "pointsatexisting": history[0],
124 "pointsatremoved": history[1],
125 }, tree.branch.tags.get_tag_dict())
99126
=== modified file 'bzrlib/uncommit.py'
--- bzrlib/uncommit.py 2011-06-16 12:50:32 +0000
+++ bzrlib/uncommit.py 2011-08-24 09:34:52 +0000
@@ -26,8 +26,29 @@
26from bzrlib.errors import BoundBranchOutOfDate26from bzrlib.errors import BoundBranchOutOfDate
2727
2828
29def remove_tags(branch, graph, old_tip, new_tip):
30 """Remove tags on revisions between old_tip and new_tip.
31
32 :param branch: Branch to remove tags from
33 :param graph: Graph object for branch repository
34 :param old_tip: Old branch tip
35 :param new_tip: New branch tip
36 :return: Names of the removed tags
37 """
38 reverse_tags = branch.tags.get_reverse_tag_dict()
39 ancestors = graph.find_unique_ancestors(old_tip, [new_tip])
40 removed_tags = []
41 for revid, tags in reverse_tags.iteritems():
42 if not revid in ancestors:
43 continue
44 for tag in tags:
45 branch.tags.delete_tag(tag)
46 removed_tags.append(tag)
47 return removed_tags
48
49
29def uncommit(branch, dry_run=False, verbose=False, revno=None, tree=None,50def uncommit(branch, dry_run=False, verbose=False, revno=None, tree=None,
30 local=False):51 local=False, keep_tags=False):
31 """Remove the last revision from the supplied branch.52 """Remove the last revision from the supplied branch.
3253
33 :param dry_run: Don't actually change anything54 :param dry_run: Don't actually change anything
@@ -36,6 +57,8 @@
36 :param local: If this branch is bound, only remove the revisions from the57 :param local: If this branch is bound, only remove the revisions from the
37 local branch. If this branch is not bound, it is an error to pass58 local branch. If this branch is not bound, it is an error to pass
38 local=True.59 local=True.
60 :param keep_tags: Whether to keep tags pointing at the removed revisions
61 around.
39 """62 """
40 unlockable = []63 unlockable = []
41 try:64 try:
@@ -105,6 +128,8 @@
105 hook_new_tip = None128 hook_new_tip = None
106 hook(hook_local, hook_master, old_revno, old_tip, new_revno,129 hook(hook_local, hook_master, old_revno, old_tip, new_revno,
107 hook_new_tip)130 hook_new_tip)
131 if branch.supports_tags() and not keep_tags:
132 remove_tags(branch, graph, old_tip, new_revision_id)
108 if tree is not None:133 if tree is not None:
109 if not _mod_revision.is_null(new_revision_id):134 if not _mod_revision.is_null(new_revision_id):
110 parents = [new_revision_id]135 parents = [new_revision_id]
111136
=== modified file 'bzrlib/vf_repository.py'
--- bzrlib/vf_repository.py 2011-08-02 11:18:43 +0000
+++ bzrlib/vf_repository.py 2011-08-24 09:34:52 +0000
@@ -419,8 +419,8 @@
419 return None, False, None419 return None, False, None
420 # XXX: Friction: parent_candidates should return a list not a dict420 # XXX: Friction: parent_candidates should return a list not a dict
421 # so that we don't have to walk the inventories again.421 # so that we don't have to walk the inventories again.
422 parent_candiate_entries = ie.parent_candidates(parent_invs)422 parent_candidate_entries = ie.parent_candidates(parent_invs)
423 head_set = self._heads(ie.file_id, parent_candiate_entries.keys())423 head_set = self._heads(ie.file_id, parent_candidate_entries.keys())
424 heads = []424 heads = []
425 for inv in parent_invs:425 for inv in parent_invs:
426 if inv.has_id(ie.file_id):426 if inv.has_id(ie.file_id):
@@ -441,7 +441,7 @@
441 store = True441 store = True
442 if not store:442 if not store:
443 # There is a single head, look it up for comparison443 # There is a single head, look it up for comparison
444 parent_entry = parent_candiate_entries[heads[0]]444 parent_entry = parent_candidate_entries[heads[0]]
445 # if the non-content specific data has changed, we'll be writing a445 # if the non-content specific data has changed, we'll be writing a
446 # node:446 # node:
447 if (parent_entry.parent_id != ie.parent_id or447 if (parent_entry.parent_id != ie.parent_id or
@@ -559,7 +559,7 @@
559 :param iter_changes: An iter_changes iterator with the changes to apply559 :param iter_changes: An iter_changes iterator with the changes to apply
560 to basis_revision_id. The iterator must not include any items with560 to basis_revision_id. The iterator must not include any items with
561 a current kind of None - missing items must be either filtered out561 a current kind of None - missing items must be either filtered out
562 or errored-on beefore record_iter_changes sees the item.562 or errored-on before record_iter_changes sees the item.
563 :param _entry_factory: Private method to bind entry_factory locally for563 :param _entry_factory: Private method to bind entry_factory locally for
564 performance.564 performance.
565 :return: A generator of (file_id, relpath, fs_hash) tuples for use with565 :return: A generator of (file_id, relpath, fs_hash) tuples for use with
566566
=== modified file 'doc/en/release-notes/bzr-2.5.txt'
--- doc/en/release-notes/bzr-2.5.txt 2011-08-23 10:27:54 +0000
+++ doc/en/release-notes/bzr-2.5.txt 2011-08-24 09:34:52 +0000
@@ -100,6 +100,10 @@
100 Entering an empty commit message in the message editor still triggers100 Entering an empty commit message in the message editor still triggers
101 an error. (Jelmer Vernooij)101 an error. (Jelmer Vernooij)
102102
103* ``bzr uncommit`` will now remove tags that refer to removed revisions.
104 The ``--keep-tags`` option can be used to prevent this behaviour.
105 (Jelmer Vernooij, #605814)
106
103* Locations printed by ``bzr upgrade`` are now formatted before display.107* Locations printed by ``bzr upgrade`` are now formatted before display.
104 (Jelmer Vernooij)108 (Jelmer Vernooij)
105109
106110
=== modified file 'doc/en/user-guide/undoing_mistakes.txt'
--- doc/en/user-guide/undoing_mistakes.txt 2009-11-23 15:29:24 +0000
+++ doc/en/user-guide/undoing_mistakes.txt 2011-08-24 09:34:52 +0000
@@ -93,6 +93,9 @@
93one or more files. Some users like to alias ``commit`` to ``commit --strict``93one or more files. Some users like to alias ``commit`` to ``commit --strict``
94so that commits fail if unknown files are found in the tree.94so that commits fail if unknown files are found in the tree.
9595
96Tags for uncommitted revisions are removed from the branch unless
97``--keep-tags`` was specified.
98
96Note: While the ``merge`` command is not introduced until the next99Note: While the ``merge`` command is not introduced until the next
97chapter, it is worth noting now that ``uncommit`` restores any pending100chapter, it is worth noting now that ``uncommit`` restores any pending
98merges. (Running ``bzr status`` after ``uncommit`` will show these.)101merges. (Running ``bzr status`` after ``uncommit`` will show these.)