Subject: bug#25683: semi-working patch

From: Tom Tromey <[email-masked]>
Date: Sat, 11 Feb 2017 13:45:06 -0700

This patch kind of works.

That is, it correctly notices files that have a conflict.  However, when
typing "g" in vc-dir, such a file briefly appears as "edited", then
switches to "conflict".  This happens because a file is first noticed in
the diff-index phase, then later its state is corrected in the new
ls-files-conflict stage.

Ideally it would be possible to get the conflict state directly from git
diff-index, but I couldn't see a way to do that :(.  The manual says:

        8. sha1 for "dst"; 0{40} if creation, unmerged or "look at work tree".

... but this just means the value can be all-0 for either the edited or
conflict states.

One fix for this might be to pass maintain more state here and only call
the update-function when all the passes are done.

Another idea for a fix would be to notice files with an all-0 sha in
diff-index, then push these names on "files"; then let the new
ls-files-conflict stage determine the result.

Tom

diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index 24dabb6..db19eb0 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -417,10 +417,22 @@ vc-git-after-dir-status-stage
                  result))))
       (`ls-files-up-to-date
        (setq next-stage 'ls-files-unknown)
-       (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} 0\t\\([^\0]+\\)\0" nil t)
+       (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} \\([0-3]\\)\t\\([^\0]+\\)\0" nil t)
+         (let ((perm (string-to-number (match-string 1) 8))
+               (state (match-string 2))
+               (name (match-string 3)))
+           (push (list name (if (equal state "0")
+                                'up-to-date
+                              'conflict)
+                       (vc-git-create-extra-fileinfo perm perm))
+                 result))))
+      (`ls-files-conflict
+       (setq next-stage 'ls-files-unknown)
+       ;; It's enough to look for "3" to notice a conflict.
+       (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} 3\t\\([^\0]+\\)\0" nil t)
          (let ((perm (string-to-number (match-string 1) 8))
                (name (match-string 2)))
-           (push (list name 'up-to-date
+           (push (list name 'conflict
                        (vc-git-create-extra-fileinfo perm perm))
                  result))))
       (`ls-files-unknown
@@ -435,7 +447,7 @@ vc-git-after-dir-status-stage
                      (vc-git-create-extra-fileinfo 0 0))
                result)))
       (`diff-index
-       (setq next-stage (if files 'ls-files-up-to-date 'ls-files-unknown))
+       (setq next-stage (if files 'ls-files-up-to-date 'ls-files-conflict))
        (while (re-search-forward
                ":\\([0-7]\\{6\\}\\) \\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} [0-9a-f]\\{40\\} \\(\\([ADMUT]\\)\0\\([^\0]+\\)\\|\\([CR]\\)[0-9]*\0\\([^\0]+\\)\0\\([^\0]+\\)\\)\0"
                nil t 1)
@@ -491,6 +503,9 @@ vc-git-dir-status-goto-stage
     (`ls-files-up-to-date
      (vc-git-command (current-buffer) 'async files
                      "ls-files" "-z" "-c" "-s" "--"))
+    (`ls-files-conflict
+     (vc-git-command (current-buffer) 'async files
+                     "ls-files" "-z" "-c" "-s" "--"))
     (`ls-files-unknown
      (vc-git-command (current-buffer) 'async files
                      "ls-files" "-z" "-o" "--directory"