tags:

views:

1337

answers:

4

I maintain the build system at my company, which is currently using CVS. This build system is used across multiple projects and multiple CVS repositories.

Whenever we have a release milestone, we create a tag. In CVS, this is easy:

$ cvs tag TAG_NAME

That command works regardless of the CVS module or repository, as long as it is executed in a CVS working directory.

In order to do the same thing in subversion though, it looks like I will first have to parse the output of svn info to get the repository root. Then I can create the tag with:

svn cp . $REPO_ROOT/tags/TAG_NAME -m"Created tag TAG_NAME"

This of course assumes that the svn repository has the recommended "trunk, tags, branches" directory structure. So to be safe I'll probably need to verify this first.

That seems like a lot of work just to map a revision number to a symbolic name. Is there a better way?

+1  A: 

Unlike CVS, tags are more than just a symbolic name in subversions, that's the point. We you create a tag, you are actually creating a branch. I recommend to read this, if you haven't already: http://svnbook.red-bean.com/

Davide
+2  A: 

I use svn from the command line almost exclusively and0t I quickly tired of typing in monster URLs. I finally wrote a script svnurl, which I use from the shell. It operates on the assumption that an "project" hast the form:

.../PROJECTNAME/trunk
                tags
                branches

Let's assume you are somewhere in a working copy of PROJECTNAME/branches/foo:

svnurl -tl  # gives a list of tags for the current project 
svnurl -tlu # the same as full urls
svnurl -t 1.1 # the url for the tag 1.1 of the current project
# analagous functions for branches
svnurl -ru  # the url of the "root" of the current working copy
            # eg  svn://.../PROJECTNAME/branches/foo
svnurl -T   # the url of the trunk of the current project
svnurl -pn  # the name of the current project, `PROJECTNAME`
# ...

Usage looks something like this:

$ svn cp $(svnurl -T) $(svnurl -t 1.1.1)  # tag trunk as 1.1.1

The code isn't beautiful, but it has saved me many keystrokes and been useful in ways I hadn't expected. I'd be willing to share it if you are interested.

bendin
Thanks, I would certainly be interested in taking a look. I won't be able to use it directly, since I have to support windows clients, but I would love to see how it works.
Jason Day
You'll find the script here: [[http://github.com/bpsm/svnurl/tree/master/svnurl.py][svnurl at github]].
bendin
+4  A: 

You're missing a core principle of Subversion: the revision number is the tag. When you "tag" it with svn cp, you're just making a copy of that particular revision with a longer name. And unlike a CVS tag, you (or other developers) could continue doing ongoing development on that "tag". It isn't a static entity like a CVS tag is (well, to be fair, you can move a tag on individual CVS files which effectively "changes" it).

Most svn users treat tags the way CVS presented them. And (under Apache, at least) you can configure the DAV server to not permit writes/check-ins under any tag directory. I haven't tried this, and it might prevent you using http URLs for creating the tags (you'd have to use file paths from a shell on the hosting machine). But for all practical purposes, your release process should be more interested in the specific revision number, than in some arbitrary text-string. The latter can be altered after the release; the former should[*] always give you access to the exact same set of files every time you check it out.

[*] There's always a way to fiddle around with files behind the scenes, after the fact... I used to hand-edit RCS and CVS files with vi when I needed to fix a comment, etc. But without some serious svn-cleverness, a given revision number should be pretty constant.

rjray
I understand all that, but it's not relevant. My customers want a symbolic tag name, not a revision. That's not going to change (I've tried).
Jason Day
The way that svn treats tags its stupid. Why its soo dificult to have a list of tuples rev-number <-> tag-name in a indexed file, and use it as a dictionary?
damian
agree with damian. The revision number itself is not useful as a tag, since it's just a number. Also, knowing the revision number does not help you if you have multiple branches, as the entire tree shares revision numbers.
Ken Liu
+1  A: 

Here is how I implemented this, in case anyone is curious:

<!-- First, we need to get the svn repository root URL by parsing
the output of 'svn info'. -->
<exec executable="svn" failonerror="yes">
    <arg line="info"/>

    <redirector outputproperty="svninfo.out" errorproperty="svninfo.err">
        <outputfilterchain>
            <linecontains>
                <contains value="Repository Root: "/>
            </linecontains>

            <tokenfilter>
                <replacestring from="Repository Root: " to=""/>
            </tokenfilter>
        </outputfilterchain>
    </redirector>
</exec>

<echo level="verbose" message="Root from svn info: ${svninfo.out}"/>

<!-- Set the svn.root property from the svn info output, and append
the module prefix if it exists. The module prefix allows multiple
projects to use the same repository root. -->
<condition property="svn.root" value="${svninfo.out}/${svn.module.prefix}">
    <isset property="svn.module.prefix"/>
</condition>
<!-- Note that the next line will have no effect if the property was
set in the condition above, since ant properties are immutable. The
effect is an "else", if the condition above is NOT true. -->
<property name="svn.root" value="${svninfo.out}"/>
<echo level="verbose" message="Root: ${svn.root}"/>

<!-- Verify the tags directory exists. -->
<exec executable="svn"
      failonerror="no"
      outputproperty="null"
      errorproperty="svn.ls.error">
    <arg line="ls ${svn.root}/tags"/>
</exec>
<fail>
Cannot find 'tags' subdirectory.

${svn.ls.error}

The subversion repository is expected to have 'trunk', 'branches', and 'tags'
subdirectories. The tag '${tag}' will need to be manually created.
    <condition>
        <not>
            <equals arg1="${svn.ls.error}" arg2="" trim="yes"/>
        </not>
    </condition>
</fail>

<!-- Finally, do the actual tag (copy in subversion). -->
<exec executable="svn" failonerror="yes">
    <arg line="cp . ${svn.root}/tags/${tag} -m 'Created tag ${tag}'"/>
</exec>

I also want to point out that I am aware of the differences between CVS and subversion with respect to tagging, and that the subversion revision is, for all practical purposes, equivalent to the tag. Unfortunately, that is not really relevant; my users want a symbolic name composed of the module name and a (different) version number.

Jason Day