Rev 2228: Add -d option to push, pull, merge commands. in file:///home/mbp/bzr/Work/tags/

Martin Pool mbp at sourcefrog.net
Sun Jan 21 12:42:17 GMT 2007


------------------------------------------------------------
revno: 2228
revision-id: mbp at sourcefrog.net-20070121124213-8ksq92nrm3tzn6s9
parent: mbp at sourcefrog.net-20070121085653-ptonrp6w7ini27un
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: tags
timestamp: Sun 2007-01-21 23:42:13 +1100
message:
  Add -d option to push, pull, merge commands.
  
  Tags now propagate between repositories by commands that move history around:
  branch, push, pull, merge.
  
  Add Repository.supports_tags method.
  
  All Repository tag methods now raise TagsNotSupported if they're not.
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
  bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
  bzrlib/tests/blackbox/test_tags.py test_tags.py-20070116132048-5h4qak2cm22jlb9e-1
=== modified file 'NEWS'
--- a/NEWS	2007-01-03 02:09:52 +0000
+++ b/NEWS	2007-01-21 12:42:13 +0000
@@ -1,3 +1,12 @@
+  IMPROVEMENTS:
+
+    * New option ``-d`` for pull and other commands, specifying the
+      branch or tree to operate on rather than the working directory.
+      (Martin Pool)
+
+    * Builtin tags support, created by the ``tag`` command and stored 
+      in the repository.  (Martin Pool)
+
 IN DEVELOPMENT
 
   IMPROVEMENTS:

=== modified file 'bzrlib/builtins.py'
--- a/bzrlib/builtins.py	2007-01-19 08:47:51 +0000
+++ b/bzrlib/builtins.py	2007-01-21 12:42:13 +0000
@@ -499,18 +499,29 @@
     location can be accessed.
     """
 
-    takes_options = ['remember', 'overwrite', 'revision', 'verbose']
+    takes_options = ['remember', 'overwrite', 'revision', 'verbose',
+        Option('directory',
+            help='branch to pull into, '
+                 'rather than the one containing the working directory',
+            short_name='d',
+            type=unicode,
+            ),
+        ]
     takes_args = ['location?']
     encoding_type = 'replace'
 
-    def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
+    def run(self, location=None, remember=False, overwrite=False,
+            revision=None, verbose=False,
+            directory=None):
         # FIXME: too much stuff is in the command class
+        if directory is None:
+            directory = u'.'
         try:
-            tree_to = WorkingTree.open_containing(u'.')[0]
+            tree_to = WorkingTree.open_containing(directory)[0]
             branch_to = tree_to.branch
         except errors.NoWorkingTree:
             tree_to = None
-            branch_to = Branch.open_containing(u'.')[0]
+            branch_to = Branch.open_containing(directory)[0]
 
         reader = None
         if location is not None:
@@ -530,7 +541,6 @@
                 self.outf.write("Using saved location: %s\n" % display_url)
                 location = stored_loc
 
-
         if reader is not None:
             install_bundle(branch_to.repository, reader)
             branch_from = branch_to
@@ -554,6 +564,7 @@
             count = tree_to.pull(branch_from, overwrite, rev_id)
         else:
             count = branch_to.pull(branch_from, overwrite, rev_id)
+        _copy_tags_maybe(branch_from, branch_to)
         note('%d revision(s) pulled.' % (count,))
 
         if verbose:
@@ -592,18 +603,27 @@
     """
 
     takes_options = ['remember', 'overwrite', 'verbose',
-                     Option('create-prefix', 
-                            help='Create the path leading up to the branch '
-                                 'if it does not already exist')]
+        Option('create-prefix', 
+               help='Create the path leading up to the branch '
+                    'if it does not already exist'),
+        Option('directory',
+            help='branch to push from, '
+                 'rather than the one containing the working directory',
+            short_name='d',
+            type=unicode,
+            ),
+        ]
     takes_args = ['location?']
     encoding_type = 'replace'
 
     def run(self, location=None, remember=False, overwrite=False,
-            create_prefix=False, verbose=False):
+            create_prefix=False, verbose=False,
+            directory=None):
         # FIXME: Way too big!  Put this into a function called from the
         # command.
-        
-        br_from = Branch.open_containing('.')[0]
+        if directory is None:
+            directory = '.'
+        br_from = Branch.open_containing(directory)[0]
         stored_loc = br_from.get_push_location()
         if location is None:
             if stored_loc is None:
@@ -674,6 +694,7 @@
             except errors.DivergedBranches:
                 raise errors.BzrCommandError('These branches have diverged.'
                                         '  Try using "merge" and then "push".')
+        _copy_tags_maybe(br_from, br_to)
         note('%d revision(s) pushed.' % (count,))
 
         if verbose:
@@ -759,11 +780,28 @@
                 raise errors.BzrCommandError(msg)
             if name:
                 branch.control_files.put_utf8('branch-name', name)
+            _copy_tags_maybe(br_from, branch)
             note('Branched %d revision(s).' % branch.revno())
         finally:
             br_from.unlock()
 
 
+def _copy_tags_maybe(from_branch, to_branch):
+    """Copy tags between repositories if necessary and possible.
+    
+    This method has common command-line behaviour about handling 
+    error cases.
+    """
+    from_repo = from_branch.repository
+    to_repo = to_branch.repository
+    if not from_repo.supports_tags():
+        # obviously nothing to copy
+        return
+    # TODO: give a warning if the source format supports tags and actually has
+    # tags, but the destination doesn't accept them.
+    from_repo.copy_tags_to(to_repo)
+
+
 class cmd_checkout(Command):
     """Create a new checkout of an existing branch.
 
@@ -2235,6 +2273,10 @@
     default, use --remember. The value will only be saved if the remote
     location can be accessed.
 
+    The results of the merge are placed into the destination working
+    directory, where they can be reviewed (with bzr diff), tested, and then
+    committed to record the result of the merge.
+
     Examples:
 
     To merge the latest revision from bzr.dev
@@ -2253,15 +2295,21 @@
     """
     takes_args = ['branch?']
     takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
-                     Option('show-base', help="Show base revision text in "
-                            "conflicts"),
-                     Option('uncommitted', help='Apply uncommitted changes'
-                            ' from a working copy, instead of branch changes'),
-                     Option('pull', help='If the destination is already'
-                             ' completely merged into the source, pull from the'
-                             ' source rather than merging. When this happens,'
-                             ' you do not need to commit the result.'),
-                     ]
+        Option('show-base', help="Show base revision text in "
+               "conflicts"),
+        Option('uncommitted', help='Apply uncommitted changes'
+               ' from a working copy, instead of branch changes'),
+        Option('pull', help='If the destination is already'
+                ' completely merged into the source, pull from the'
+                ' source rather than merging. When this happens,'
+                ' you do not need to commit the result.'),
+        Option('directory',
+            help='branch to push from, '
+                 'rather than the one containing the working directory',
+            short_name='d',
+            type=unicode,
+            ),
+    ]
 
     def help(self):
         from inspect import getdoc
@@ -2269,11 +2317,13 @@
 
     def run(self, branch=None, revision=None, force=False, merge_type=None,
             show_base=False, reprocess=False, remember=False, 
-            uncommitted=False, pull=False):
+            uncommitted=False, pull=False,
+            directory=None,
+            ):
         if merge_type is None:
             merge_type = _mod_merge.Merge3Merger
-
-        tree = WorkingTree.open_containing(u'.')[0]
+        if directory is None: directory = u'.'
+        tree = WorkingTree.open_containing(directory)[0]
 
         if branch is not None:
             try:
@@ -2328,6 +2378,10 @@
         if tree.branch.get_parent() is None or remember:
             tree.branch.set_parent(other_branch.base)
 
+        # pull tags now... it's a bit inconsistent to do it ahead of copying
+        # the history but that's done inside the merge code
+        _copy_tags_maybe(other_branch, tree.branch)
+
         if path != "":
             interesting_files = [path]
         else:
@@ -2341,6 +2395,7 @@
                     reprocess=reprocess,
                     show_base=show_base,
                     pull=pull,
+                    this_dir=directory,
                     pb=pb, file_list=interesting_files)
             finally:
                 pb.finished()
@@ -2995,7 +3050,16 @@
 
 
 class cmd_tag(Command):
-    """Create a tag naming a revision"""
+    """Create a tag naming a revision.
+    
+    Tags give human-meaningful names to revisions.  Commands that take a -r
+    (--revision) option can be given -rtag:X, where X is any previously
+    created tag.
+
+    Tags are stored in the repository, and apply to all branches stored
+    in the repository.  Tags are copied from one branch to another along
+    when you branch, push, pull or merge.
+    """
 
     takes_args = ['tag_name']
     takes_options = [

=== modified file 'bzrlib/repository.py'
--- a/bzrlib/repository.py	2007-01-21 08:56:53 +0000
+++ b/bzrlib/repository.py	2007-01-21 12:42:13 +0000
@@ -88,13 +88,22 @@
     def _not_supported(self, *a, **k):
         raise errors.TagsNotSupported(self.repository)
 
+    def supports_tags(self):
+        return False
+
     set_tag = _not_supported
+    get_tag_dict = _not_supported
+    _set_tag_dict = _not_supported
+    lookup_tag = _not_supported
 
 
 class _BasicTagStore(_TagStore):
     """Tag storage in an unversioned repository control file.
     """
 
+    def supports_tags(self):
+        return True
+
     def set_tag(self, tag_name, tag_target):
         """Add a tag definition to the repository.
 
@@ -876,6 +885,9 @@
     def _set_tag_dict(self, new_dict):
         return self._tag_store._set_tag_dict(new_dict)
 
+    def supports_tags(self):
+        return self._tag_store.supports_tags()
+
     def copy_tags_to(self, to_repository):
         """Copy tags to another repository.
 
@@ -2003,6 +2015,8 @@
         # A default implementation is provided even though not all
         # Repositories will support tags... we'll just get an error back from
         # the underlying method.
+        if self.target == self.source:
+            return
         self.target.lock_write()
         try:
             self.target._set_tag_dict(self.source.get_tag_dict())

=== modified file 'bzrlib/tests/blackbox/test_tags.py'
--- a/bzrlib/tests/blackbox/test_tags.py	2007-01-19 08:47:51 +0000
+++ b/bzrlib/tests/blackbox/test_tags.py	2007-01-21 12:42:13 +0000
@@ -19,7 +19,11 @@
 from bzrlib.branch import Branch
 from bzrlib.bzrdir import BzrDir
 from bzrlib.tests import TestCaseWithTransport
-from bzrlib.repository import RepositoryFormatKnit2
+from bzrlib.repository import (
+    Repository,
+    RepositoryFormatKnit2,
+    )
+from bzrlib.workingtree import WorkingTree
 
 
 class TestTagging(TestCaseWithTransport):
@@ -55,3 +59,30 @@
         # can also create tags using -r
         self.run_bzr('tag', '-d', 'branch', 'tag2', '-r1')
         self.assertEquals(repo.lookup_tag('tag2'), 'first-revid')
+
+    def test_branch_push_pull_merge_copies_tags(self):
+        t = self.make_branch_and_tree('branch1')
+        t.commit(allow_pointless=True, message='initial commit',
+            rev_id='first-revid')
+        repo1 = t.branch.repository
+        repo1.set_tag('tag1', 'first-revid')
+        # branching copies the tag across
+        self.run_bzr('branch', 'branch1', 'branch2')
+        repo2 = Repository.open('branch2')
+        self.assertEquals(repo2.lookup_tag('tag1'), 'first-revid')
+        # make a new tag and pull it
+        repo1.set_tag('tag2', 'twa')
+        self.run_bzr('pull', '-d', 'branch2', 'branch1')
+        self.assertEquals(repo2.lookup_tag('tag2'), 'twa')
+        # make a new tag and push it
+        repo1.set_tag('tag3', 'san')
+        self.run_bzr('push', '-d', 'branch1', 'branch2')
+        self.assertEquals(repo2.lookup_tag('tag3'), 'san')
+        # make a new tag and merge it
+        t.commit(allow_pointless=True, message='second commit',
+            rev_id='second-revid')
+        t2 = WorkingTree.open('branch2')
+        t2.commit(allow_pointless=True, message='commit in second')
+        repo1.set_tag('tag4', 'second-revid')
+        self.run_bzr('merge', '-d', 'branch2', 'branch1')
+        self.assertEquals(repo2.lookup_tag('tag4'), 'second-revid')




More information about the bazaar-commits mailing list