[merge] tags in repository

John Arbash Meinel john at arbash-meinel.com
Tue Jan 23 02:39:09 GMT 2007


Martin Pool wrote:
> This adds tags stored in the repository, and visible across branches in
> that repository.  Adding a tag doesn't require a commit.  Tags are
> 'global' across projects so people should use them appropriately - eg
> putting the project name at the start of the tag like 'bzr-0.14'.  
> 
> Tags are copied by commands like push, pull, merge, branch.  This is
> done in the command line level rather than from eg fetch (but I'm open
> to changing it) because commands might want 'pull --no-tags' or 'pull
> --overwrite-tags' in the future.
> 
> This incidentally adds a -d option to override the default directory for
> some commands, for ease of testing and because it's previously been
> requested.
> 
> Implementation notes:
> 
>  * This adds them into the KnitRepository2 format.  I would like them to
>    be in the default format for the next release, but I'm not sure if 
>    all the changes in KnitRepository2 are in that class.
>  
>  * The implementation of tags is in a strategy object used by the
>    repository, partly so that we can keep it common between related
>    formats, or switch it from one release into another.
> 
>  * There should be some scope for different repositories (eg svn or
>    future formats) to have different approaches.

There are 2 things that I saw with this.

1) Tags are not versioned, rather they are just current points in time.
I know one of the big troubles we had was trying to handle versioning.
At least it caused a lot of debate.

Many systems do not version their tags, though, so it isn't like we are
doing worse then others. The systems that do version their tags tend to
have them in the working directory, which means you have to commit them,
and you can only understand them in context. (There is no way to have a
floating 'latest stable' tag, because it can only point to something in
the past).

2) Your current implementation of 'copy_tags_to' always overwrites the
target tag dict with the source. Which also means you lose any local
tags. For example:

  bzr branch a b
  cd a
  bzr tag foo
  cd ../b
  bzr tag bar
  bzr pull ../a # Now we have 'foo' but we lost 'bar'.

So at the very least I would do:

+    def copy_tags(self):
+        """Copy all tags from source to the target."""
+        # 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:
+            tags = self.target.get_tag_dict()
+            tags.update(self.source.get_tag_dict())
+            self._set_tag_dict(tags)
+        finally:
+            self.target.unlock()
+

At least that would not delete tags that exist locally.


What I would rather see is the dict be a map from key => list of values.
I don't really care about the ancestry of the values, but you could at
least see that you have already seen that value so it wouldn't override
by default.

I can understand that it complicates matters, though. Could we have a
way to interactively resolve tags?


So one possibility would be to have the default "copy_tags_to" be:

  tags = self.target.get_tag_dict()
  source_tags = self.source.get_tag_dict()
  for k,v in source_tags.iteritems():
    tags.setdefault(k,v)

Which means that it will pull across any tags that don't already exist,
but it won't touch ones that do.

John
=:->



More information about the bazaar mailing list