Subject: bug#49683: Unable to open file under Git VC

From: Yan Gajdos <[email-masked]>
Date: Wed, 21 Jul 2021 17:37:05 +0200

Emacs kept refusing to open a file with 'emacs lisp/wang/wang.lisp' and instead reported:
vc-git-mode-line-string: Wrong type argument: arrayp, nil

Adding
(setq debug-on-error t)
at the beginning of vc-git-mode-line-string reveals the problem:

Debugger entered--Lisp error: (wrong-type-argument arrayp nil)
  substring(nil 0 7)
  (or (vc-git--symbolic-ref file) (substring rev 0 7))
  (let* ((rev (vc-working-revision file 'Git)) (disp-rev (or (vc-git--symbolic-ref file) (substring rev 0 7))) (def-ml (vc-default-mode-line-string 'Git file)) (help-echo (get-text-property 0 'help-echo def-ml)) (face (get-text-property 0 'face def-ml))) (propertize (concat (substring def-ml 0 4) disp-rev) 'face face 'help-echo (concat help-echo "\nCurrent revision: " rev)))
  vc-git-mode-line-string("/src/xxx/lisp/wang/wang.lisp")
  apply(vc-git-mode-line-string "/src/xxx/lisp/wang/wang.lisp")
  vc-call-backend(Git mode-line-string "/src/xxx/lisp/wang/wang.lisp")
  vc-mode-line("/src/xxx/lisp/wang/wang.lisp" Git)
  vc-refresh-state()
  run-hooks(find-file-hook)
  after-find-file(nil t)
  find-file-noselect-1(#<buffer wang.lisp> "/src/xxx/lisp/wang/wang.lisp" nil nil "/Users/Shared/cl/my/wang/wang.lisp" (133696873 16777221))
  find-file-noselect("/src/xxx/lisp/wang/wang.lisp" nil nil t)
  find-file("/src/xxx/lisp/wang/wang.lisp" t)
  funcall-interactively(find-file "/src/xxx/lisp/wang/wang.lisp" t)
  call-interactively(find-file nil nil)
  command-execute(find-file)

Explanation:
The file used to be in a Git hierarchy, but its directory was moved, and this directory is only pointed to with a symbolic link now.
This seems to give the impression that it both is and isn't under version control, so vc-working-revision returning nil causes the issue.

Solution:
Only attempt to get substring of rev if rev is non-nil.

Patch:
-----
From 4814217010157fb1e8041b6613c6deda70caf51c Mon Sep 17 00:00:00 2001
From: Yan <[email-masked]>
Date: Wed, 21 Jul 2021 16:11:08 +0200
Subject: [PATCH] Ensure git revision exists

---
 lisp/vc/vc-git.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index 89f9800..5828a83 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -375,7 +375,7 @@ (defun vc-git-mode-line-string (file)
   "Return a string for `vc-mode-line' to put in the mode line for FILE."
   (let* ((rev (vc-working-revision file 'Git))
          (disp-rev (or (vc-git--symbolic-ref file)
-                       (substring rev 0 7)))
+                       (and rev (substring rev 0 7))))
          (def-ml (vc-default-mode-line-string 'Git file))
          (help-echo (get-text-property 0 'help-echo def-ml))
          (face   (get-text-property 0 'face def-ml)))
-- 
2.32.0
-----

Works like a charm. Feel free to use or improve.

/Yan

P.S.
Probably unnecessarily lengthy attempt at an explanation of the reason for the issue:
The file was checked in while it was still in the original hierarchy: /src/xxx/lisp/
/src/xxx/.git is the repository location.
/src/xxx/lisp is now a symbolic link pointing to /cl/my/
/cl points to /Users/Shared/cl
Now Git thinks the file is deleted when it's accessed from the old hierarchy (/src/xxx/lisp/), while from the new hierarchy (/cl/my/) it is not under version control at all.