]> code.delx.au - gnu-emacs/blobdiff - lisp/vc-cvs.el
* progmodes/grep.el (grep-compute-defaults): Simplify how settings
[gnu-emacs] / lisp / vc-cvs.el
index 1e9788487bc88e2741bd538febf01bd3955e435b..50a4e281d81227d59a1ffe3c5f30a6908733eb9b 100644 (file)
@@ -1,13 +1,11 @@
 ;;; vc-cvs.el --- non-resident support for CVS version-control
 
-;; Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003,
-;;   2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+;;   2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
 ;; Author:      FSF (see vc.el for full credits)
 ;; Maintainer:  Andre Spiegel <spiegel@gnu.org>
 
-;; $Id$
-
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software: you can redistribute it and/or modify
@@ -62,7 +60,7 @@
 ;;;
 
 (defcustom vc-cvs-global-switches nil
-  "*Global switches to pass to any CVS command."
+  "Global switches to pass to any CVS command."
   :type '(choice (const :tag "None" nil)
                 (string :tag "Argument String")
                 (repeat :tag "Argument List"
   :group 'vc)
 
 (defcustom vc-cvs-register-switches nil
-  "*Extra switches for registering a file into CVS.
+  "Switches for registering a file into CVS.
 A string or list of strings passed to the checkin program by
-\\[vc-register]."
-  :type '(choice (const :tag "None" nil)
+\\[vc-register].  If nil, use the value of `vc-register-switches'.
+If t, use no switches."
+  :type '(choice (const :tag "Unspecified" nil)
+                (const :tag "None" t)
                 (string :tag "Argument String")
-                (repeat :tag "Argument List"
-                        :value ("")
-                        string))
+                (repeat :tag "Argument List" :value ("") string))
   :version "21.1"
   :group 'vc)
 
 (defcustom vc-cvs-diff-switches nil
-  "*A string or list of strings specifying extra switches for cvs diff under VC."
-    :type '(choice (const :tag "None" nil)
-                (string :tag "Argument String")
-                (repeat :tag "Argument List"
-                        :value ("")
-                        string))
+  "String or list of strings specifying switches for CVS diff under VC.
+If nil, use the value of `vc-diff-switches'.  If t, use no switches."
+  :type '(choice (const :tag "Unspecified" nil)
+                 (const :tag "None" t)
+                 (string :tag "Argument String")
+                 (repeat :tag "Argument List" :value ("") string))
   :version "21.1"
   :group 'vc)
 
 (defcustom vc-cvs-header (or (cdr (assoc 'CVS vc-header-alist)) '("\$Id\$"))
-  "*Header keywords to be inserted by `vc-insert-headers'."
+  "Header keywords to be inserted by `vc-insert-headers'."
   :version "21.1"
   :type '(repeat string)
   :group 'vc)
 
 (defcustom vc-cvs-use-edit t
-  "*Non-nil means to use `cvs edit' to \"check out\" a file.
+  "Non-nil means to use `cvs edit' to \"check out\" a file.
 This is only meaningful if you don't use the implicit checkout model
 \(i.e. if you have $CVSREAD set)."
   :type 'boolean
   :version "21.1"
   :group 'vc)
 
-(defcustom vc-cvs-stay-local t
-  "*Non-nil means use local operations when possible for remote repositories.
+(defcustom vc-cvs-stay-local 'only-file
+  "Non-nil means use local operations when possible for remote repositories.
 This avoids slow queries over the network and instead uses heuristics
 and past information to determine the current status of a file.
 
+If value is the symbol `only-file' `vc-dir' will connect to the
+server, but heuristics will be used to determine the status for
+all other VC operations.
+
 The value can also be a regular expression or list of regular
 expressions to match against the host name of a repository; then VC
 only stays local for hosts that match it.  Alternatively, the value
@@ -119,16 +121,20 @@ can be a list of regular expressions where the first element is the
 symbol `except'; then VC always stays local except for hosts matched
 by these regular expressions."
   :type '(choice (const :tag "Always stay local" t)
-                (const :tag "Don't stay local" nil)
-                 (list :format "\nExamine hostname and %v" :tag "Examine hostname ..."
-                       (set :format "%v" :inline t (const :format "%t" :tag "don't" except))
-                       (regexp :format " stay local,\n%t: %v" :tag "if it matches")
+                (const :tag "Only for file operations" only-file)
+                (const :tag "Don't stay local" nil)
+                 (list :format "\nExamine hostname and %v"
+                       :tag "Examine hostname ..."
+                       (set :format "%v" :inline t
+                            (const :format "%t" :tag "don't" except))
+                       (regexp :format " stay local,\n%t: %v"
+                               :tag "if it matches")
                        (repeat :format "%v%i\n" :inline t (regexp :tag "or"))))
-  :version "21.1"
+  :version "23.1"
   :group 'vc)
 
 (defcustom vc-cvs-sticky-date-format-string "%c"
-  "*Format string for mode-line display of sticky date.
+  "Format string for mode-line display of sticky date.
 Format is according to `format-time-string'.  Only used if
 `vc-cvs-sticky-tag-display' is t."
   :type '(string)
@@ -136,7 +142,7 @@ Format is according to `format-time-string'.  Only used if
   :group 'vc)
 
 (defcustom vc-cvs-sticky-tag-display t
-  "*Specify the mode-line display of sticky tags.
+  "Specify the mode-line display of sticky tags.
 Value t means default display, nil means no display at all.  If the
 value is a function or macro, it is called with the sticky tag and
 its' type as parameters, in that order.  TYPE can have three different
@@ -196,16 +202,16 @@ See also variable `vc-cvs-sticky-date-format-string'."
         ;; make sure that the file name is searched case-sensitively
         (case-fold-search nil))
     (if (file-readable-p (expand-file-name "CVS/Entries" dirname))
-       (with-temp-buffer
-          (vc-cvs-get-entries dirname)
-          (goto-char (point-min))
-         (cond
-          ((re-search-forward
-            (concat "^/" (regexp-quote basename) "/[^/]") nil t)
-           (beginning-of-line)
-           (vc-cvs-parse-entry file)
-           t)
-          (t nil)))
+        (or (string= basename "")
+            (with-temp-buffer
+              (vc-cvs-get-entries dirname)
+              (goto-char (point-min))
+              (cond ((re-search-forward
+                      (concat "^/" (regexp-quote basename) "/[^/]") nil t)
+                     (beginning-of-line)
+                     (vc-cvs-parse-entry file)
+                     t)
+                    (t nil))))
       nil)))
 
 (defun vc-cvs-state (file)
@@ -231,6 +237,7 @@ See also variable `vc-cvs-sticky-date-format-string'."
     (cond
      ((equal checkout-time lastmod) 'up-to-date)
      ((string= (vc-working-revision file) "0") 'added)
+     ((null checkout-time) 'unregistered)
      (t 'edited))))
 
 (defun vc-cvs-working-revision (file)
@@ -250,13 +257,13 @@ committed and support display of sticky tags."
         help-echo
         (string
           (let ((def-ml (vc-default-mode-line-string 'CVS file)))
-            (setq help-echo 
+            (setq help-echo
                   (get-text-property 0 'help-echo def-ml))
             def-ml)))
-    (propertize 
+    (propertize
      (if (zerop (length sticky-tag))
         string
-       (setq help-echo (format "%s on the '%s' branch" 
+       (setq help-echo (format "%s on the '%s' branch"
                               help-echo sticky-tag))
        (concat string "[" sticky-tag "]"))
      'help-echo help-echo)))
@@ -269,9 +276,8 @@ committed and support display of sticky tags."
 (defun vc-cvs-register (files &optional rev comment)
   "Register FILES into the CVS version-control system.
 COMMENT can be used to provide an initial description of FILES.
-
-`vc-register-switches' and `vc-cvs-register-switches' are passed to
-the CVS command (in that order)."
+Passes either `vc-cvs-register-switches' or `vc-register-switches'
+to the CVS command."
   ;; Register the directories if needed.
   (let (dirs)
     (dolist (file files)
@@ -300,9 +306,10 @@ its parents."
     (while (and (stringp dir)
                 (not (equal dir (setq dir (file-name-directory dir))))
                 dir)
-      (setq dir (if (file-directory-p
+      (setq dir (if (file-exists-p
                      (expand-file-name "CVS/Entries" dir))
-                    t (directory-file-name dir))))
+                    t
+                  (directory-file-name dir))))
     (eq dir t)))
 
 (defun vc-cvs-checkin (files rev comment)
@@ -421,7 +428,7 @@ The changes are between FIRST-REVISION and SECOND-REVISION."
   (with-current-buffer (get-buffer "*vc*")
     (goto-char (point-min))
     (if (re-search-forward "conflicts during merge" nil t)
-       (progn 
+       (progn
          (vc-file-setprop file 'vc-state 'conflict)
          ;; signal error
          1)
@@ -476,7 +483,7 @@ The changes are between FIRST-REVISION and SECOND-REVISION."
       (message "Merging changes into %s...done" file))))
 
 (defun vc-cvs-modify-change-comment (files rev comment)
-  "Modify the change comments for FILES on a specified REV. 
+  "Modify the change comments for FILES on a specified REV.
 Will fail unless you have administrative privileges on the repo."
   (vc-cvs-command nil 0 files "admin" (concat "-m" rev ":" comment)))
 
@@ -518,13 +525,12 @@ Will fail unless you have administrative privileges on the repo."
              (coding-system-for-read (vc-coding-system-for-diff file)))
          (if (and file-oldvers file-newvers)
              (progn
+               ;; This used to append diff-switches and vc-diff-switches,
+               ;; which was consistent with the vc-diff-switches doc at that
+               ;; time, but not with the actual behavior of any other VC diff.
                (apply 'vc-do-command (or buffer "*vc-diff*") 1 "diff" nil
-                      (append (if (listp diff-switches)
-                                  diff-switches
-                                (list diff-switches))
-                              (if (listp vc-diff-switches)
-                                  vc-diff-switches
-                                (list vc-diff-switches))
+                      ;; Not a CVS diff, does not use vc-cvs-diff-switches.
+                      (append (vc-switches nil 'diff)
                               (list (file-relative-name file-oldvers)
                                     (file-relative-name file-newvers))))
                (setq status 0))
@@ -569,6 +575,8 @@ Optional arg REVISION is a revision to annotate from."
         (re-search-forward vc-cvs-annotate-first-line-re)
         (delete-region (point-min) (1- (point)))))))
 
+(declare-function vc-annotate-convert-time "vc-annotate" (time))
+
 (defun vc-cvs-annotate-current-time ()
   "Return the current time, based at midnight of the current day, and
 encoded as fractional days."
@@ -688,9 +696,6 @@ If UPDATE is non-nil, then update (resynch) any affected buffers."
 ;;; Internal functions
 ;;;
 
-(defun vc-cvs-root (dir)
-  (vc-find-root dir "CVS" t))
-
 (defun vc-cvs-command (buffer okstatus files &rest flags)
   "A wrapper around `vc-do-command' for use in vc-cvs.el.
 The difference to vc-do-command is that this function always invokes `cvs',
@@ -717,10 +722,16 @@ and that it passes `vc-cvs-global-switches' to it before FLAGS."
                (buffer-substring (point)
                                  (line-end-position))))))))
 
+(defun vc-cvs-parse-uhp (path)
+  "parse user@host/path into (user@host /path)"
+  (if (string-match "\\([^/]+\\)\\(/.*\\)" path)
+      (list (match-string 1 path) (match-string 2 path))
+      (list nil path)))
+
 (defun vc-cvs-parse-root (root)
   "Split CVS ROOT specification string into a list of fields.
 A CVS root specification of the form
-  [:METHOD:][[USER@]HOSTNAME:]/path/to/repository
+  [:METHOD:][[USER@]HOSTNAME]:?/path/to/repository
 is converted to a normalized record with the following structure:
   \(METHOD USER HOSTNAME CVS-ROOT).
 The default METHOD for a CVS root of the form
@@ -742,17 +753,16 @@ For an empty string, nil is returned (invalid CVS root)."
             ;; Invalid CVS root
             nil)
            ((= len 1)
-            ;; Simple PATH => method `local'
-            (cons "local"
-                  (cons nil root-list)))
+            (let ((uhp (vc-cvs-parse-uhp (car root-list))))
+              (cons (if (car uhp) "ext" "local") uhp)))
            ((= len 2)
             ;; [USER@]HOST:PATH => method `ext'
             (and (not (equal (car root-list) ""))
                  (cons "ext" root-list)))
            ((= len 3)
-            ;; :METHOD:PATH
+            ;; :METHOD:PATH or :METHOD:USER@HOSTNAME/PATH
             (cons (cadr root-list)
-                  (cons nil (cddr root-list))))
+                  (vc-cvs-parse-uhp (caddr root-list))))
            (t
             ;; :METHOD:[USER@]HOST:PATH
             (cdr root-list)))))
@@ -799,10 +809,8 @@ state."
       (cond
        ((re-search-forward "\\=\\([^ \t]+\\)" nil t)
        (setq file (expand-file-name (match-string 1)))
-       (vc-file-setprop file 'vc-backend 'CVS)
-       (if (not (re-search-forward "\\=[ \t]+Status: \\(.*\\)" nil t))
-           (setq status "Unknown")
-         (setq status (match-string 1)))
+       (setq status(if (re-search-forward "\\=[ \t]+Status: \\(.*\\)" nil t)
+                        (match-string 1) "Unknown"))
        (when (and full
                   (re-search-forward
                    "\\(RCS Version\\|RCS Revision\\|Repository revision\\):\
@@ -823,6 +831,7 @@ state."
          ((string-match "Locally Added" status)                'added)
          ((string-match "Locally Removed" status)              'removed)
          ((string-match "File had conflicts " status)          'conflict)
+          ((string-match "Unknown" status)                     'unregistered)
          (t 'edited))))))))
 
 (defun vc-cvs-after-dir-status (update-function)
@@ -833,15 +842,16 @@ state."
        (file nil)
        (result nil)
        (missing nil)
+       (ignore-next nil)
        (subdir default-directory))
     (goto-char (point-min))
     (while
        ;; Look for either a file entry, an unregistered file, or a
        ;; directory change.
        (re-search-forward
-        "\\(^=+\n\\([^=c?\n].*\n\\|\n\\)+\\)\\|\\(\\(^?? .*\n\\)+\\)\\|\\(^cvs status: Examining .*\n\\)"
+        "\\(^=+\n\\([^=c?\n].*\n\\|\n\\)+\\)\\|\\(\\(^?? .*\n\\)+\\)\\|\\(^cvs status: \\(Examining\\|nothing\\) .*\n\\)"
         nil t)
-      ;; XXX: get rid of narrowing here.
+      ;; FIXME: get rid of narrowing here.
       (narrow-to-region (match-beginning 0) (match-end 0))
       (goto-char (point-min))
       ;; The subdir
@@ -849,37 +859,50 @@ state."
        (setq subdir (expand-file-name (match-string 1))))
       ;; Unregistered files
       (while (looking-at "? \\(.*\\)")
-       (setq file (file-relative-name 
+       (setq file (file-relative-name
                    (expand-file-name (match-string 1) subdir)))
        (push (list file 'unregistered) result)
        (forward-line 1))
+      (when (looking-at "cvs status: nothing known about")
+       ;; We asked about a non existent file.  The output looks like this:
+
+       ;; cvs status: nothing known about `lisp/v.diff'
+       ;; ===================================================================
+       ;; File: no file v.diff            Status: Unknown
+       ;;
+       ;;    Working revision:    No entry for v.diff
+       ;;    Repository revision: No revision control file
+       ;;
+
+       ;; Due to narrowing in this iteration we only see the "cvs
+       ;; status:" line, so just set a flag so that we can ignore the
+       ;; file in the next iteration.
+       (setq ignore-next t))
       ;; A file entry.
-      (when (re-search-forward "^File: " nil t)
-       (when (setq missing (looking-at "no file "))
-         (goto-char (match-end 0)))
-       (cond
-        ((re-search-forward "\\=\\([^ \t]+\\)" nil t)
-         (setq file (file-relative-name 
-                     (expand-file-name (match-string 1) subdir)))
-         (if (not (re-search-forward "\\=[ \t]+Status: \\(.*\\)" nil t))
-             (push (list file 'unregistered) result)
-           (setq status-str (match-string 1))
-           (setq status
-                 (cond
-                  ((string-match "Up-to-date" status-str) 'up-to-date)
-                  ((string-match "Locally Modified" status-str) 'edited)
-                  ((string-match "Needs Merge" status-str) 'needs-merge)
-                  ((string-match "Needs \\(Checkout\\|Patch\\)" status-str)
-                   (if missing 'missing 'needs-update))
-                  ((string-match "Locally Added" status-str) 'added)
-                  ((string-match "Locally Removed" status-str) 'removed)
-                  ((string-match "File had conflicts " status-str) 'conflict)
-                  (t 'edited)))
-           (unless (eq status 'up-to-date)
-             (push (list file status) result))))))
+      (when (re-search-forward "^File: \\(no file \\)?\\(.*[^ \t]\\)[ \t]+Status: \\(.*\\)" nil t)
+       (setq missing (match-string 1))
+       (setq file (file-relative-name
+                   (expand-file-name (match-string 2) subdir)))
+       (setq status-str (match-string 3))
+       (setq status
+             (cond
+              ((string-match "Up-to-date" status-str) 'up-to-date)
+              ((string-match "Locally Modified" status-str) 'edited)
+              ((string-match "Needs Merge" status-str) 'needs-merge)
+              ((string-match "Needs \\(Checkout\\|Patch\\)" status-str)
+               (if missing 'missing 'needs-update))
+              ((string-match "Locally Added" status-str) 'added)
+              ((string-match "Locally Removed" status-str) 'removed)
+              ((string-match "File had conflicts " status-str) 'conflict)
+              ((string-match "Unknown" status-str) 'unregistered)
+              (t 'edited)))
+       (if ignore-next
+           (setq ignore-next nil)
+         (unless (eq status 'up-to-date)
+           (push (list file status) result))))
       (goto-char (point-max))
       (widen))
-      (funcall update-function result))
+    (funcall update-function result))
   ;; Alternative implementation: use the "update" command instead of
   ;; the "status" command.
   ;; (let ((result nil)
@@ -893,8 +916,8 @@ state."
   ;;   (goto-char (point-min))
   ;;   (while (not (eobp))
   ;;     (if (looking-at "^[ACMPRU?] \\(.*\\)$")
-  ;;     (push (list (match-string 1) 
-  ;;                 (cdr (assoc (char-after) translation))) 
+  ;;     (push (list (match-string 1)
+  ;;                 (cdr (assoc (char-after) translation)))
   ;;           result)
   ;;   (cond
   ;;    ((looking-at "cvs update: warning: \\(.*\\) was lost")
@@ -910,38 +933,111 @@ state."
   ;;   (funcall update-function result)))
   )
 
+;; Based on vc-cvs-dir-state-heuristic from Emacs 22.
+(defun vc-cvs-dir-status-heuristic (dir update-function &optional basedir)
+  "Find the CVS state of all files in DIR, using only local information."
+  (let (file basename status result dirlist)
+    (with-temp-buffer
+      (vc-cvs-get-entries dir)
+      (goto-char (point-min))
+      (while (not (eobp))
+        (if (looking-at "D/\\([^/]*\\)////")
+            (push (expand-file-name (match-string 1) dir) dirlist)
+          ;; CVS-removed files are not taken under VC control.
+          (when (looking-at "/\\([^/]*\\)/[^/-]")
+            (setq basename (match-string 1)
+                  file (expand-file-name basename dir)
+                  status (or (vc-file-getprop file 'vc-state)
+                             (vc-cvs-parse-entry file t)))
+            (unless (eq status 'up-to-date)
+              (push (list (if basedir
+                              (file-relative-name file basedir)
+                            basename)
+                          status) result))))
+        (forward-line 1)))
+    (dolist (subdir dirlist)
+      (setq result (append result
+                           (vc-cvs-dir-status-heuristic subdir nil
+                                                        (or basedir dir)))))
+    (if basedir result
+      (funcall update-function result))))
+
 (defun vc-cvs-dir-status (dir update-function)
   "Create a list of conses (file . state) for DIR."
-  (vc-cvs-command (current-buffer) 'async dir "status")
-  ;; Alternative implementation: use the "update" command instead of
-  ;; the "status" command.
-  ;; (vc-cvs-command (current-buffer) 'async
-  ;;             (file-relative-name dir)
-  ;;             "-f" "-n" "update" "-d" "-P")
+  ;; FIXME check all files in DIR instead?
+  (let ((local (vc-stay-local-p dir)))
+    (if (and local (not (eq local 'only-file)))
+       (vc-cvs-dir-status-heuristic dir update-function)
+      (vc-cvs-command (current-buffer) 'async dir "-f" "status")
+      ;; Alternative implementation: use the "update" command instead of
+      ;; the "status" command.
+      ;; (vc-cvs-command (current-buffer) 'async
+      ;;                 (file-relative-name dir)
+      ;;                 "-f" "-n" "update" "-d" "-P")
+      (vc-exec-after
+       `(vc-cvs-after-dir-status (quote ,update-function))))))
+
+(defun vc-cvs-dir-status-files (dir files default-state update-function)
+  "Create a list of conses (file . state) for DIR."
+  (apply 'vc-cvs-command (current-buffer) 'async dir "-f" "status" files)
   (vc-exec-after
    `(vc-cvs-after-dir-status (quote ,update-function))))
 
-(defun vc-cvs-status-extra-headers (dir)
+(defun vc-cvs-file-to-string (file)
+  "Read the content of FILE and return it as a string."
+  (condition-case nil
+      (with-temp-buffer
+       (insert-file-contents file)
+       (goto-char (point-min))
+       (buffer-substring (point) (point-max)))
+    (file-error nil)))
+
+(defun vc-cvs-dir-extra-headers (dir)
+  "Extract and represent per-directory properties of a CVS working copy."
   (let ((repo
-        (condition-case nil 
-            (save-excursion 
-              (set-buffer (find-file-noselect "CVS/Root" t))
+        (condition-case nil
+            (with-temp-buffer
+              (insert-file-contents "CVS/Root")
+              (goto-char (point-min))
               (and (looking-at ":ext:") (delete-char 5))
-              (buffer-string))
-          nil)))
+              (concat (buffer-substring (point) (1- (point-max))) "\n"))
+          (file-error nil)))
+       (module
+        (condition-case nil
+            (with-temp-buffer
+              (insert-file-contents "CVS/Repository")
+              (goto-char (point-min))
+              (skip-chars-forward "^\n")
+              (concat (buffer-substring (point-min) (point)) "\n"))
+          (file-error nil))))
     (concat
-     ;; FIXME: see how PCL-CVS gets the data to print all these
-     (propertize "Module     : " 'face 'font-lock-type-face)
-     (propertize "ADD CODE TO PRINT THE MODULE\n"
-                'face 'font-lock-warning-face)
      (cond (repo
-           (concat
-             (propertize "Repository : " 'face 'font-lock-type-face)
-             (propertize repo 'face 'font-lock-warning-face)))
+           (concat (propertize "Repository : " 'face 'font-lock-type-face)
+                    (propertize repo 'face 'font-lock-variable-name-face)))
+          (t ""))
+     (cond (module
+           (concat (propertize "Module     : " 'face 'font-lock-type-face)
+                    (propertize module 'face 'font-lock-variable-name-face)))
           (t ""))
-     (propertize "Branch     : " 'face 'font-lock-type-face)
-     (propertize "ADD CODE TO PRINT THE BRANCH NAME\n"
-                'face 'font-lock-warning-face))))
+     (if (file-readable-p "CVS/Tag")
+        (let ((tag (vc-cvs-file-to-string "CVS/Tag")))
+          (cond
+           ((string-match "\\`T" tag)
+            (concat (propertize "Tag        : " 'face 'font-lock-type-face)
+                    (propertize (substring tag 1)
+                                'face 'font-lock-variable-name-face)))
+           ((string-match "\\`D" tag)
+            (concat (propertize "Date       : " 'face 'font-lock-type-face)
+                    (propertize (substring tag 1)
+                                'face 'font-lock-variable-name-face)))
+           (t ""))))
+
+     ;; In CVS, branch is a per-file property, not a per-directory property.
+     ;; We can't really do this here without making dangerous assumptions.
+     ;;(propertize "Branch:     " 'face 'font-lock-type-face)
+     ;;(propertize "ADD CODE TO PRINT THE BRANCH NAME\n"
+     ;;         'face 'font-lock-warning-face)
+     )))
 
 (defun vc-cvs-get-entries (dir)
   "Insert the CVS/Entries file from below DIR into the current buffer.
@@ -1024,7 +1120,6 @@ is non-nil."
   (cond
    ;; entry for a "locally added" file (not yet committed)
    ((looking-at "/[^/]+/0/")
-    (vc-file-setprop file 'vc-backend 'CVS)
     (vc-file-setprop file 'vc-checkout-time 0)
     (vc-file-setprop file 'vc-working-revision "0")
     (if set-state (vc-file-setprop file 'vc-state 'added)))
@@ -1040,7 +1135,6 @@ is non-nil."
             ;; sticky tag
             "\\(.\\|\\)" ;Sticky tag type (date or tag name, could be empty)
             "\\(.*\\)"))               ;Sticky tag
-    (vc-file-setprop file 'vc-backend 'CVS)
     (vc-file-setprop file 'vc-working-revision (match-string 1))
     (vc-file-setprop file 'vc-cvs-sticky-tag
                     (vc-cvs-parse-sticky-tag (match-string 4)
@@ -1087,7 +1181,7 @@ is non-nil."
     (setq table (lazy-completion-table
                  table (lambda () (vc-cvs-revision-table (car files)))))
     table))
-                                           
+
 
 (provide 'vc-cvs)