Function: vc-git-after-dir-status-stage

vc-git-after-dir-status-stage is a byte-compiled function defined in vc-git.el.gz.

Signature

(vc-git-after-dir-status-stage GIT-STATE)

Documentation

Process sentinel for the various dir-status stages.

Source Code

;; Defined in /usr/src/emacs/lisp/vc/vc-git.el.gz
(defun vc-git-after-dir-status-stage (git-state)
  "Process sentinel for the various dir-status stages."
  (let (next-stage
        (files (vc-git-dir-status-state->files git-state)))
    ;; First stage is always update-index.
    ;;   After that, if no commits yet, ls-files-added.
    ;;   Otherwise (there are commits), diff-index then ls-files-missing.
    ;;     After ls-files-missing, if FILES non-nil, ls-files-up-to-date.
    ;;     After ls-files-missing, if FILES     nil, ls-files-conflict.
    ;; Then always ls-files-unknown.
    ;; Finally, if FILES non-nil, ls-files-ignored.
    (goto-char (point-min))
    (pcase (vc-git-dir-status-state->stage git-state)
      ('update-index
       (setq next-stage (if (vc-git--empty-db-p) 'ls-files-added 'diff-index)))
      ('ls-files-added
       (setq next-stage 'ls-files-unknown)
       (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} 0\t\\([^\0]+\\)\0" nil t)
         (let ((new-perm (string-to-number (match-string 1) 8))
               (name (match-string 2)))
           (vc-git-dir-status-update-file
            git-state name 'added
            (vc-git-create-extra-fileinfo 0 new-perm)))))
      ('ls-files-up-to-date
       (setq next-stage 'ls-files-unknown)
       (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))
                (file-info (vc-git-create-extra-fileinfo perm perm)))
           (if (equal state "0")
               (unless (gethash name (vc-git-dir-status-state->hash git-state))
                 ;; `diff-index' stage has not produced a more precise info.
                 (vc-git-dir-status-update-file
                  git-state name 'up-to-date file-info))
             ;; `diff-index' assigns `edited' status to conflicted
             ;; files, so we can't do the above in both cases.
             (vc-git-dir-status-update-file
              git-state name 'conflict file-info)))))
      ('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)))
           (vc-git-dir-status-update-file
            git-state name 'conflict
            (vc-git-create-extra-fileinfo perm perm)))))
      ('ls-files-missing
       (setq next-stage (if files 'ls-files-up-to-date 'ls-files-conflict))
       (while (re-search-forward "\\([^\0]*?\\)\0" nil t 1)
         (vc-git-dir-status-update-file git-state (match-string 1) 'missing
                                        (vc-git-create-extra-fileinfo 0 0))))
      ('ls-files-unknown
       (when files (setq next-stage 'ls-files-ignored))
       (while (re-search-forward "\\([^\0]*?\\)\0" nil t 1)
         (vc-git-dir-status-update-file git-state (match-string 1) 'unregistered
                                        (vc-git-create-extra-fileinfo 0 0))))
      ('ls-files-ignored
       (while (re-search-forward "\\([^\0]*?\\)\0" nil t 1)
         (vc-git-dir-status-update-file git-state (match-string 1) 'ignored
                                        (vc-git-create-extra-fileinfo 0 0))))
      ('diff-index
       ;; This is output from 'git diff-index' without --cached.
       ;; Therefore this stage compares HEAD and the working tree and
       ;; ignores the index (cf. git-diff-index(1) "RAW OUTPUT FORMAT").
       ;; In particular that means it cannot distinguish between
       ;; `removed' (deletion staged) and `missing' (deleted only in
       ;; working tree).  Set them all to `removed' and then do
       ;; `ls-files-missing' as the next stage to possibly change some
       ;; of those just set to `removed', to `missing'.
       (setq next-stage 'ls-files-missing)
       (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)
         (let ((old-perm (string-to-number (match-string 1) 8))
               (new-perm (string-to-number (match-string 2) 8))
               (state (or (match-string 4) (match-string 6)))
               (name (or (match-string 5) (match-string 7)))
               (new-name (match-string 8)))
           (if new-name                 ; Copy or rename.
               (if (eq ?C (string-to-char state))
                   (vc-git-dir-status-update-file
                    git-state new-name 'added
                    (vc-git-create-extra-fileinfo old-perm new-perm
                                                  'copy name))
                 (vc-git-dir-status-update-file
                  git-state name 'removed
                  (vc-git-create-extra-fileinfo 0 0 'rename new-name))
                 (vc-git-dir-status-update-file
                  git-state new-name 'added
                  (vc-git-create-extra-fileinfo old-perm new-perm
                                                'rename name)))
             (vc-git-dir-status-update-file
              git-state name (pcase (string-to-char state)
                               (?M 'edited)
                               (?A 'added)
                               (?C 'added)
                               (?D 'removed)
                               (?U 'edited)  ;; FIXME
                               (?T 'edited)) ;; FIXME
              (vc-git-create-extra-fileinfo old-perm new-perm)))))))
    ;; If we had files but now we don't, it's time to stop.
    (when (and files (not (vc-git-dir-status-state->files git-state)))
      (setq next-stage nil))
    (setf (vc-git-dir-status-state->stage git-state) next-stage)
    (setf (vc-git-dir-status-state->files git-state) files)
    (if next-stage
        (vc-git-dir-status-goto-stage git-state)
      (funcall (vc-git-dir-status-state->update-function git-state)
               (let ((result nil))
                 (maphash (lambda (key value)
                            (push (cons key value) result))
                          (vc-git-dir-status-state->hash git-state))
                 result)
               nil))))