diff --git a/contrib/cvs/src/checkout.c b/contrib/cvs/src/checkout.c
index 86dc9510eb0b..a9afa494fe21 100644
--- a/contrib/cvs/src/checkout.c
+++ b/contrib/cvs/src/checkout.c
@@ -33,6 +33,10 @@
  * edited by the user, if necessary (when the repository is moved, e.g.)
  */
 
+/*
+ * $FreeBSD$
+ */
+
 #include <assert.h>
 #include "cvs.h"
 
@@ -50,6 +54,7 @@ static const char *const checkout_usage[] =
     "\t-N\tDon't shorten module paths if -d specified.\n",
     "\t-P\tPrune empty directories.\n",
     "\t-R\tProcess directories recursively.\n",
+    "\t-T\tCreate Template file from local repository for remote commit.\n",
     "\t-c\t\"cat\" the module database.\n",
     "\t-f\tForce a head revision match if tag/date not found.\n",
     "\t-l\tLocal directory only, not recursive\n",
@@ -92,6 +97,7 @@ static char *date = NULL;
 static char *join_rev1 = NULL;
 static char *join_rev2 = NULL;
 static int join_tags_validated = 0;
+static int pull_template = 0;
 static char *preload_update_dir = NULL;
 static char *history_name = NULL;
 static enum mtype m_type;
@@ -127,7 +133,7 @@ checkout (argc, argv)
     else
     {
         m_type = CHECKOUT;
-	valid_options = "+ANnk:d:flRpQqcsr:D:j:P";
+	valid_options = "+ANnk:d:flRpTQqcsr:D:j:P";
 	valid_usage = checkout_usage;
     }
 
@@ -156,6 +162,9 @@ checkout (argc, argv)
 	    case 'n':
 		run_module_prog = 0;
 		break;
+	    case 'T':
+		pull_template = 1;
+		break;
 	    case 'Q':
 	    case 'q':
 #ifdef SERVER_SUPPORT
@@ -1008,7 +1017,7 @@ internal error: %s doesn't start with %s in checkout_proc",
 			  force_tag_match, 0 /* !local */ ,
 			  1 /* update -d */ , aflag, checkout_prune_dirs,
 			  pipeout, which, join_rev1, join_rev2,
-			  preload_update_dir, m_type == CHECKOUT);
+			  preload_update_dir, pull_template);
 	goto out;
     }
 
@@ -1064,7 +1073,7 @@ internal error: %s doesn't start with %s in checkout_proc",
     err += do_update (argc - 1, argv + 1, options, tag, date,
 		      force_tag_match, local_specified, 1 /* update -d */,
 		      aflag, checkout_prune_dirs, pipeout, which, join_rev1,
-		      join_rev2, preload_update_dir, m_type == CHECKOUT);
+		      join_rev2, preload_update_dir, pull_template);
 out:
     free (preload_update_dir);
     preload_update_dir = oldupdate;
diff --git a/contrib/cvs/src/cvs.h b/contrib/cvs/src/cvs.h
index 8ce1cefe8ea2..d8b5c89bc85b 100644
--- a/contrib/cvs/src/cvs.h
+++ b/contrib/cvs/src/cvs.h
@@ -543,6 +543,7 @@ void Scratch_Entry PROTO((List * list, char *fname));
 void ParseTag PROTO((char **tagp, char **datep, int *nonbranchp));
 void WriteTag PROTO ((char *dir, char *tag, char *date, int nonbranch,
 		      char *update_dir, char *repository));
+void WriteTemplate PROTO ((char *dir, char *update_dir));
 void cat_module PROTO((int status));
 void check_entries PROTO((char *dir));
 void close_module PROTO((DBM * db));
diff --git a/contrib/cvs/src/entries.c b/contrib/cvs/src/entries.c
index 686244dbb332..d50683672be9 100644
--- a/contrib/cvs/src/entries.c
+++ b/contrib/cvs/src/entries.c
@@ -11,6 +11,9 @@
  * the Entries file.
  */
 
+/*
+ * $FreeBSD$
+ */
 #include "cvs.h"
 #include "getline.h"
 
@@ -633,6 +636,76 @@ AddEntryNode (list, entdata)
     return (p);
 }
 
+static char *root_template;
+
+static int
+get_root_template(char *repository, char *path)
+{
+    if (root_template) {
+	if (strcmp(path, root_template) == 0)
+	    return(0);
+	free(root_template);
+    }
+    if ((root_template = strdup(path)) == NULL)
+	return(-1);
+    return(0);
+}
+
+/*
+ * Write out/Clear the CVS/Template file.
+ */
+void
+WriteTemplate (dir, update_dir)
+    char *dir;
+    char *update_dir;
+{
+    char *tmp = NULL;
+    char *root = NULL;
+    struct stat st1;
+    struct stat st2;
+
+    if (Parse_Info(CVSROOTADM_RCSINFO, "cvs", get_root_template, 1) < 0)
+	return;
+
+    if ((root = Name_Root(dir, update_dir)) == NULL)
+	error (1, errno, "unable to locate cvs root");
+    if (asprintf(&tmp, "%s/%s", dir, CVSADM_TEMPLATE) < 0)
+	error (1, errno, "out of memory");
+
+    if (stat(root_template, &st1) == 0) {
+	if (stat(tmp, &st2) < 0 || st1.st_mtime != st2.st_mtime) {
+	    FILE *fi;
+	    FILE *fo;
+
+	    if ((fi = open_file(root_template, "r")) != NULL) {
+		if ((fo = open_file(tmp, "w")) != NULL) {
+		    int n;
+		    char buf[256];
+
+		    while ((n = fread(buf, 1, sizeof(buf), fi)) > 0)
+			fwrite(buf, 1, n, fo);
+		    fflush(fo);
+		    if (ferror(fi) || ferror(fo)) {
+			fclose(fo);
+			remove(tmp);
+			error (1, errno, "error copying Template");
+		    } else {
+			struct timeval times[2];
+			fclose(fo);
+			times[0].tv_sec = st1.st_mtime;
+			times[0].tv_usec = 0;
+			times[1] = times[0];
+			utimes(tmp, times);
+		    }
+		} 
+		fclose(fi);
+	    }
+	}
+    }
+    free(tmp);
+    free(root);
+}
+
 /*
  * Write out/Clear the CVS/Tag file.
  */
diff --git a/contrib/cvs/src/update.c b/contrib/cvs/src/update.c
index c92dc4184548..fa75977b4a98 100644
--- a/contrib/cvs/src/update.c
+++ b/contrib/cvs/src/update.c
@@ -98,10 +98,10 @@ static char *join_rev2, *date_rev2;
 static int aflag = 0;
 static int toss_local_changes = 0;
 static int force_tag_match = 1;
+static int pull_template = 0;
 static int update_build_dirs = 0;
 static int update_prune_dirs = 0;
 static int pipeout = 0;
-static int dotemplate = 0;
 #ifdef SERVER_SUPPORT
 static int patches = 0;
 static int rcs_diff_patches = 0;
@@ -126,6 +126,7 @@ static const char *const update_usage[] =
     "\t-j rev\tMerge in changes made between current revision and rev.\n",
     "\t-I ign\tMore files to ignore (! to reset).\n",
     "\t-W spec\tWrappers specification line.\n",
+    "\t-T\tCreate CVS/Template.\n",
     "(Specify the --help global option for a list of other help options)\n",
     NULL
 };
@@ -141,6 +142,7 @@ update (argc, argv)
     int c, err;
     int local = 0;			/* recursive by default */
     int which;				/* where to look for files and dirs */
+    int xpull_template = 0;
 
     if (argc == -1)
 	usage (update_usage);
@@ -150,7 +152,7 @@ update (argc, argv)
 
     /* parse the args */
     optind = 0;
-    while ((c = getopt (argc, argv, "+ApCPflRQqduk:r:D:j:I:W:")) != -1)
+    while ((c = getopt (argc, argv, "+ApCPflRQTqduk:r:D:j:I:W:")) != -1)
     {
 	switch (c)
 	{
@@ -188,6 +190,9 @@ update (argc, argv)
 			   "-q or -Q must be specified before \"%s\"",
 			   command_name);
 		break;
+	    case 'T':
+		xpull_template = 1;
+		break;
 	    case 'd':
 		update_build_dirs = 1;
 		break;
@@ -412,7 +417,8 @@ update (argc, argv)
     /* call the command line interface */
     err = do_update (argc, argv, options, tag, date, force_tag_match,
 		     local, update_build_dirs, aflag, update_prune_dirs,
-		     pipeout, which, join_rev1, join_rev2, (char *) NULL, 1);
+		     pipeout, which, join_rev1, join_rev2, (char *) NULL,
+		     xpull_template);
 
     /* free the space Make_Date allocated if necessary */
     if (date != NULL)
@@ -427,7 +433,7 @@ update (argc, argv)
 int
 do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
 	   xprune, xpipeout, which, xjoin_rev1, xjoin_rev2, preload_update_dir,
-	   xdotemplate)
+	   xpull_template)
     int argc;
     char **argv;
     char *xoptions;
@@ -443,7 +449,7 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
     char *xjoin_rev1;
     char *xjoin_rev2;
     char *preload_update_dir;
-    int xdotemplate;
+    int xpull_template;
 {
     int err = 0;
     char *cp;
@@ -457,7 +463,7 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
     aflag = xaflag;
     update_prune_dirs = xprune;
     pipeout = xpipeout;
-    dotemplate = xdotemplate;
+    pull_template = xpull_template;
 
     /* setup the join support */
     join_rev1 = xjoin_rev1;
@@ -968,7 +974,7 @@ update_dirent_proc (callerdat, dir, repository, update_dir, entries)
 			     via WriteTag.  */
 			  0,
 			  0,
-			  dotemplate);
+			  pull_template);
 	    rewrite_tag = 1;
 	    nonbranch = 0;
 	    Subdir_Register (entries, (char *) NULL, dir);
@@ -1027,6 +1033,12 @@ update_dirent_proc (callerdat, dir, repository, update_dir, entries)
 	    nonbranch = 0;
 	}
 
+	/* keep the CVS/Template file current */
+	if (pull_template) 
+	{
+	    WriteTemplate (dir, update_dir);
+	}
+
 	/* initialize the ignore list for this directory */
 	ignlist = getlist ();
     }
diff --git a/contrib/cvs/src/update.h b/contrib/cvs/src/update.h
index 9a1fc003db91..1c3ea6644ad0 100644
--- a/contrib/cvs/src/update.h
+++ b/contrib/cvs/src/update.h
@@ -10,10 +10,14 @@
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.  */
 
+/*
+ * $FreeBSD$
+ */
+
 int do_update PROTO((int argc, char *argv[], char *xoptions, char *xtag,
 	       char *xdate, int xforce, int local, int xbuild,
 	       int xaflag, int xprune, int xpipeout, int which,
 	       char *xjoin_rev1, char *xjoin_rev2, char *preload_update_dir,
-	       int xdotemplate));
+	       int xpull_template));
 int joining PROTO((void));
 extern int isemptydir PROTO ((char *dir, int might_not_exist));