Ok, here's a refinement of my ".trunk' patch that gives
the trunk a branch-tag name, just like other branches
(from the user's perspective, the implementation is rather
different.)

You can also find this here:
http://www.geocities.com/dotslashstar/branch_patch.html

>From HACKING:

        * Writing patches (strategy)

        [...] For features, the desirable attributes are that
        the need is clear and that they fit nicely into the architecture of
        CVS.  Is it worth the cost (in terms of complexity or any other
        tradeoffs involved)?  Are there better solutions?

I'm not sure I know the answers to the above..., but you can have a
look at my code and ponder it.

        If the design is not yet clear (which is true of most features), then
        the design is likely to benefit from more work and community input.

Yes please, input could be nice.

        Make a list of issues, or write documentation including rationales for
        how one would use the feature.



        Discuss it with coworkers, a
        newsgroup, or a mailing list, and see what other people think.

This has been discussed several times in the past...with no real outcome. 

        Distribute some experimental patches and see what people think.  The
        intention is arrive at some kind of rough community consensus before
        changing the "official" CVS.  Features like zlib, encryption, and
        the RCS library have benefitted from this process in the past.

So far: ...silence... (the sound of crickets chirping maybe)

        If longstanding CVS behavior, that people may be relying on, is
        clearly deficient, it can be changed, but only slowly and carefully.
        For example, the global -q option was introduced in CVS 1.3 but the
        command -q options, which the global -q replaced, were not removed
        until CVS 1.6.

I have carefully refrained from disturbing the longstanding (but
        disturbing) behavior of the "HEAD" pseudo tag.

        * Writing patches (tactics)

        When you first distribute a patch it may be suitable to just put forth
        a rough patch, or even just an idea.  But before the end of the
        process the following should exist:

Check!

          - ChangeLog entry (see the GNU coding standards for details).

Check!

          - Changes to the NEWS file and cvs.texinfo, if the change is a
            user-visible change worth mentioning.

Check!
          - Somewhere, a description of what the patch fixes (often in
            comments in the code, or maybe the ChangeLog or documentation).

Check!
          - Most of the time, a test case (see TESTS).  It can be quite
            frustrating to fix a bug only to see it reappear later, and adding
            the case to the testsuite, where feasible, solves this and other
            problems.
Check!

        Include words like "I grant permission to distribute this patch under
        the terms of the GNU Public License" with your patch.  By sending a
        patch to [EMAIL PROTECTED], you implicitly grant this permission.

Check!

"I hereby grant permission to distribute this patch under
the terms of the GNU Public License"  -- Steve Cameron

So, of course my expectations are not that this will be checked
in, but maybe someone will point me to what I need to fix to move
things in that direction, or tell me not to bother.


Thanks,

-- steve

The patch is attached. Or you can get it here too:
http://www.geocities.com/dotslashstar/branch_patch.html




__________________________________________________
Do You Yahoo!?
Send instant messages with Yahoo! Messenger.
http://im.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/18 04:19:30
***************
*** 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/18 04:19:47
***************
*** 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/18 04:20:32
***************
*** 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
--- 3313,3333 ----
  @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
--- 3632,3639 ----
  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
--- 3695,3705 ----
  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 ****
--- 8080,8086 ----
  @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 ****
--- 8110,8120 ----
  @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 ****
--- 8221,8229 ----
  @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
  
--- 8835,8854 ----
  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 ****
--- 9039,9063 ----
  
  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
+ the particular file being diffed is not present on the
+ branch, in which case the head revision of the trunk is
+ taken.  It is evident that there are at least some cases
+ for which this definition fails, that is, the wrong 
+ revision may be found by `cvs diff' when used in combination
+ with `-r HEAD'.  You may wish to use `.trunk' 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.1916
diff -c -r1.1916 ChangeLog
*** ChangeLog   2000/06/16 20:35:23     1.1916
--- ChangeLog   2000/06/18 04:20:48
***************
*** 1,3 ****
--- 1,24 ----
+ 2000-06-18  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
+ 
  2000-06-16  Larry Jones  <[EMAIL PROTECTED]>
  
        * fileattr.c (fileattr_read): Plug memory leak.
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/18 04:20:53
***************
*** 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.161
diff -c -r1.161 commit.c
*** commit.c    2000/06/12 21:47:32     1.161
--- commit.c    2000/06/18 04:20:59
***************
*** 687,696 ****
      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);
--- 687,697 ----
      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);
***************
*** 746,751 ****
--- 747,753 ----
      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;
***************
*** 819,828 ****
             * 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
--- 821,831 ----
             * 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
***************
*** 839,844 ****
--- 842,848 ----
                    return (1);
                }
                if (status == T_MODIFIED && vers->tag &&
+                   strcmp(vers->tag, TAG_TRUNK)!=0 &&
                    !RCS_isbranch (finfo->rcs, vers->tag))
                {
                    error (0, 0,
***************
*** 917,923 ****
            }
            if (status == T_ADDED)
            {
!               if (vers->tag == NULL)
                {
                    char *rcs;
  
--- 921,927 ----
            }
            if (status == T_ADDED)
            {
!               if (vers->tag == NULL || strcmp(vers->tag, TAG_TRUNK) == 0)
                {
                    char *rcs;
  
***************
*** 988,994 ****
            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;
--- 992,1003 ----
            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;
***************
*** 1000,1013 ****
            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);
--- 1009,1028 ----
            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);
***************
*** 1639,1645 ****
        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)
--- 1654,1661 ----
        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/18 04:21:03
***************
*** 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/18 04:21:05
***************
*** 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/18 04:21:07
***************
*** 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) /* this is probably kind of evil...  */
+               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.61
diff -c -r1.61 log.c
*** log.c       2000/06/13 21:30:44     1.61
--- log.c       2000/06/18 04:21:10
***************
*** 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':
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/18 04:21:31
***************
*** 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;
***************
*** 2793,2798 ****
--- 2801,2822 ----
  }
  
  /*
+  * 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.
***************
*** 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
--- 5585,5593 ----
  
      /* 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/18 04:21:32
***************
*** 202,207 ****
--- 202,208 ----
  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));
  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/18 04:22:15
***************
*** 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,20849 ----
            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 brahcn, 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")
+         #
+ 
+         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 should come back
+         # Note, I think ".trunk" is working correctly here, but I'm not
+         # sure that "cvs update" is doing the right thing.  The 
+         # file was just "cvs removed", but not committed, doing this
+         # reverse merge, it seems to me, should bring the file back,
+           # but it doesn't... Hmmm.  Need to look into that more.
+         #
+ 
+           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.
+ 
+         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, see if 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.  maybe it should be "newly added?"
+ 
+           # 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 the
+         # 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 leave
+           # the file's status alone. 
+           #
+ 
+         # 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"
+          
          ;;
  
        *)
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/18 04:22:16
***************
*** 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);

Reply via email to