@@ -314,8 +314,8 @@ and returns the process output as a string."
314314 (sort-lines nil (point-min ) (point-max ))
315315 (save-buffer ))
316316 (when created
317- (git-run-command nil nil " update-index" " --info-only " " -- add" " --" (file-relative-name ignore-name)))
318- (git-add -status-file ( if created 'added 'modified ) (file-relative-name ignore-name))))
317+ (git-run-command nil nil " update-index" " --add" " --" (file-relative-name ignore-name)))
318+ (git-update -status-files ( list (file-relative-name ignore-name)) 'unknown )))
319319
320320; propertize definition for XEmacs, stolen from erc-compat
321321(eval-when-compile
@@ -523,23 +523,39 @@ and returns the process output as a string."
523523 " " (git-escape-file-name (git-fileinfo->name info))
524524 (git-rename-as-string info))))
525525
526- (defun git-parse-status (status )
527- " Parse the output of git-diff-index in the current buffer."
528- (goto-char (point-min ))
529- (while (re-search-forward
530- " :\\ ([0-7]\\ {6\\ }\\ ) \\ ([0-7]\\ {6\\ }\\ ) [0-9a-f]\\ {40\\ } [0-9a-f]\\ {40\\ } \\ (\\ ([ADMU]\\ )\0 \\ ([^\0 ]+\\ )\\ |\\ ([CR]\\ )[0-9]*\0 \\ ([^\0 ]+\\ )\0 \\ ([^\0 ]+\\ )\\ )\0 "
531- nil t 1 )
532- (let ((old-perm (string-to-number (match-string 1 ) 8 ))
533- (new-perm (string-to-number (match-string 2 ) 8 ))
534- (state (or (match-string 4 ) (match-string 6 )))
535- (name (or (match-string 5 ) (match-string 7 )))
536- (new-name (match-string 8 )))
537- (if new-name ; copy or rename
538- (if (eq ?C (string-to-char state))
539- (ewoc-enter-last status (git-create-fileinfo 'added new-name old-perm new-perm 'copy name))
540- (ewoc-enter-last status (git-create-fileinfo 'deleted name 0 0 'rename new-name))
541- (ewoc-enter-last status (git-create-fileinfo 'added new-name old-perm new-perm 'rename name)))
542- (ewoc-enter-last status (git-create-fileinfo (git-state-code state) name old-perm new-perm))))))
526+ (defun git-insert-fileinfo (status info &optional refresh )
527+ " Insert INFO in the status buffer, optionally refreshing an existing one."
528+ (let ((node (and refresh
529+ (git-find-status-file status (git-fileinfo->name info)))))
530+ (setf (git-fileinfo->needs-refresh info) t )
531+ (when node ; preserve the marked flag
532+ (setf (git-fileinfo->marked info) (git-fileinfo->marked (ewoc-data node))))
533+ (if node (ewoc-set-data node info) (ewoc-enter-last status info))))
534+
535+ (defun git-run-diff-index (status files )
536+ " Run git-diff-index on FILES and parse the results into STATUS.
537+ Return the list of files that haven't been handled."
538+ (let ((refresh files ))
539+ (with-temp-buffer
540+ (apply #'git-run-command t nil " diff-index" " -z" " -M" " HEAD" " --" files )
541+ (goto-char (point-min ))
542+ (while (re-search-forward
543+ " :\\ ([0-7]\\ {6\\ }\\ ) \\ ([0-7]\\ {6\\ }\\ ) [0-9a-f]\\ {40\\ } [0-9a-f]\\ {40\\ } \\ (\\ ([ADMU]\\ )\0 \\ ([^\0 ]+\\ )\\ |\\ ([CR]\\ )[0-9]*\0 \\ ([^\0 ]+\\ )\0 \\ ([^\0 ]+\\ )\\ )\0 "
544+ nil t 1 )
545+ (let ((old-perm (string-to-number (match-string 1 ) 8 ))
546+ (new-perm (string-to-number (match-string 2 ) 8 ))
547+ (state (or (match-string 4 ) (match-string 6 )))
548+ (name (or (match-string 5 ) (match-string 7 )))
549+ (new-name (match-string 8 )))
550+ (if new-name ; copy or rename
551+ (if (eq ?C (string-to-char state))
552+ (git-insert-fileinfo status (git-create-fileinfo 'added new-name old-perm new-perm 'copy name) refresh)
553+ (git-insert-fileinfo status (git-create-fileinfo 'deleted name 0 0 'rename new-name) refresh)
554+ (git-insert-fileinfo status (git-create-fileinfo 'added new-name old-perm new-perm 'rename name)) refresh)
555+ (git-insert-fileinfo status (git-create-fileinfo (git-state-code state) name old-perm new-perm) refresh))
556+ (setq files (delete name files ))
557+ (when new-name (setq files (delete new-name files )))))))
558+ files )
543559
544560(defun git-find-status-file (status file )
545561 " Find a given file in the status ewoc and return its node."
@@ -548,32 +564,59 @@ and returns the process output as a string."
548564 (setq node (ewoc-next status node)))
549565 node))
550566
551- (defun git-parse-ls-files (status default-state &optional skip-existing )
552- " Parse the output of git-ls-files in the current buffer."
553- (goto-char (point-min ))
554- (let (infolist)
555- (while (re-search-forward " \\ ([HMRCK?]\\ ) \\ ([^\0 ]*\\ )\0 " nil t 1 )
556- (let ((state (match-string 1 ))
557- (name (match-string 2 )))
558- (unless (and skip-existing (git-find-status-file status name))
559- (push (git-create-fileinfo (or (git-state-code state) default-state) name) infolist))))
560- (dolist (info (nreverse infolist))
561- (ewoc-enter-last status info))))
562-
563- (defun git-parse-ls-unmerged (status )
564- " Parse the output of git-ls-files -u in the current buffer."
565- (goto-char (point-min ))
566- (let (files )
567- (while (re-search-forward " [0-7]\\ {6\\ } [0-9a-f]\\ {40\\ } [123]\t \\ ([^\0 ]+\\ )\0 " nil t )
568- (let ((node (git-find-status-file status (match-string 1 ))))
569- (when node (push (ewoc-data node) files ))))
570- (git-set-files-state files 'unmerged )))
571-
572- (defun git-add-status-file (state name )
573- " Add a new file to the status list (if not existing already) and return its node."
567+ (defun git-run-ls-files (status files default-state &rest options )
568+ " Run git-ls-files on FILES and parse the results into STATUS.
569+ Return the list of files that haven't been handled."
570+ (let ((refresh files ))
571+ (with-temp-buffer
572+ (apply #'git-run-command t nil " ls-files" " -z" " -t" (append options (list " --" ) files ))
573+ (goto-char (point-min ))
574+ (while (re-search-forward " \\ ([HMRCK?]\\ ) \\ ([^\0 ]*\\ )\0 " nil t 1 )
575+ (let ((state (match-string 1 ))
576+ (name (match-string 2 )))
577+ (git-insert-fileinfo status (git-create-fileinfo (or (git-state-code state) default-state) name) refresh)
578+ (setq files (delete name files ))))))
579+ files )
580+
581+ (defun git-run-ls-unmerged (status files )
582+ " Run git-ls-files -u on FILES and parse the results into STATUS."
583+ (with-temp-buffer
584+ (apply #'git-run-command t nil " ls-files" " -z" " -u" " --" files )
585+ (goto-char (point-min ))
586+ (let (unmerged-files)
587+ (while (re-search-forward " [0-7]\\ {6\\ } [0-9a-f]\\ {40\\ } [123]\t \\ ([^\0 ]+\\ )\0 " nil t )
588+ (let ((node (git-find-status-file status (match-string 1 ))))
589+ (when node (push (ewoc-data node) unmerged-files))))
590+ (git-set-files-state unmerged-files 'unmerged ))))
591+
592+ (defun git-update-status-files (files &optional default-state )
593+ " Update the status of FILES from the index."
574594 (unless git-status (error " Not in git-status buffer. " ))
575- (or (git-find-status-file git-status name)
576- (ewoc-enter-last git-status (git-create-fileinfo state name))))
595+ (let* ((status git-status)
596+ (remaining-files
597+ (if (git-empty-db-p) ; we need some special handling for an empty db
598+ (git-run-ls-files status files 'added " -c" )
599+ (git-run-diff-index status files ))))
600+ (git-run-ls-unmerged status files )
601+ (when (and (or (not files ) remaining-files)
602+ (file-readable-p " .git/info/exclude" ))
603+ (setq remaining-files (git-run-ls-files status remaining-files
604+ 'unknown " -o" " --exclude-from=.git/info/exclude"
605+ (concat " --exclude-per-directory=" git-per-dir-ignore-file))))
606+ ; mark remaining files with the default state (or remove them if nil)
607+ (when remaining-files
608+ (if default-state
609+ (ewoc-map (lambda (info )
610+ (when (member (git-fileinfo->name info) remaining-files)
611+ (git-set-files-state (list info) default-state))
612+ nil )
613+ status)
614+ (ewoc-filter status
615+ (lambda (info files )
616+ (not (member (git-fileinfo->name info) files )))
617+ remaining-files)))
618+ (git-refresh-files)
619+ (git-refresh-ewoc-hf status)))
577620
578621(defun git-marked-files ()
579622 " Return a list of all marked files, or if none a list containing just the file at cursor position."
@@ -789,54 +832,34 @@ and returns the process output as a string."
789832(defun git-add-file ()
790833 " Add marked file(s) to the index cache."
791834 (interactive )
792- (let ((files (git-marked-files-state 'unknown )))
835+ (let ((files (git-get-filenames (git- marked-files-state 'unknown ) )))
793836 (unless files
794- (push (ewoc-data
795- (git-add-status-file 'added (file-relative-name
796- (read-file-name " File to add: " nil nil t ))))
797- files ))
798- (apply #'git-run-command nil nil " update-index" " --info-only" " --add" " --" (git-get-filenames files ))
799- (git-set-files-state files 'added )
800- (git-refresh-files)))
837+ (push (file-relative-name (read-file-name " File to add: " nil nil t )) files ))
838+ (apply #'git-run-command nil nil " update-index" " --add" " --" files )
839+ (git-update-status-files files 'uptodate )))
801840
802841(defun git-ignore-file ()
803842 " Add marked file(s) to the ignore list."
804843 (interactive )
805- (let ((files (git-marked-files-state 'unknown )))
844+ (let ((files (git-get-filenames (git- marked-files-state 'unknown ) )))
806845 (unless files
807- (push (ewoc-data
808- (git-add-status-file 'unknown (file-relative-name
809- (read-file-name " File to ignore: " nil nil t ))))
810- files ))
811- (dolist (info files ) (git-append-to-ignore (git-fileinfo->name info)))
812- (git-set-files-state files 'ignored )
813- (git-refresh-files)))
846+ (push (file-relative-name (read-file-name " File to ignore: " nil nil t )) files ))
847+ (dolist (f files ) (git-append-to-ignore f))
848+ (git-update-status-files files 'ignored )))
814849
815850(defun git-remove-file ()
816851 " Remove the marked file(s)."
817852 (interactive )
818- (let ((files (git-marked-files-state 'added 'modified 'unknown 'uptodate )))
853+ (let ((files (git-get-filenames (git- marked-files-state 'added 'modified 'unknown 'uptodate ) )))
819854 (unless files
820- (push (ewoc-data
821- (git-add-status-file 'unknown (file-relative-name
822- (read-file-name " File to remove: " nil nil t ))))
823- files ))
855+ (push (file-relative-name (read-file-name " File to remove: " nil nil t )) files ))
824856 (if (yes-or-no-p
825857 (format " Remove %d file%s ? " (length files ) (if (> (length files ) 1 ) " s" " " )))
826858 (progn
827- (dolist (info files )
828- (let ((name (git-fileinfo->name info)))
829- (when (file-exists-p name) (delete-file name))))
830- (apply #'git-run-command nil nil " update-index" " --info-only" " --remove" " --" (git-get-filenames files ))
831- ; remove unknown files from the list, set the others to deleted
832- (ewoc-filter git-status
833- (lambda (info files )
834- (not (and (memq info files ) (eq (git-fileinfo->state info) 'unknown ))))
835- files )
836- (git-set-files-state files 'deleted )
837- (git-refresh-files)
838- (unless (ewoc-nth git-status 0 ) ; refresh header if list is empty
839- (git-refresh-ewoc-hf git-status)))
859+ (dolist (name files )
860+ (when (file-exists-p name) (delete-file name)))
861+ (apply #'git-run-command nil nil " update-index" " --remove" " --" files )
862+ (git-update-status-files files nil ))
840863 (message " Aborting " ))))
841864
842865(defun git-revert-file ()
@@ -849,26 +872,23 @@ and returns the process output as a string."
849872 (format " Revert %d file%s ? " (length files ) (if (> (length files ) 1 ) " s" " " ))))
850873 (dolist (info files )
851874 (case (git-fileinfo->state info)
852- ('added (push info added))
853- ('deleted (push info modified))
854- ('unmerged (push info modified))
855- ('modified (push info modified))))
875+ ('added (push (git-fileinfo->name info) added))
876+ ('deleted (push (git-fileinfo->name info) modified))
877+ ('unmerged (push (git-fileinfo->name info) modified))
878+ ('modified (push (git-fileinfo->name info) modified))))
856879 (when added
857- (apply #'git-run-command nil nil " update-index" " --force-remove" " --" (git-get-filenames added))
858- (git-set-files-state added 'unknown ))
880+ (apply #'git-run-command nil nil " update-index" " --force-remove" " --" added))
859881 (when modified
860- (apply #'git-run-command nil nil " checkout" " HEAD" (git-get-filenames modified))
861- (git-set-files-state modified 'uptodate ))
862- (git-refresh-files))))
882+ (apply #'git-run-command nil nil " checkout" " HEAD" modified))
883+ (git-update-status-files (append added modified) 'uptodate ))))
863884
864885(defun git-resolve-file ()
865886 " Resolve conflicts in marked file(s)."
866887 (interactive )
867- (let ((files (git-marked-files-state 'unmerged )))
888+ (let ((files (git-get-filenames (git- marked-files-state 'unmerged ) )))
868889 (when files
869- (apply #'git-run-command nil nil " update-index" " --" (git-get-filenames files ))
870- (git-set-files-state files 'modified )
871- (git-refresh-files))))
890+ (apply #'git-run-command nil nil " update-index" " --" files )
891+ (git-update-status-files files 'uptodate ))))
872892
873893(defun git-remove-handled ()
874894 " Remove handled files from the status list."
@@ -1071,27 +1091,9 @@ and returns the process output as a string."
10711091 (pos (ewoc-locate status))
10721092 (cur-name (and pos (git-fileinfo->name (ewoc-data pos)))))
10731093 (unless status (error " Not in git-status buffer. " ))
1094+ (git-run-command nil nil " update-index" " --refresh" )
10741095 (git-clear-status status)
1075- (git-run-command nil nil " update-index" " --info-only" " --refresh" )
1076- (if (git-empty-db-p)
1077- ; we need some special handling for an empty db
1078- (with-temp-buffer
1079- (git-run-command t nil " ls-files" " -z" " -t" " -c" )
1080- (git-parse-ls-files status 'added ))
1081- (with-temp-buffer
1082- (git-run-command t nil " diff-index" " -z" " -M" " HEAD" )
1083- (git-parse-status status)))
1084- (with-temp-buffer
1085- (git-run-command t nil " ls-files" " -z" " -u" )
1086- (git-parse-ls-unmerged status))
1087- (when (file-readable-p " .git/info/exclude" )
1088- (with-temp-buffer
1089- (git-run-command t nil " ls-files" " -z" " -t" " -o"
1090- " --exclude-from=.git/info/exclude"
1091- (concat " --exclude-per-directory=" git-per-dir-ignore-file))
1092- (git-parse-ls-files status 'unknown )))
1093- (git-refresh-files)
1094- (git-refresh-ewoc-hf status)
1096+ (git-update-status-files nil )
10951097 ; move point to the current file name if any
10961098 (let ((node (and cur-name (git-find-status-file status cur-name))))
10971099 (when node (ewoc-goto-node status node)))))
0 commit comments