Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check out a CVS branch point?

Tags:

cvs

First, I have to admit I screwed up a little with CVS. I had a release tag releaseX, which was done some time back (i.e., not HEAD). Then I decided I need a maintenance branch at that point. Instead of creating a branch tag (branchX) in addition to releaseX, I deleted the release tag and created a branch tag (erroneously) named releaseX. I then proceeded to work on that maintenance branch, and created releaseX1, releaseX2 etc.

My problem: when I check out releaseX, I get the branch head, i.e. the latest code from that branch. What I need now is the code at the branch point, i.e. the former releaseX code.

Is there any way to do this?

Reverting to earlier repository version from backup is not an option.

Edit: I know I can work around it by doing a date-based checkout. I would like to know if it's possible to still do a tag-based one.

Update (Re @Philip Derbeko): I know that CVS does not correlate between files. But CVS does have the information where the branch occured. In ViewVC, I can even see it:

File X - Revision 1.y - Branch: MAIN - Branch point for: releaseX

The next file revision is:

File X - Revision 1.y.2.1 - Branch: releaseX - CVS Tags: releaseX1

The metadata is apparently there. Hence my question: Is it possible to check out the branch point, not the branch HEAD?

like image 948
DevSolar Avatar asked Jun 23 '09 07:06

DevSolar


People also ask

How do I checkout a CVS repository?

Use “cvs checkout” giving the name of the directory in the cvs repository you want to checkout, where the name you give is a directory under CVSROOT, presently $CD_SOFT/cvs (eg app/alh, script). The directory you give, and all subdirectories, will be placed in your working directory.

How do I find my CVS branch?

You can retrieve a branch in one of two ways: by checking it out fresh from the repository, or by switching an existing working copy over to the branch. It does not matter if the working copy was originally on the main trunk or on some other branch – the above command will switch it to the named branch.

How do I commit to a branch at CVS?

Use the command cvs tag -b branchname to create the branch. The tag command tags the last revisions that were committed to the repository or updated from the repository, which hopefully are the revisions before the changes you want to branch off of.

How do I change my branch at CVS?

5 Branching and merging Later you can move changes from one branch to another branch (or the main trunk) by merging. Merging involves first running cvs update -j , to merge the changes into the working directory. You can then commit that revision, and thus effectively copy the changes onto another branch.


3 Answers

Since you did not set a tag when branching, the only way I see, is to use the date approach. But you can still set that tag now. Lets assume you want to call that initial release "ReleaseX0", because unfortunately the name "ReleaseX" is already occupied for the branch. Depending on whether you want to set the tag on the branch or on the MAIN branch you can use either of these checkout commands:

cvs co -r releaseX -D "2008-12-30" modulename
cvs co -D "2008-12-30" modulename

Then set the tag:

cvs tag releaseX0

From now on you can checkout this release in the same way as you checkout the other releases.


As you pointed out in your comment to my initial response, renaming the branch from releaseX to releaseX_branch like this does not work:

cvs rtag -r releaseX releaseX_branch modulename
cvs rtag -d releaseX modulename

To rename a branch cvs admin -N < old >:< new > needs to be used. But renaming a branch is a bad idea anyway. (I am sorry for bringing it up in the first place ;-).), Renaming will mess up the working copies of other users. So it is probably best to stick with the original name.

like image 59
Ralph Avatar answered Sep 20 '22 01:09

Ralph


This comes four years later - it won't help you out, but it may help someone like myself trying to figure this problem out via google. I recently ran across the same problem with a merge that I am doing. I need to see the parent ancestor of files between the branch head and mainline head - which is the branch point. The branch point was not tagged and was created years ago - at an indeterminate time so tagging by time is no help.

The solution I came up with is figuring out the branch point revision number for each file and applying a branch point tag via a PERL script. It is very similar to what is pointed out here: http://www.cvsnt.org/pipermail/cvsnt/2006-February/024063.html

A little CVS background: In CVS branches are kept track of by adding a .0.x to the mainline revision of the file. For example if the mainline revision is 1.18, then a branch off of that will be 1.18.0.x, X the branch number (if there were already a branch in existence from this revision number then x would be 2 -> 1.18.0.2). The ".0" is dropped when you revise files on the branch so the branch will be 1.18.0.2 in this example and the first revision will be 1.18.2.1 and the second revision will be 1.18.2.2. A lot of this is drawn from this: http://www.astro.princeton.edu/~rhl/cvs-branches.html#branchnumbers

I found a perl script here: https://github.com/effectiveprogramming/ep-cvs/wiki/List-CVS-Tags that will either list the CVS tags when given the -t switch or if given a branch name tag it will list all files and revision associated with that tag. This script uses this command: "cvs -q status -R -v filename" which will list the branches with the ".0" part hidden, so you simply remove the ".x" from the revision number of the desired branch name. So I took the script on github and added a few lines. You simply execute this script with a branch name as an argument and it will tag the branch point with the same branch name with an _BP appended to it.

#!/usr/bin/perl

# Simple perl script.  Given a branch name, determine 
# the file revision a branch was created on for all 
# files in a repository and tag those files with a user defined tag.    
# Created 2013/04/05 CPG
# $Id: lstag,v 1.1 2002/09/26 10:02:53 ec Exp $

use strict;

$::VERSION = "1.0";
$::cvs_ID = '$Id: lstag,v 1.1 2002/09/26 10:02:53 ec Exp $'; #'

undef ($::repo);
# Try #1 to get CVS repository location
if (-r "CVS/Root") {
    open (INF, "<CVS/Root") || die "Failed to read CVS/Root file!\n";
    ###chop ($::repo = <INF>);
    $::repo = <INF>;
    close (INF);
} else {
    # Try #2 to get CVS repository location
    if (!$::ENV{"CVSROOT"}) {
        print "CVSROOT environment variable not found!\n";
        print "CVS not detected...\n";
        exit (10);
    }
}
$::repo =~ s/\n$//g;
$::repo =~ s/\r$//g;
($::repo) = $::repo =~ /([^:]+)$/;
$::repo =~ s/\/*$/\//;

### print "CVS repository at $::repo\n";


# Check commandline arguments
if ($#ARGV < 0) {
    print "Missing argument!\n";
    print "Usage: $0 [ tag]\n\n";
    print "Where: tag is number of "; 
    print "     each file this tag was created.\n";
    print "       tag   shows list of files with this tag\n";
    print "\n";
    exit (1);
}

# Get desired tagname
$::tag = $ARGV[0];
$::taglist = 0;
if ($::tag eq "-l") {
    $::taglist = 1;
}



# Run cvs status and catch output
open (INF, "cvs -q status -R -v |") || die "Failed to run cvs status command!\n";
chop (@::STATUS = <INF>);
close (INF);

# Parse status
$::state = 0;
$::fpath = $::frpath = $::fname = $::fstatus = $::ftag = $::ftagrev = "!UNINITIALIZED VARIABLE!";
undef (%::TAGS);
$::found = 0;
for $::lc (0 .. $#::STATUS) {
    $_ = $::STATUS[$::lc];
    if ($::state == 0) {
        if (/^File:/) {
            ($::fname, $::fstatus) = /^File:\s+(\S+\s*\S+)\s+Status:\s+(\S+)/;
            $::state = 1;
        }
        next;
    }
    if ($::state == 1) {
        if (/^\s+Repository revision:/) {
            ($::frpath) = /(\/.*),v/;
            ($::fpath) = $::frpath =~ /^$::repo(.*)$/;
            push @::INFOL, ( $::fpath );
            $::current = $::fpath;
            $::INFO{$::current}->{"rpath"}  = $::frpath;
            $::INFO{$::current}->{"name"}   = $::fname;
            $::INFO{$::current}->{"status"} = $::fstatus;
            $::fpath = $::frpath = $::fname = $::fstatus = "!UNINITIALIZED VARIABLE!";
            $::state = 2;
        }
        next;
    }
    if ($::state == 2) {
        if (/^\s+Existing Tags:/) {
            $::state = 3;
        }
        next;
    }
    if (/^\s+\S+\s+\([^:]+:/) {
        ($::ftag, $::ftagrev) = /^\s+(\S+)\s+\([^:]+:\s+([^\)]+)\)/;
        if ($::taglist) {
            $::TAGL{$::ftag}++;
        }
        if ($::ftag eq $::tag) {
            $::found++;
            $::INFO{$::current}->{"tag"} = $::ftag;
            $::INFO{$::current}->{"tagrev"} = $::ftagrev;
            $::ftag = $::ftagrev = "!UNINITIALIZED VARIABLE!";
        }
    } else { $::state = 0; }
}

# Print results
print "$0 - CVS tag and file lister version $::VERSION\n";
print "ID: $::cvs_ID\n\n";
if ($::taglist) {
    print "List of all known tags:\n\n";
    foreach $::key (sort {uc($a) cmp uc($b)} keys %::TAGL) {
        print "$::key\n";
    }
} else {
    print "Files with tag \"$::tag\":";
    if ($::found > 0) {
        print "\n\n";
    } else {
        print "  NONE\n";
    }
    for $::i (0 .. $#::INFOL) {
        if (!defined($::INFO{$::INFOL[$::i]}->{"tag"})) {
            next;
        }
        $::name = $::INFOL[$::i];
        $::status = $::INFO{$::name}->{"status"};
        $::tagrev = $::INFO{$::name}->{"tagrev"};

        #  Code added to apply a tag to a branch point:
        # regex to strip from last '.' to end of revision #.
        $::ge = '\.[^\.]*$';

        $::branchPtRev = $::tagrev;
        $_ = $::branchPtRev;
        s/$::ge//;
        $::cmd = "cvs tag -r".$_." ".$::tag."_BP " . $::name . " xst";

        #printf "%10s %s\n", ($_, $::name);

        #  printf "%10s %10s\n", ($::branchPtRev, $_);

        #printf $::cmd;
        #  printf "\n";

        # Run cvs command
        open (INF, $::cmd) || die "Failed to run cvs status command!\n";
        close (INF);
    }
}

print "Script Completed Successfully\n";
like image 45
Chuck Avatar answered Sep 23 '22 01:09

Chuck


I'm not a CVS expert. Here's what I would do if I were in your place. CVS marks file versions in HEAD branch as 1.N, when you branch file at version X, commits to that branch get marked as 1.X.B.M . So after checking out releaseX, I would write a script that would update files that were changed in branch to a version 1.X, and then tag my working copy. Maybe there is a simpler way, but I don't know about it.

like image 30
Juozas Kontvainis Avatar answered Sep 21 '22 01:09

Juozas Kontvainis