This version of my ".trunk" patch
contains fixes for "cvs log -r.trunk"
in the case of oddball revision numbers created by
the likes of "cvs commit -r" and sanity.sh test
cases involving such revisions.

At this point, as far as I know, the illusion that 
".trunk" is a real branch tag is as complete as it
needs to be.  (tiny differences persist, for instance
it doesn't show up in the list of tags output by
"cvs log" the way a real branch tag does, but that's
because it's not a real branch tag.)  In all the
important ways I'm aware of it functions exactly
as a branch tag.  

So, let me know if you can break this illusion and I'll
try to fix whatever you find.

I release this patch under the GPL, in case that doesn't
go without saying.

It passwd "make check" and "make remotecheck" for me
under Linux (Red Hat 6.1, I think)

The patch is against the current (6-28-2000) cvs source.

-- steve






__________________________________________________
Do You Yahoo!?
Get Yahoo! Mail - Free email you can access from anywhere!
http://mail.yahoo.com/
Index: NEWS
===================================================================
RCS file: /home2/cvsroot/ccvs/NEWS,v
retrieving revision 1.79
diff -c -r1.79 NEWS
*** NEWS        2000/05/05 14:48:37     1.79
--- NEWS        2000/06/28 03:45:08
***************
*** 1,5 ****
--- 1,8 ----
  Changes since 1.10:
  
+ * New ".trunk" pseudo-branch-tag added which acts just like a branch
+   tag, but means the trunk.
+ 
  * The "cvs history" command output format has changed -- the date
  now includes the year and is given is ISO 8601 format (yyyy-mm-dd).
  
Index: doc/ChangeLog
===================================================================
RCS file: /home2/cvsroot/ccvs/doc/ChangeLog,v
retrieving revision 1.622
diff -c -r1.622 ChangeLog
*** ChangeLog   2000/06/14 17:41:56     1.622
--- ChangeLog   2000/06/28 03:45:25
***************
*** 1,3 ****
--- 1,7 ----
+ 2000-06-18  Stephen Cameron <[EMAIL PROTECTED]>
+ 
+       * cvs.texinfo:  Document new ".trunk" pseudo branch tag.
+ 
  2000-04-03  Pavel Roskin  <[EMAIL PROTECTED]>
  
        * cvs.texinfo (Telling CVS to notify you): Remove backslashes
Index: doc/cvs.texinfo
===================================================================
RCS file: /home2/cvsroot/ccvs/doc/cvs.texinfo,v
retrieving revision 1.489
diff -c -r1.489 cvs.texinfo
*** cvs.texinfo 2000/06/14 17:41:56     1.489
--- cvs.texinfo 2000/06/28 03:46:30
***************
*** 3258,3264 ****
  as internal numbers that @sc{cvs} maintains, and tags
  provide a better way to distinguish between things like
  release 1 versus release 2 of your product
! (@pxref{Tags}).  However, if you want to set the
  numeric revisions, the @samp{-r} option to @code{cvs
  commit} can do that.  The @samp{-r} option implies the
  @samp{-f} option, in the sense that it causes the
--- 3258,3273 ----
  as internal numbers that @sc{cvs} maintains, and tags
  provide a better way to distinguish between things like
  release 1 versus release 2 of your product
! (@pxref{Tags}).  
! 
! In fact, let's just go ahead and say right now that you are 
! STRONGLY advised against using @samp{cvs commit -r}
! to manually set revision numbers.  It is STRONGLY recommended that
! you just allow CVS to assign revision numbers however it likes.
! You should use tags instead of trying to assign some meaning to 
! revision numbers.
! 
! However, if, with that caution in mind, you still want to set the
  numeric revisions, the @samp{-r} option to @code{cvs
  commit} can do that.  The @samp{-r} option implies the
  @samp{-f} option, in the sense that it causes the
***************
*** 3313,3331 ****
  @cindex Name, symbolic (tag)
  @cindex HEAD, as reserved tag name
  @cindex BASE, as reserved tag name
  You can use the @code{tag} command to give a symbolic name to a
  certain revision of a file.  You can use the @samp{-v} flag to the
  @code{status} command to see all tags that a file has, and
  which revision numbers they represent.  Tag names must
  start with an uppercase or lowercase letter and can
  contain uppercase and lowercase letters, digits,
! @samp{-}, and @samp{_}.  The two tag names @code{BASE}
! and @code{HEAD} are reserved for use by @sc{cvs}.  It
  is expected that future names which are special to
  @sc{cvs} will be specially named, for example by
  starting with @samp{.}, rather than being named analogously to
  @code{BASE} and @code{HEAD}, to avoid conflicts with
! actual tag names.
  @c Including a character such as % or = has also been
  @c suggested as the naming convention for future
  @c special tag names.  Starting with . is nice because
--- 3322,3342 ----
  @cindex Name, symbolic (tag)
  @cindex HEAD, as reserved tag name
  @cindex BASE, as reserved tag name
+ @cindex .trunk, as reserved tag name
  You can use the @code{tag} command to give a symbolic name to a
  certain revision of a file.  You can use the @samp{-v} flag to the
  @code{status} command to see all tags that a file has, and
  which revision numbers they represent.  Tag names must
  start with an uppercase or lowercase letter and can
  contain uppercase and lowercase letters, digits,
! @samp{-}, and @samp{_}.  The three tag names @code{BASE},
! @code{HEAD}, and @code{.trunk} are reserved for use by @sc{cvs}.  It
  is expected that future names which are special to
  @sc{cvs} will be specially named, for example by
  starting with @samp{.}, rather than being named analogously to
  @code{BASE} and @code{HEAD}, to avoid conflicts with
! actual tag names.  (The previous sentence is the reason `.trunk'
! begins with a dot, since it predates `.trunk'.
  @c Including a character such as % or = has also been
  @c suggested as the naming convention for future
  @c special tag names.  Starting with . is nice because
***************
*** 3630,3636 ****
  If you specify the @samp{-r} option to @code{cvs rtag},
  then @sc{cvs} tags the files which have been removed,
  and thereby avoids this problem.  For example, one
! might specify @code{-r HEAD} to tag the head.
  
  On the subject of adding and removing files, the
  @code{cvs rtag} command has a @samp{-a} option which
--- 3641,3648 ----
  If you specify the @samp{-r} option to @code{cvs rtag},
  then @sc{cvs} tags the files which have been removed,
  and thereby avoids this problem.  For example, one
! might specify @code{-r HEAD} to tag the head, though
! you may prefer the pseudo branch tag @code{-r .trunk}.
  
  On the subject of adding and removing files, the
  @code{cvs rtag} command has a @samp{-a} option which
***************
*** 3692,3698 ****
  you delete them with @samp{cvs update -A}.  The
  @samp{-A} option retrieves the version of the file from
  the head of the trunk, and forgets any sticky tags,
! dates, or options.
  
  @cindex Sticky date
  The most common use of sticky tags is to identify which
--- 3704,3714 ----
  you delete them with @samp{cvs update -A}.  The
  @samp{-A} option retrieves the version of the file from
  the head of the trunk, and forgets any sticky tags,
! dates, or options.  (Note, `-A' clears ALL sticky tags,
! including -kb, etc., which you may not want, if for
! example you simply want to switch your working directory
! to the trunk.  For this purpose, you may want to use
! the special `.trunk' branch tag name for the trunk.)
  
  @cindex Sticky date
  The most common use of sticky tags is to identify which
***************
*** 8073,8078 ****
--- 8089,8095 ----
  @item -r @var{tag}
  @cindex HEAD, special tag
  @cindex BASE, special tag
+ @cindex .trunk, special tag
  Use the revision specified by the @var{tag} argument instead of the
  default @dfn{head} revision.  As well as arbitrary tags defined
  with the @code{tag} or @code{rtag} command, two special tags are
***************
*** 8102,8107 ****
--- 8119,8129 ----
  @c same for "diff" as for everyone else), test cases
  @c written (similar to the ones in "head"), new tests
  @c cases written for things like default branches, &c.
+ @c
+ @c Hmm.  I've made ".trunk", which works as ".thead"
+ @c above, but additionally works like a branch tag 
+ @c for the trunk, that is, you can commit changes to it.
+ @c 
  
  The tag specification is sticky when you use this
  @c option
***************
*** 8208,8213 ****
--- 8230,8238 ----
  @c the optional argument).  Note that -bHEAD does not
  @c work, as of 17 Sep 1997, but probably will once "cvs
  @c admin" is internal to CVS.
+ @c
+ @c Hmm, I wonder if ".trunk" works with "cvs admin"?
+ @c 
  
  @cindex Comment leader
  @item -c@var{string}
***************
*** 8819,8825 ****
  either a branch, or a revision on the main trunk that
  is higher than any existing revision number
  (@pxref{Assigning revisions}).  You
! cannot commit to a specific revision on a branch.
  @c FIXME: Need xref for branch case.
  @end table
  
--- 8844,8863 ----
  either a branch, or a revision on the main trunk that
  is higher than any existing revision number
  (@pxref{Assigning revisions}).  You
! cannot commit to a specific revision on a branch.  Note,
! `.trunk' is valid as a branch tag for the `-r' option, and
! will commit the file as the newest revision on the trunk.
! @c
! @c However, if the file in the working directory has a 
! @c sticky tag other than .trunk, the sticky tag will not
! @c be changed, and even if the file differs from the repository
! @c revision, it will be marked 'up-to-date',
! @c and a subsequent 'cvs commit' will not commit those changes.
! @c no doubt this is a bug, though I'm not sure what the right 
! @c fix, is, either change the sticky tag, or leave the file's
! @c status as 'locally-modified'.
! @c
! 
  @c FIXME: Need xref for branch case.
  @end table
  
***************
*** 9010,9015 ****
--- 9048,9069 ----
  
  One or both @samp{-r} options can be replaced by a
  @samp{-D @var{date}} option, described above.
+ 
+ CAUTION: the special tag `HEAD' is interpreted by
+ the `cvs diff' command in a different way than it
+ is interpreted by any other cvs command.  `cvs diff'
+ takes `-r HEAD' to mean the following, as nearly as
+ I can tell:
+ 
+ For `cvs diff', `HEAD' means the most recent revision
+ on the `current branch' (taking into account whatever
+ sticky tags are active in your working directory) unless
+ a particular file has not had a revision committed to the
+ branch, in which case the head revision of the trunk is
+ taken.  This is clearly wrong.  You should use either
+ `.trunk' or the branch tag name rather than `HEAD'.  
+ (The `.trunk' tag acts as a branch tag name for the trunk.)
+ 
  @end table
  
  @c Conceptually, this is a disaster.  There are 3
Index: src/ChangeLog
===================================================================
RCS file: /home2/cvsroot/ccvs/src/ChangeLog,v
retrieving revision 1.1922
diff -c -r1.1922 ChangeLog
*** ChangeLog   2000/06/27 20:46:53     1.1922
--- ChangeLog   2000/06/28 03:46:50
***************
*** 1,3 ****
--- 1,27 ----
+ 
+ 2000-06-28  Stephen Cameron <[EMAIL PROTECTED]>
+ 
+       * checkout.c (checkout): Add ".trunk" pseudo  branch tag feature
+       * commit.c (classify_file_internal): Ditto 
+           (check_fileproc): Ditto
+           (remove_file): Ditto
+         * cvs.h: add definition of TAG_TRUNK (".trunk") plus comments
+         * diff.c: (diff_fileproc): Handle ".trunk" pseudo branch tag.
+               (diff_file_nodiff): Ditto
+       * entriex.c (WriteTag): modified to magically treat ".trunk" as
+               a branch tag.
+       * log.c (cvslog): Modified to handle ".trunk" pseudo branch tag.
+       * rcs.c (RCS_tag2rev): 
+               (RCS_gettag): Modified to reject ".trunk" reserved tag
+               (RCS_settag): Ditto
+               (RCS_trunk): New function
+       * rcs.h (RCS_trunk): New function prototype
+       * sanity.sh: New suite of tests for ".trunk", called 
+               "btrunktag"
+       * status.c (status_fileproc): handle ".trunk" pseudo branch tag
+       * tag.c (tag_check_valid): handle ".trunk" pseudo branch tag
+       * admin.c (admin_fileproc): handle ".trunk" pseudo branch tag
+ 
  2000-06-26  Pavel Roskin <[EMAIL PROTECTED]>
        and Larry Jones  <[EMAIL PROTECTED]>
  
Index: src/admin.c
===================================================================
RCS file: /home2/cvsroot/ccvs/src/admin.c,v
retrieving revision 1.64
diff -c -r1.64 admin.c
*** admin.c     2000/06/13 21:30:44     1.64
--- admin.c     2000/06/28 03:46:53
***************
*** 801,810 ****
                break;
  
            case 'l':
!               status |= RCS_lock (rcs, arg[2] ? arg + 2 : NULL, 0);
                break;
            case 'u':
!               status |= RCS_unlock (rcs, arg[2] ? arg + 2 : NULL, 0);
                break;
            default: assert(0); /* can't happen */
        }
--- 801,824 ----
                break;
  
            case 'l':
!               {
!                       char *rev;
! 
!                       rev = arg[2] ? arg + 2 : NULL;
!                       if (rev && strcmp(rev, TAG_TRUNK)==0)
!                               rev = NULL;
!                       status |= RCS_lock (rcs, rev, 0);
!               }
                break;
            case 'u':
!               {
!                       char *rev;
! 
!                       rev = arg[2] ? arg + 2 : NULL;
!                       if (rev && strcmp(rev, TAG_TRUNK)==0)
!                               rev = NULL;
!                       status |= RCS_unlock (rcs, rev, 0);
!               }
                break;
            default: assert(0); /* can't happen */
        }
Index: src/checkout.c
===================================================================
RCS file: /home2/cvsroot/ccvs/src/checkout.c,v
retrieving revision 1.89
diff -c -r1.89 checkout.c
*** checkout.c  2000/06/15 15:33:30     1.89
--- checkout.c  2000/06/28 03:46:57
***************
*** 197,203 ****
                break;
            case 'r':
                tag = optarg;
!               checkout_prune_dirs = 1;
                break;
            case 'D':
                date = Make_Date (optarg);
--- 197,204 ----
                break;
            case 'r':
                tag = optarg;
!               if (strcmp(optarg, TAG_TRUNK) != 0)
!                       checkout_prune_dirs = 1;
                break;
            case 'D':
                date = Make_Date (optarg);
Index: src/commit.c
===================================================================
RCS file: /home2/cvsroot/ccvs/src/commit.c,v
retrieving revision 1.162
diff -c -r1.162 commit.c
*** commit.c    2000/06/21 22:28:36     1.162
--- commit.c    2000/06/28 03:47:05
***************
*** 694,703 ****
      noexec = quiet = really_quiet = 1;
  
      /* handle specified numeric revision specially */
!     if (saved_tag && isdigit ((unsigned char) *saved_tag))
      {
        /* If the tag is for the trunk, make sure we're at the head */
!       if (numdots (saved_tag) < 2)
        {
            status = Classify_File (finfo, (char *) NULL, (char *) NULL,
                                    (char *) NULL, 1, aflag, vers, 0);
--- 694,704 ----
      noexec = quiet = really_quiet = 1;
  
      /* handle specified numeric revision specially */
!     if (saved_tag && (isdigit ((unsigned char) *saved_tag) || 
!                     strcmp(saved_tag, TAG_TRUNK) == 0))
      {
        /* If the tag is for the trunk, make sure we're at the head */
!       if (numdots (saved_tag) < 2 || strcmp(saved_tag, TAG_TRUNK) == 0 )
        {
            status = Classify_File (finfo, (char *) NULL, (char *) NULL,
                                    (char *) NULL, 1, aflag, vers, 0);
***************
*** 753,758 ****
--- 754,760 ----
      else
        status = Classify_File (finfo, saved_tag, (char *) NULL, (char *) NULL,
                                1, 0, vers, 0);
+ 
      noexec = save_noexec;
      quiet = save_quiet;
      really_quiet = save_really_quiet;
***************
*** 826,835 ****
             * some quick sanity checks; if no numeric -r option specified:
             *  - can't have a sticky date
             *  - can't have a sticky tag that is not a branch
             * Also,
             *  - if status is T_REMOVED, can't have a numeric tag
             *  - if status is T_ADDED, rcs file must not exist unless on
!            *    a branch
             *  - if status is T_ADDED, can't have a non-trunk numeric rev
             *  - if status is T_MODIFIED and a Conflict marker exists, don't
             *    allow the commit if timestamp is identical or if we find
--- 828,838 ----
             * some quick sanity checks; if no numeric -r option specified:
             *  - can't have a sticky date
             *  - can't have a sticky tag that is not a branch
+              *    (except if it's TAG_TRUNK)
             * Also,
             *  - if status is T_REMOVED, can't have a numeric tag
             *  - if status is T_ADDED, rcs file must not exist unless on
!            *    a branch (and count TAG_TRUNK as a branch)
             *  - if status is T_ADDED, can't have a non-trunk numeric rev
             *  - if status is T_MODIFIED and a Conflict marker exists, don't
             *    allow the commit if timestamp is identical or if we find
***************
*** 846,851 ****
--- 849,855 ----
                    return (1);
                }
                if (status == T_MODIFIED && vers->tag &&
+                   strcmp(vers->tag, TAG_TRUNK)!=0 &&
                    !RCS_isbranch (finfo->rcs, vers->tag))
                {
                    error (0, 0,
***************
*** 924,930 ****
            }
            if (status == T_ADDED)
            {
!               if (vers->tag == NULL)
                {
                    char *rcs;
  
--- 928,934 ----
            }
            if (status == T_ADDED)
            {
!               if (vers->tag == NULL || strcmp(vers->tag, TAG_TRUNK) == 0)
                {
                    char *rcs;
  
***************
*** 995,1001 ****
            li = ((struct logfile_info *)
                  xmalloc (sizeof (struct logfile_info)));
            li->type = status;
!           li->tag = xstrdup (vers->tag);
            li->rev_old = xstrdup (vers->vn_rcs);
            li->rev_new = NULL;
            p->data = (char *) li;
--- 999,1010 ----
            li = ((struct logfile_info *)
                  xmalloc (sizeof (struct logfile_info)));
            li->type = status;
! 
!           if (vers->tag != NULL && strcmp(vers->tag, TAG_TRUNK) == 0)
!               li->tag = NULL;
!           else
!               li->tag = xstrdup (vers->tag);
! 
            li->rev_old = xstrdup (vers->vn_rcs);
            li->rev_new = NULL;
            p->data = (char *) li;
***************
*** 1007,1020 ****
            p->delproc = ci_delproc;
            ci = (struct commit_info *) xmalloc (sizeof (struct commit_info));
            ci->status = status;
!           if (vers->tag)
                if (isdigit ((unsigned char) *vers->tag))
                    ci->rev = xstrdup (vers->tag);
                else
                    ci->rev = RCS_whatbranch (finfo->rcs, vers->tag);
            else
                ci->rev = (char *) NULL;
!           ci->tag = xstrdup (vers->tag);
            ci->options = xstrdup(vers->options);
            p->data = (char *) ci;
            (void) addnode (cilist, p);
--- 1016,1035 ----
            p->delproc = ci_delproc;
            ci = (struct commit_info *) xmalloc (sizeof (struct commit_info));
            ci->status = status;
! 
!           if (vers->tag && strcmp(vers->tag, TAG_TRUNK)!=0)
                if (isdigit ((unsigned char) *vers->tag))
                    ci->rev = xstrdup (vers->tag);
                else
                    ci->rev = RCS_whatbranch (finfo->rcs, vers->tag);
            else
                ci->rev = (char *) NULL;
! 
!           if (vers->tag && strcmp(vers->tag, TAG_TRUNK) == 0)
!               ci->tag = (char *) NULL;
!           else
!               ci->tag = xstrdup (vers->tag);
! 
            ci->options = xstrdup(vers->options);
            p->data = (char *) ci;
            (void) addnode (cilist, p);
***************
*** 1646,1652 ****
        error (1, 0, "internal error: no parsed RCS file");
  
      branch = 0;
!     if (tag && !(branch = RCS_nodeisbranch (finfo->rcs, tag)))
      {
        /* a symbolic tag is specified; just remove the tag from the file */
        if ((retcode = RCS_deltag (finfo->rcs, tag)) != 0)
--- 1661,1668 ----
        error (1, 0, "internal error: no parsed RCS file");
  
      branch = 0;
!     if (tag && strcmp(tag, TAG_TRUNK)!=0 && 
!         !(branch = RCS_nodeisbranch (finfo->rcs, tag)))
      {
        /* a symbolic tag is specified; just remove the tag from the file */
        if ((retcode = RCS_deltag (finfo->rcs, tag)) != 0)
Index: src/cvs.h
===================================================================
RCS file: /home2/cvsroot/ccvs/src/cvs.h,v
retrieving revision 1.202
diff -c -r1.202 cvs.h
*** cvs.h       2000/06/14 19:38:15     1.202
--- cvs.h       2000/06/28 03:47:11
***************
*** 245,256 ****
  #endif /* USE_VMS_FILENAMES */
  
  /*
!  * Special tags. -rHEAD       refers to the head of an RCS file, regardless of any
!  * sticky tags. -rBASE        refers to the current revision the user has checked
!  * out This mimics the behaviour of RCS.
   */
  #define       TAG_HEAD        "HEAD"
  #define       TAG_BASE        "BASE"
  
  /* Environment variable used by CVS */
  #define       CVSREAD_ENV     "CVSREAD"       /* make files read-only */
--- 245,278 ----
  #endif /* USE_VMS_FILENAMES */
  
  /*
!  * Special tags. 
!  * -rHEAD refers to the tip revision on the trunk, _except_ for
!  *  "cvs diff".  "cvs diff" interprets -rHEAD to mean the tip
!  *  revision of the current branch, however, that behavior is 
!  *  broken, because if the file has not been branched, that is,
!  *  the revision on the branch is the same one that's on the trunk
!  *  then the tip revision of the trunk is reported.  Also, it's
!  *  not clear (to me) what happens in the instance of a sticky
!  *  non-branch tag what -rHEAD is supposed to mean.  So, -rHEAD
!  *  is probably a lost cause, unless you redefine what it means.
!  *
!  * -rBASE refers to the current revision the user has checked
!  *  out This mimics the behaviour of RCS.
!  *
!  * -r.trunk refers to the head revision on the trunk.  
!  *  (necessary for this to exist so that the trunk is not anonymous.)
!  *  "cvs commit" and "cvs status" have been hacked to believe ".trunk"
!  *  is a "branch tag", even though, really, it's not.
!  *  This is more like how I think -rHEAD probably should have 
!  *  always worked.  I chose ".trunk" as the name for various 
!  *  reasons, (lowercase is easier to type, nobody currently has
!  *  any real tag names that begin with dots.)
!  *
   */
+ 
  #define       TAG_HEAD        "HEAD"
  #define       TAG_BASE        "BASE"
+ #define       TAG_TRUNK       ".trunk"
  
  /* Environment variable used by CVS */
  #define       CVSREAD_ENV     "CVSREAD"       /* make files read-only */
Index: src/diff.c
===================================================================
RCS file: /home2/cvsroot/ccvs/src/diff.c,v
retrieving revision 1.83
diff -c -r1.83 diff.c
*** diff.c      1999/04/15 00:12:26     1.83
--- diff.c      2000/06/28 03:47:13
***************
*** 461,466 ****
--- 461,477 ----
                    if (head != NULL)
                        free (head);
                }
+               else /* special handling for TAG_TRUNK */
+               if (diff_rev1 && strcmp (diff_rev1, TAG_TRUNK) == 0)
+               {
+                   char *trunk =
+                       (vers->vn_rcs == NULL
+                        ? NULL
+                        : RCS_trunk (vers->srcfile));
+                   exists = trunk != NULL;
+                   if (trunk != NULL)
+                       free (trunk);
+               }
                else
                {
                    Vers_TS *xvers;
***************
*** 843,855 ****
            use_rev1 = ((vers->vn_rcs == NULL || vers->srcfile == NULL)
                        ? NULL
                        : RCS_branch_head (vers->srcfile, vers->vn_rcs));
!       else
!       {
!           xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1, 1, 0);
!           if (xvers->vn_rcs != NULL)
!               use_rev1 = xstrdup (xvers->vn_rcs);
!           freevers_ts (&xvers);
!       }
      }
      if (diff_rev2 || diff_date2)
      {
--- 854,874 ----
            use_rev1 = ((vers->vn_rcs == NULL || vers->srcfile == NULL)
                        ? NULL
                        : RCS_branch_head (vers->srcfile, vers->vn_rcs));
!       else 
!         { 
!           /* special handling for TAG_TRUNK */
!             if (diff_rev1 && strcmp (diff_rev1, TAG_TRUNK) == 0)
!               use_rev1 = ((vers->vn_rcs == NULL || vers->srcfile == NULL)
!                           ? NULL
!                           : RCS_trunk (vers->srcfile));
!           else
!           {
!               xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1, 1, 0);
!               if (xvers->vn_rcs != NULL)
!                   use_rev1 = xstrdup (xvers->vn_rcs);
!               freevers_ts (&xvers);
!           }
!         } 
      }
      if (diff_rev2 || diff_date2)
      {
***************
*** 859,869 ****
                        ? NULL
                        : RCS_branch_head (vers->srcfile, vers->vn_rcs));
        else
!       {
!           xvers = Version_TS (finfo, NULL, diff_rev2, diff_date2, 1, 0);
!           if (xvers->vn_rcs != NULL)
!               use_rev2 = xstrdup (xvers->vn_rcs);
!           freevers_ts (&xvers);
        }
  
        if (use_rev1 == NULL)
--- 878,896 ----
                        ? NULL
                        : RCS_branch_head (vers->srcfile, vers->vn_rcs));
        else
!         {
!           /* special handling for TAG_TRUNK */
!           if (diff_rev2 && strcmp (diff_rev2, TAG_TRUNK) == 0)
!               use_rev2 = ((vers->vn_rcs == NULL || vers->srcfile == NULL)
!                           ? NULL
!                           : RCS_trunk (vers->srcfile));
!             else
!           {
!               xvers = Version_TS (finfo, NULL, diff_rev2, diff_date2, 1, 0);
!               if (xvers->vn_rcs != NULL)
!                   use_rev2 = xstrdup (xvers->vn_rcs);
!               freevers_ts (&xvers);
!           }
        }
  
        if (use_rev1 == NULL)
Index: src/entries.c
===================================================================
RCS file: /home2/cvsroot/ccvs/src/entries.c,v
retrieving revision 1.45
diff -c -r1.45 entries.c
*** entries.c   1999/09/29 19:24:15     1.45
--- entries.c   2000/06/28 03:47:16
***************
*** 662,667 ****
--- 662,674 ----
        fout = open_file (tmp, "w+");
        if (tag)
        {
+           /* Let's imagine that the magic TAG_TRUNK 
+                tag is a branch tag, even though it's really not.
+                this is so that "cvs add" will allow us to proceed */
+ 
+             if (strcmp(tag, TAG_TRUNK)==0)
+               nonbranch=0; 
+ 
            if (nonbranch)
            {
                if (fprintf (fout, "N%s\n", tag) < 0)
Index: src/log.c
===================================================================
RCS file: /home2/cvsroot/ccvs/src/log.c,v
retrieving revision 1.62
diff -c -r1.62 log.c
*** log.c       2000/06/21 22:28:37     1.62
--- log.c       2000/06/28 03:47:20
***************
*** 232,237 ****
--- 232,239 ----
                break;
            case 'r':
                *prl = log_parse_revlist (optarg);
+                 if (optarg != NULL && strcmp(optarg, TAG_TRUNK)==0)
+                         log_data.default_branch = 1;
                prl = &(*prl)->next;
                break;
            case 's':
***************
*** 905,925 ****
                nr->first = xstrdup (r->first);
            else
            {
!               if (RCS_nodeisbranch (rcs, r->first))
!                   nr->first = RCS_whatbranch (rcs, r->first);
                else
-                   nr->first = RCS_gettag (rcs, r->first, 1, (int *) NULL);
-               if (nr->first == NULL)
                {
!                   error (0, 0, "warning: no revision `%s' in `%s'",
!                          r->first, rcs->path);
!                   free (nr);
!                   continue;
                }
            }
  
            if (r->last == r->first)
!               nr->last = xstrdup (nr->first);
            else if (r->last == NULL || isdigit ((unsigned char) r->last[0]))
                nr->last = xstrdup (r->last);
            else
--- 907,935 ----
                nr->first = xstrdup (r->first);
            else
            {
!               if (r->first != NULL && strcmp(r->first,TAG_TRUNK)==0)
!                       nr->first = RCS_trunkorigin(rcs);
                else
                {
!                   if (RCS_nodeisbranch (rcs, r->first))
!                       nr->first = RCS_whatbranch (rcs, r->first);
!                   else
!                       nr->first = RCS_gettag (rcs, r->first, 1, (int *) NULL);
!                   if (nr->first == NULL)
!                   {
!                       error (0, 0, "warning: no revision `%s' in `%s'",
!                              r->first, rcs->path);
!                       free (nr);
!                       continue;
!                   }
                }
            }
  
+           if (r->last != NULL && strcmp(r->last, TAG_TRUNK)==0)
+               nr->last = RCS_trunk(rcs);
+           else
            if (r->last == r->first)
!               nr->last = xstrdup(nr->first);
            else if (r->last == NULL || isdigit ((unsigned char) r->last[0]))
                nr->last = xstrdup (r->last);
            else
Index: src/rcs.c
===================================================================
RCS file: /home2/cvsroot/ccvs/src/rcs.c,v
retrieving revision 1.235
diff -c -r1.235 rcs.c
*** rcs.c       2000/06/16 18:34:52     1.235
--- rcs.c       2000/06/28 03:47:47
***************
*** 2198,2203 ****
--- 2198,2207 ----
      if (tag && STREQ (tag, TAG_HEAD))
          return (RCS_head (rcs));
  
+     /* If tag is "TRUNK", special case to get the trunk RCS revision */
+     if (tag && STREQ (tag, TAG_TRUNK))
+         return (RCS_trunk (rcs));
+ 
      /* If valid tag let translate_symtag say yea or nay. */
      rev = translate_symtag (rcs, tag);
  
***************
*** 2248,2253 ****
--- 2252,2261 ----
  #endif
            return (RCS_head (rcs));
  
+     /* If tag is "TRUNK", special case to get trunk RCS revision */
+     if (tag && (STREQ (tag, TAG_TRUNK) ))
+           return (RCS_trunk (rcs));
+ 
      if (!isdigit ((unsigned char) tag[0]))
      {
        char *version;
***************
*** 2475,2480 ****
--- 2483,2490 ----
      if (isdigit ((unsigned char) *rev))
        return ((numdots (rev) & 1) == 0);
  
+     if (strcmp(rev, TAG_TRUNK)==0) return(1);
+ 
      version = translate_symtag (rcs, rev);
      if (version == NULL)
        return (0);
***************
*** 2793,2798 ****
--- 2803,2824 ----
  }
  
  /*
+  * Get the "trunk" of the RCS file. 
+  * or, the real head. 
+  * Returns NULL or a newly malloc'd string.
+  */
+ 
+ char *
+ RCS_trunk (rcs)
+     RCSNode *rcs;
+ {
+     /* make sure we have something to look at... */
+     assert (rcs != NULL);
+ 
+     return (xstrdup (rcs->head));
+ }
+ 
+ /*
   * Get the head of the RCS file.  If branch is set, this is the head of the
   * branch, otherwise the real head.
   * Returns NULL or a newly malloc'd string.
***************
*** 2814,2819 ****
--- 2840,2879 ----
        return (xstrdup (rcs->head));
  }
  
+ char *
+ RCS_trunkorigin(rcs)
+     RCSNode *rcs;
+ {
+     char *cur_rev = NULL;
+     Node *p;
+     RCSVers *vers = NULL;
+ 
+     if (rcs->head)
+     {
+       p = findnode (rcs->versions, rcs->head);
+       while (p != NULL)
+       {
+           vers = (RCSVers *) p->data;
+           /* if there is not a next version, then we're there */
+           cur_rev = vers->version;
+           if (vers->next != NULL)
+               p = findnode (rcs->versions, vers->next);
+             else
+               break;
+       }
+ 
+       /* p is either NULL, or else cur_rev points to the 1st rev on trunk */
+ 
+       if (p == NULL)
+               return(NULL);
+ 
+       return(cur_rev); /* must point to the first rev on the trunk */
+ 
+     }
+     else 
+       return(NULL);
+ }
+ 
  /*
   * Get the most recent revision, based on the supplied date, but use some
   * funky stuff and follow the vendor branch maybe
***************
*** 5561,5568 ****
  
      /* FIXME: This check should be moved to RCS_check_tag.  There is no
         reason for it to be here.  */
!     if (STREQ (tag, TAG_BASE)
!       || STREQ (tag, TAG_HEAD))
      {
        /* Print the name of the tag might be considered redundant
           with the caller, which also prints it.  Perhaps this helps
--- 5621,5629 ----
  
      /* FIXME: This check should be moved to RCS_check_tag.  There is no
         reason for it to be here.  */
!     if (   STREQ (tag, TAG_BASE)
!       || STREQ (tag, TAG_HEAD) 
!         || STREQ (tag, TAG_TRUNK))
      {
        /* Print the name of the tag might be considered redundant
           with the caller, which also prints it.  Perhaps this helps
Index: src/rcs.h
===================================================================
RCS file: /home2/cvsroot/ccvs/src/rcs.h,v
retrieving revision 1.55
diff -c -r1.55 rcs.h
*** rcs.h       2000/06/12 21:47:32     1.55
--- rcs.h       2000/06/28 03:47:48
***************
*** 202,207 ****
--- 202,209 ----
  int RCS_nodeisbranch PROTO((RCSNode *rcs, const char *tag));
  char *RCS_whatbranch PROTO((RCSNode *rcs, const char *tag));
  char *RCS_head PROTO((RCSNode * rcs));
+ char *RCS_trunk PROTO((RCSNode * rcs));
+ char *RCS_trunkorigin PROTO((RCSNode * rcs));
  int RCS_datecmp PROTO((char *date1, char *date2));
  time_t RCS_getrevtime PROTO((RCSNode * rcs, char *rev, char *date, int fudge));
  List *RCS_symbols PROTO((RCSNode *rcs));
Index: src/sanity.sh
===================================================================
RCS file: /home2/cvsroot/ccvs/src/sanity.sh,v
retrieving revision 1.608
diff -c -r1.608 sanity.sh
*** sanity.sh   2000/06/14 20:40:53     1.608
--- sanity.sh   2000/06/28 03:48:46
***************
*** 670,675 ****
--- 670,678 ----
        # Multiple root directories and low-level protocol tests.
        tests="${tests} multiroot multiroot2 multiroot3 multiroot4"
        tests="${tests} rmroot reposmv pserver server server2 client"
+       # ".trunck" pseudo branch tag
+       tests="${tests} btrunktag"
+       
  else
        tests="$*"
  fi
***************
*** 796,802 ****
  "${PROG} [a-z]*: nothing known about ssfile
  ${PROG} "'\[[a-z]* aborted\]: correct the above errors first!'
          cd ../..
!         dotest basica-5 "${testcvs} -q ci -m add-it" \
  "RCS file: ${TESTDIR}/cvsroot/first-dir/sdir/ssdir/ssfile,v
  done
  Checking in sdir/ssdir/ssfile;
--- 799,805 ----
  "${PROG} [a-z]*: nothing known about ssfile
  ${PROG} "'\[[a-z]* aborted\]: correct the above errors first!'
          cd ../..
!         dotest basica-5 "${testcvs}  -q ci -m add-it" \
  "RCS file: ${TESTDIR}/cvsroot/first-dir/sdir/ssdir/ssfile,v
  done
  Checking in sdir/ssdir/ssfile;
***************
*** 20538,20543 ****
--- 20541,21102 ----
            rm ${TESTDIR}/serveme
            CVS_SERVER=${testcvs}; export CVS_SERVER
          fi # skip the whole thing for local
+         ;;
+       btrunktag)
+ 
+         # test operations with "-r .trunk"
+ 
+         mkdir 1; cd 1
+         dotest trunkbtag1 "${testcvs} -q co -l -r .trunk ." ''
+         mkdir my-dir
+         dotest btrunktag2 "${testcvs} add my-dir" \
+ "Directory ${TESTDIR}/cvsroot/my-dir added to the repository
+ --> Using per-directory sticky tag "'`.'"trunk'"
+         cd ..
+         rm -r 1
+ 
+         dotest btrunktag3 "${testcvs} co -r .trunk my-dir" \
+ "${PROG} [a-z]*: Updating my-dir"
+ 
+         dotest btrunktag3 "${testcvs} co my-dir" \
+ "${PROG} [a-z]*: Updating my-dir"
+         cd my-dir
+ 
+         # add a file
+ 
+         echo xyz > xyz
+         dotest btrunktag4 "${testcvs} add xyz" \
+ "${PROG} [a-z]*: "'scheduling file `xyz'\'' for addition on branch `.trunk'\'"
+ ${PROG}"' [a-z]*: use '\''cvs commit'\'' to add this file permanently'
+ 
+         # commit the file
+ 
+         dotest btrunktag5 "${testcvs} commit -m addxyz xyz" \
+ "RCS file: ${TESTDIR}/cvsroot/my-dir/xyz,v
+ done
+ Checking in xyz;
+ ${TESTDIR}/cvsroot/my-dir/xyz,v  <--  xyz
+ initial revision: 1.1
+ done"
+         # status the file
+           # Running "cvs status" and matching output is too
+           # error-prone, too likely to falsely fail.  Instead, we'll
+           # just grep the Entries lines: (I found this out the hard way.)
+ 
+           dotest btrunktag6 "grep xyz ./CVS/Entries" \
+                  "/xyz/1.1/[A-Za-z0-9         :]*//T.trunk"
+ 
+         # edit the file and commit again
+         echo xyz >> xyz
+         dotest btrunktag7 "${testcvs} commit -m editxyz xyz" \
+ "Checking in xyz;
+ ${TESTDIR}/cvsroot/my-dir/xyz,v  <--  xyz
+ new revision: 1.2; previous revision: 1.1
+ done"
+ 
+         # create a branch, commit some changes to the branch,
+         # commit some more changes to the trunk, check out a
+           # specific revision that is neither the head of the branch
+           # nor the trunk, and do a cvs rdiff between the head of
+           # the branch and the head of the trunk.A
+           # (that is, test some unique functionality provided by ".trunk")
+         # (well, ok, -r1 would work in this case.)
+ 
+         dotest btrunktag8 "${testcvs} tag stickytag" \
+ "${PROG} [a-z]*: Tagging .
+ T xyz"
+         dotest btrunktag9 "${testcvs} tag -r stickytag -b mybranch" \
+ "${PROG} [a-z]*: Tagging .
+ T xyz"
+         dotest btrunktag9a "${testcvs} -q update -r mybranch" "" 
+         echo mybranch >> xyz
+         dotest btrunktag10 "${testcvs} commit -m branchedit" \
+ "${PROG} [a-z]*: Examining .
+ Checking in xyz;
+ ${TESTDIR}/cvsroot/my-dir/xyz,v  <--  xyz
+ new revision: 1.2.2.1; previous revision: 1.2
+ done"
+         dotest btrunktag11 "${testcvs} update -r .trunk" \
+ "${PROG} [a-z]*: Updating .
+ [UP] xyz"
+         echo trunkedit >> xyz
+         dotest btrunktag12 "${testcvs} commit -m trunkedit" \
+ "${PROG} [a-z]*: Examining .
+ Checking in xyz;
+ ${TESTDIR}/cvsroot/my-dir/xyz,v  <--  xyz
+ new revision: 1.3; previous revision: 1.2
+ done"
+         dotest btrunktag13 "${testcvs} update -r stickytag" \
+ "${PROG} [a-z]*: Updating .
+ [UP] xyz"
+         # try cvs rdiff
+ 
+         dotest btrunktag14a \
+               "${testcvs} rdiff -s -r mybranch -r .trunk my-dir"  \
+ "${PROG} [a-z]*: Diffing my-dir
+ File my-dir/xyz changed from revision 1\.2\.2\.1 to 1\.3"
+ 
+         # try cvs diff
+ 
+         dotest_fail btrunktag14b "${testcvs} diff -u -r mybranch -r .trunk" \
+ "${PROG} [a-z]*: Diffing .
+ Index: xyz
+ ===================================================================
+ RCS file: ${TESTDIR}/cvsroot/my-dir/xyz,v
+ retrieving revision 1\.2\.2\.1
+ retrieving revision 1\.3
+ diff -u -r1\.2\.2\.1 -r1\.3
+ --- xyz       [0-9/]* [0-9:]* 1\.2\.2\.1
+ ${PLUS}${PLUS}${PLUS} xyz     [0-9/]* [0-9:]* 1\.3
+ @@ -1,3 ${PLUS}1,3 @@
+  xyz
+  xyz
+ -mybranch
+ ${PLUS}trunkedit"
+ 
+         # make sure cvs diff works with just one -r 
+ 
+         dotest_fail btrunktag14a "${testcvs} diff -u -r .trunk" \
+ "${PROG} [a-z]*: Diffing \.
+ Index: xyz
+ ===================================================================
+ RCS file: ${TESTDIR}/cvsroot/my-dir/xyz,v
+ retrieving revision 1\.3
+ retrieving revision 1\.2
+ diff -u -r1\.3 -r1\.2
+ --- xyz       [0-9/]* [0-9:]* 1\.3
+ +++ xyz       [0-9/]* [0-9:]* 1\.2
+ @@ -1,3 ${PLUS}1,2 @@
+  xyz
+  xyz
+ -trunkedit"
+ 
+         # make sure cvs log works
+ 
+         dotest btrunktag15 "${testcvs} log -r.trunk" \
+ "${PROG} [a-z]*: Logging .
+ 
+ RCS file: ${TESTDIR}/cvsroot/my-dir/xyz,v
+ Working file: xyz
+ head: 1\.3
+ branch:
+ locks: strict
+ access list:
+ symbolic names:
+       mybranch: 1\.2\.0\.2
+       stickytag: 1\.2
+ keyword substitution: kv
+ total revisions: 4;   selected revisions: 3
+ description:
+ ----------------------------
+ revision 1\.3
+ date: [0-9/]* [0-9:]*;  author: ${username};  state: Exp;  lines: ${PLUS}1 -0
+ trunkedit
+ ----------------------------
+ revision 1\.2
+ date: [0-9/]* [0-9:]*;  author: ${username};  state: Exp;  lines: ${PLUS}1 -0
+ branches:  1\.2\.2;
+ editxyz
+ ----------------------------
+ revision 1\.1
+ date: [0-9/]* [0-9:]*;  author: ${username};  state: Exp;
+ addxyz
+ ============================================================================="
+ 
+       # try cvs update with -j options involving .trunk 
+ 
+       dotest btrunktag16 "${testcvs} update -j mybranch -j .trunk" \
+ "${PROG} [a-z]*: Updating \.
+ RCS file: ${TESTDIR}/cvsroot/my-dir/xyz,v
+ retrieving revision 1\.2\.2\.1
+ retrieving revision 1\.3
+ Merging differences between 1\.2\.2\.1 and 1\.3 into xyz
+ rcsmerge: warning: conflicts during merge"
+ 
+       # undo the conflicted merge,
+ 
+       rm xyz
+ 
+       # note, discrepancy here between client-server CVS 
+         # and local CVS, "xyz was lost" message printed only 
+         # by local-CVS but not by client-server CVS.  
+       # This is not a ".trunk" related problem though.
+         #
+ 
+       if [ "$remote" = "yes" ]
+       then
+               dotest btrunktag17 "${testcvs} -q update" \
+ "[UP] xyz"
+       else
+               dotest btrunktag17 "${testcvs} -q update" \
+ "${PROG} [a-z]*: warning: xyz was lost
+ [UP] xyz"
+       fi
+ 
+       # try cvs annotate
+       dotest btrunktag18 "${testcvs} annotate -r .trunk xyz" \
+ "Annotations for xyz
+ \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+ 1\.1          (${username} [0-9]*-[A-Za-z]*-[0-9]*): xyz
+ 1\.2          (${username} [0-9]*-[A-Za-z]*-[0-9]*): xyz
+ 1\.3          (${username} [0-9]*-[A-Za-z]*-[0-9]*): trunkedit"
+ 
+         # try cvs update -A
+ 
+       dotest btrunktag19 "${testcvs} update -A" \
+ "${PROG} [a-z]*: Updating \.
+ [UP] xyz"
+ 
+         # status the file  (just grep the Entries lines)
+ 
+           dotest btrunktag20 "grep xyz ./CVS/Entries" \
+ "/xyz/1\.3/[A-Za-z ]*[0-9]* [0-9:]* [0-9]*//"
+ 
+         # try switching working directory back: cvs update -r .trunk
+       dotest btrunktag21 "${testcvs} update -r .trunk" \
+ "${PROG} [a-z]*: Updating \."
+ 
+         # status the file  (just grep the Entries lines)
+ 
+           dotest btrunktag22 "grep xyz ./CVS/Entries" \
+ "/xyz/1\.3/[A-Za-z ]*[0-9]* [0-9:]* [0-9]*//T.trunk"
+ 
+         # try cvs remove
+         rm xyz
+           dotest btrunktag23 "${testcvs} remove xyz" \
+ "${PROG} [a-z]*: scheduling "\`"xyz"\'" for removal
+ ${PROG} [a-z]*: use "\'"cvs commit"\'" to remove this file permanently"
+ 
+         # commit the removal
+           dotest btrunktag24 "${testcvs} commit -m removexyz" \
+ "${PROG} [a-z]*: Examining \.
+ Removing xyz;
+ ${TESTDIR}/cvsroot/my-dir/xyz,v  <--  xyz
+ new revision: delete; previous revision: 1\.3
+ done" 
+ 
+         # update working directory to the branch
+           dotest btrunktag25 "${testcvs} update -r mybranch" \
+ "${PROG} [a-z]*: Updating \.
+ [UP] xyz"
+ 
+         # merge in the trunk just to see if the file disappears.
+ 
+           dotest btrunktag26 "${testcvs} update -j stickytag -j .trunk" \
+ "${PROG} [a-z]*: Updating \.
+ ${PROG} [a-z]*: scheduling xyz for removal"
+ 
+         # reverse the merge, file would come back
+         # except we just "cvs removed" it with the prior merge
+         # so that's a conflict, (is the file removed, or isn't it?)
+         # At least I guess that's the logic.  The file remains 
+         # in the removed state and a commit will remove it.
+         # this behavior is identical if two branches are used
+         # instead of one branch and ".trunk", therefore ".trunk" 
+         # is working perfectly.
+ 
+           dotest btrunktag27 "${testcvs} update -j .trunk -j stickytag" \
+ "${PROG} [a-z]*: Updating \.
+ R xyz
+ ${PROG} [a-z]*: file xyz exists, but has been added in revision stickytag"
+ 
+         # commit, just to see what happens
+ 
+         dotest btrunktag28 "${testcvs} commit -m removesticky" \
+ "${PROG} [a-z]*: Examining \.
+ Removing xyz;
+ ${TESTDIR}/cvsroot/my-dir/Attic/xyz,v  <--  xyz
+ new revision: delete; previous revision: 1\.2\.2\.1
+ done"
+ 
+         # try the reverse merge again, to see that the file comes back
+ 
+           dotest btrunktag29 "${testcvs} update -j .trunk -j stickytag" \
+ "${PROG} [a-z]*: Updating \.
+ [UP] xyz"
+ 
+         # try to commit it directly to the trunk instead of to branch
+         dotest btrunktag30 "${testcvs} commit -r .trunk -m totrunk xyz" \
+ "Checking in xyz;
+ ${TESTDIR}/cvsroot/my-dir/xyz,v  <--  xyz
+ new revision: 1\.5; previous revision: 1\.4
+ done"
+ 
+         # at this point, the file still has the sticky branch tag and
+           # it's status is "up-to-date..." not sure if that's right...
+           # It might be a bug.  My gut feeling is it should be 
+         # "newly added?"?  I strongly suspect exactly the same behavior
+           # would occur with two branches instead of ".trunk" and a 
+         # branch, but I haven't tried that case.
+ 
+           # let's see what happens with another commit.
+ 
+         dotest btrunktag31 "${testcvs} commit -m tobranch" \
+ "${PROG} [a-z]*: Examining ."
+ 
+         # Hmm, the file didn't get added... That doesn't seem 
+           # consistent.  I think that's a bug.  Had I done
+         # this commit before I'd done the "commit -r .trunk", 
+         # this file would have gone onto the branch.
+           # The "commit -r different-branch" probably should either leave
+           # the file's status alone, or else change the sticky tag to 
+           # the new branch, I think.
+         #
+ 
+         # try to remove the ".trunk" tag.  The message could be
+         # better, but it's not wrong in any way that's harmful.
+ 
+         dotest_fail btrunktag32 "${testcvs} tag -d .trunk xyz" \
+ "${PROG} .*: tag "\`"\.trunk"\'" must start with a letter"
+ 
+         # note, this, above, is *not* what happens if you try to remove 
+         # HEAD.  In that case, cvs actually tries to
+         # remove a tag called "HEAD", but can't find it, naturally.
+           # Perhaps that's a bug, that it doesn't catch that you're
+         # trying to remove the special HEAD tag.  BASE is almost
+           # certainly in the same boat.
+         #
+         # I'm going to go ahead and leave the following test in here
+           # to remind someone to look into this later, though
+         # it probably belongs someplace else.
+ 
+         dotest_fail btrunktag33 "${testcvs} tag -d HEAD xyz" \
+ "${PROG} [a-z]*: failed to remove tag HEAD from ${TESTDIR}/cvsroot/my-dir/xyz,v"
+ 
+         # test the case of ".trunk" with revision 
+         # numbers such as 2.1
+ 
+         # update to the trunk, odd behavior on the client/server front
+ 
+         if [ "$remote" != "yes" ]
+         then
+               dotest btrunktag34 "${testcvs} update -r .trunk" \
+ "${PROG} [a-z]*: Updating \.
+ [UP] xyz"
+         else
+               dotest btrunktag34 "${testcvs} update -r .trunk" \
+ "${PROG} [a-z]*: Updating \.
+ [UP] xyz
+ ${PROG} [a-z]*: invalid change text in \./xyz
+ ${PROG} [a-z]*: refetching unpatchable files
+ U xyz"
+               # Now, what the heck is *that* about?
+         fi
+ 
+         echo "revision 2.1" >> xyz
+         dotest btrunktag35 "${testcvs} commit -r2.1 -m twopointone" \
+ "${PROG} [a-z]*: Examining \.
+ Checking in xyz;
+ ${TESTDIR}/cvsroot/my-dir/xyz,v  <--  xyz
+ new revision: 2\.1; previous revision: 1\.5
+ done"
+ 
+         dotest btrunktag36 "${testcvs} rdiff -r stickytag \
+               -r .trunk my-dir" \
+ "${PROG} [a-z]*: Diffing my-dir
+ Index: my-dir/xyz
+ diff -c my-dir/xyz:1\.2 my-dir/xyz:2\.1
+ \*\*\* my-dir/xyz:1\.2        [A-Za-z ]*[0-9]* [0-9:]* [0-9]*
+ --- my-dir/xyz        [A-Za-z ]*[0-9]* [0-9:]* [0-9]*
+ \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+ \*\*\* 1,2 \*\*\*\*
+ --- 1,3 ----
+   xyz
+   xyz
+ ${PLUS} revision 2\.1"
+ 
+         # try a few things with "cvs admin" and ".trunk"
+ 
+         dotest_fail btrunktag40 "${testcvs} admin -o ::.trunk xyz" \
+ "RCS file: ${TESTDIR}/cvsroot/my-dir/xyz,v
+ deleting revision 1\.5
+ deleting revision 1\.4
+ deleting revision 1\.3
+ ${PROG} [a-z]*: ${TESTDIR}/cvsroot/my-dir/xyz,v: can't remove branch point 1\.2
+ ${PROG} [a-z]*: cannot modify RCS file for .xyz'"
+ 
+         dotest btrunktag41 "${testcvs} admin -o 1.2::.trunk xyz" \
+ "RCS file: /tmp/cvs-sanity/cvsroot/my-dir/xyz,v
+ deleting revision 1\.5
+ deleting revision 1\.4
+ deleting revision 1\.3
+ done"
+         dotest_fail btrunktag42 "${testcvs} admin -o 1.2:.trunk xyz" \
+ "RCS file: ${TESTDIR}/cvsroot/my-dir/xyz,v
+ deleting revision 2\.1
+ ${PROG} [a-z]*: ${TESTDIR}/cvsroot/my-dir/xyz,v: can't remove branch point 1\.2
+ ${PROG} [a-z]*: cannot modify RCS file for .xyz'"
+ 
+         dotest btrunktag43 "${testcvs} admin -sStab:2.1 xyz" \
+ "RCS file: ${TESTDIR}/cvsroot/my-dir/xyz,v
+ done"
+ 
+         dotest btrunktag44 "${testcvs} admin -m.trunk:this_is_a_test xyz" \
+ "RCS file: /tmp/cvs-sanity/cvsroot/my-dir/xyz,v
+ done"
+ 
+         # NOTE, "cvs log -r.trunk" differs from  
+         # "cvs log -b" in that ".trunk" will find all the 
+         # revisions on the trunk, not just those with the same 
+         # starting number as the final revision on the trunk.
+         # "cvs log -b" was made to be compatible with RCS, 
+         # I believe.
+         # 
+         # As far as I know, "cvs log" is the only command which
+         # takes a branch tag to mean "all the revisions on the branch."
+         # All the other commands take a branch tag to mean "the latest
+         # revision on the branch."
+         #
+         # also, "cvs log -rbranchtag:revision file" means all the
+         # revisions from the beginning of the branch to the specified
+         # revision inclusive, and "cvs log -rrevision:branchtag file" means
+         # all the revisions from the specified revision to the tip of
+         # the branch inclusive.  These too work with ".trunk"
+ 
+         dotest btrunktag45 "${testcvs} log -N -r.trunk xyz" \
+ "
+ RCS file: ${TESTDIR}/cvsroot/my-dir/xyz,v
+ Working file: xyz
+ head: 2\.1
+ branch:
+ locks: strict
+ access list:
+ keyword substitution: kv
+ total revisions: 5;   selected revisions: 3
+ description:
+ ----------------------------
+ revision 2\.1
+ date: [0-9/]* [0-9:]*;  author: ${username};  state: Stab;  lines: ${PLUS}1 -0
+ this_is_a_test
+ ----------------------------
+ revision 1\.2
+ date: [0-9/]* [0-9:]*;  author: ${username};  state: Exp;  lines: +1 -0
+ branches:  1\.2\.2;
+ editxyz
+ ----------------------------
+ revision 1\.1
+ date: [0-9/]* [0-9:]*;  author: ${username};  state: Exp;
+ addxyz
+ ============================================================================="
+ 
+         dotest btrunktag46 "${testcvs} admin -l.trunk xyz" \
+ "RCS file: ${TESTDIR}/cvsroot/my-dir/xyz,v
+ 2.1 locked
+ done"
+         dotest btrunktag46 "${testcvs} admin -u.trunk xyz" \
+ "RCS file: ${TESTDIR}/cvsroot/my-dir/xyz,v
+ 2.1 unlocked
+ done"
+ 
+       # let's try some really funky cases with "cvs log"
+ 
+       echo one > one
+       dotest btrunktag47 "${testcvs} -Q add one" \
+ "${PROG} [a-z]*: use .cvs commit. to add this file permanently"
+ 
+       dotest btrunktag48 "${testcvs} -Q commit -m one -r3.1 one" \
+ "RCS file: ${TESTDIR}/cvsroot/my-dir/one,v
+ done
+ Checking in one;
+ ${TESTDIR}/cvsroot/my-dir/one,v  <--  one
+ initial revision: 3\.1
+ done"
+       echo two >> two
+       dotest btrunktag49 "${testcvs} -Q commit -m two -r4.1 one" \
+ "Checking in one;
+ ${TESTDIR}/cvsroot/my-dir/one,v  <--  one
+ new revision: 4\.1; previous revision: 3\.1
+ done"
+       dotest btrunktag50 "${testcvs} -Q tag -b a_branch one" ""
+       dotest btrunktag50 "${testcvs} -Q update -r a_branch one" ""
+       echo branch >> one
+       dotest btrunktag51 "${testcvs} -Q commit -m branch one" \
+ "Checking in one;
+ ${TESTDIR}/cvsroot/my-dir/one,v  <--  one
+ new revision: 4\.1\.2\.1; previous revision: 4\.1
+ done"
+       dotest btrunktag52 "${testcvs} -Q update -r .trunk one" "" 
+       echo "more trunk" >> one
+       dotest btrunktag53 "${testcvs} -Q commit -m abc -r 5.1 one" \
+ "Checking in one;
+ ${TESTDIR}/cvsroot/my-dir/one,v  <--  one
+ new revision: 5\.1; previous revision: 4\.1
+ done"
+       dotest btrunktag54 "${testcvs} log -r.trunk one" \
+ "
+ RCS file: ${TESTDIR}/cvsroot/my-dir/one,v
+ Working file: one
+ head: 5\.1
+ branch:
+ locks: strict
+ access list:
+ symbolic names:
+       a_branch: 4\.1\.0\.2
+ keyword substitution: kv
+ total revisions: 4;   selected revisions: 3
+ description:
+ ----------------------------
+ revision 5\.1
+ date: [0-9/]* [0-9:]*;  author: ${username};  state: Exp;  lines: ${PLUS}1 -0
+ abc
+ ----------------------------
+ revision 4\.1
+ date: [0-9/]* [0-9:]*;  author: ${username};  state: Exp;  lines: ${PLUS}0 -0
+ branches:  4.1.2;
+ two
+ ----------------------------
+ revision 3\.1
+ date: [0-9/]* [0-9:]*;  author: ${username};  state: Exp;
+ one
+ ============================================================================="
+         
+       dotest btrunktag55 "${testcvs} log -r4.1:.trunk one" \
+ "
+ RCS file: ${TESTDIR}/cvsroot/my-dir/one,v
+ Working file: one
+ head: 5\.1
+ branch:
+ locks: strict
+ access list:
+ symbolic names:
+       a_branch: 4\.1\.0\.2
+ keyword substitution: kv
+ total revisions: 4;   selected revisions: 2
+ description:
+ ----------------------------
+ revision 5\.1
+ date: [0-9/]* [0-9:]*;  author: ${username};  state: Exp;  lines: ${PLUS}1 -0
+ abc
+ ----------------------------
+ revision 4\.1
+ date: [0-9/]* [0-9:]*;  author: ${username};  state: Exp;  lines: ${PLUS}0 -0
+ branches:  4\.1\.2;
+ two
+ ============================================================================="
+ 
+       dotest btrunktag56 "${testcvs} log -r.trunk:4.1 one" \
+ "
+ RCS file: ${TESTDIR}/cvsroot/my-dir/one,v
+ Working file: one
+ head: 5\.1
+ branch:
+ locks: strict
+ access list:
+ symbolic names:
+       a_branch: 4\.1\.0\.2
+ keyword substitution: kv
+ total revisions: 4;   selected revisions: 2
+ description:
+ ----------------------------
+ revision 4\.1
+ date: [0-9/]* [0-9:]*;  author: ${username};  state: Exp;  lines: ${PLUS}0 -0
+ branches:  4\.1\.2;
+ two
+ ----------------------------
+ revision 3\.1
+ date: [0-9/]* [0-9:]*;  author: ${username};  state: Exp;
+ one
+ ============================================================================="
          ;;
  
        *)
Index: src/status.c
===================================================================
RCS file: /home2/cvsroot/ccvs/src/status.c,v
retrieving revision 1.45
diff -c -r1.45 status.c
*** status.c    1999/06/01 21:36:33     1.45
--- status.c    2000/06/28 03:48:47
***************
*** 256,261 ****
--- 256,264 ----
                    if (RCS_nodeisbranch (finfo->rcs, edata->tag))
                        branch = RCS_whatbranch(finfo->rcs, edata->tag);
  
+                   if ( strcmp(edata->tag, TAG_TRUNK) == 0)
+                       branch = xstrdup(TAG_TRUNK);
+ 
                    cvs_output ("   Sticky Tag:\t\t", 0);
                    cvs_output (edata->tag, 0);
                    cvs_output (" (", 0);
Index: src/tag.c
===================================================================
RCS file: /home2/cvsroot/ccvs/src/tag.c,v
retrieving revision 1.86
diff -c -r1.86 tag.c
*** tag.c       2000/06/14 19:32:51     1.86
--- tag.c       2000/06/28 03:48:50
***************
*** 778,784 ****
  
      /* Special tags are always valid.  */
      if (strcmp (name, TAG_BASE) == 0
!       || strcmp (name, TAG_HEAD) == 0)
        return;
  
      /* FIXME: This routine doesn't seem to do any locking whatsoever
--- 778,785 ----
  
      /* Special tags are always valid.  */
      if (strcmp (name, TAG_BASE) == 0
!       || strcmp (name, TAG_HEAD) == 0
!       || strcmp (name, TAG_TRUNK) == 0)
        return;
  
      /* FIXME: This routine doesn't seem to do any locking whatsoever

Reply via email to