Skip to content

Commit 433ee03

Browse files
committed
git.el: Never clear the status buffer, only update the files.
This makes it unnecessary to save/restore the file marks. Signed-off-by: Alexandre Julliard <julliard@winehq.org>
1 parent db18a18 commit 433ee03

File tree

1 file changed

+85
-84
lines changed

1 file changed

+85
-84
lines changed

contrib/emacs/git.el

Lines changed: 85 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ the process output as a string, or nil if the git command failed."
356356
(save-buffer))
357357
(when created
358358
(git-call-process nil "update-index" "--add" "--" (file-relative-name ignore-name)))
359-
(git-update-status-files (list (file-relative-name ignore-name)) 'unknown)))
359+
(git-update-status-files (list (file-relative-name ignore-name)))))
360360

361361
; propertize definition for XEmacs, stolen from erc-compat
362362
(eval-when-compile
@@ -497,21 +497,19 @@ the process output as a string, or nil if the git command failed."
497497
old-perm new-perm ;; permission flags
498498
rename-state ;; rename or copy state
499499
orig-name ;; original name for renames or copies
500+
needs-update ;; whether file needs to be updated
500501
needs-refresh) ;; whether file needs to be refreshed
501502

502503
(defvar git-status nil)
503504

504-
(defun git-clear-status (status)
505-
"Remove everything from the status list."
506-
(ewoc-filter status (lambda (info) nil)))
507-
508505
(defun git-set-fileinfo-state (info state)
509506
"Set the state of a file info."
510507
(unless (eq (git-fileinfo->state info) state)
511508
(setf (git-fileinfo->state info) state
512509
(git-fileinfo->new-perm info) (git-fileinfo->old-perm info)
513510
(git-fileinfo->rename-state info) nil
514511
(git-fileinfo->orig-name info) nil
512+
(git-fileinfo->needs-update info) nil
515513
(git-fileinfo->needs-refresh info) t)))
516514

517515
(defun git-status-filenames-map (status func files &rest args)
@@ -521,10 +519,11 @@ the process output as a string, or nil if the git command failed."
521519
(let ((file (pop files))
522520
(node (ewoc-nth status 0)))
523521
(while (and file node)
524-
(let ((info (ewoc-data node)))
525-
(if (string-lessp (git-fileinfo->name info) file)
522+
(let* ((info (ewoc-data node))
523+
(name (git-fileinfo->name info)))
524+
(if (string-lessp name file)
526525
(setq node (ewoc-next status node))
527-
(if (string-equal (git-fileinfo->name info) file)
526+
(if (string-equal name file)
528527
(apply func info args))
529528
(setq file (pop files))))))))
530529

@@ -622,37 +621,50 @@ the process output as a string, or nil if the git command failed."
622621
(git-file-type-as-string old-perm new-perm)
623622
(git-rename-as-string info)))))
624623

625-
(defun git-insert-info-list (status infolist)
626-
"Insert a list of file infos in the status buffer, replacing existing ones if any."
627-
(setq infolist (sort infolist
628-
(lambda (info1 info2)
629-
(string-lessp (git-fileinfo->name info1)
630-
(git-fileinfo->name info2)))))
631-
(let ((info (pop infolist))
632-
(node (ewoc-nth status 0)))
624+
(defun git-update-node-fileinfo (node info)
625+
"Update the fileinfo of the specified node. The names are assumed to match already."
626+
(let ((data (ewoc-data node)))
627+
(setf
628+
;; preserve the marked flag
629+
(git-fileinfo->marked info) (git-fileinfo->marked data)
630+
(git-fileinfo->needs-update data) nil)
631+
(when (not (equal info data))
632+
(setf (git-fileinfo->needs-refresh info) t
633+
(ewoc-data node) info))))
634+
635+
(defun git-insert-info-list (status infolist files)
636+
"Insert a sorted list of file infos in the status buffer, replacing existing ones if any."
637+
(let* ((info (pop infolist))
638+
(node (ewoc-nth status 0))
639+
(name (and info (git-fileinfo->name info)))
640+
remaining)
633641
(while info
634-
(cond ((not node)
635-
(setq node (ewoc-enter-last status info))
636-
(setq info (pop infolist)))
637-
((string-lessp (git-fileinfo->name (ewoc-data node))
638-
(git-fileinfo->name info))
639-
(setq node (ewoc-next status node)))
640-
((string-equal (git-fileinfo->name (ewoc-data node))
641-
(git-fileinfo->name info))
642-
;; preserve the marked flag
643-
(setf (git-fileinfo->marked info) (git-fileinfo->marked (ewoc-data node)))
644-
(setf (git-fileinfo->needs-refresh info) t)
645-
(setf (ewoc-data node) info)
646-
(setq info (pop infolist)))
647-
(t
648-
(setq node (ewoc-enter-before status node info))
649-
(setq info (pop infolist)))))))
642+
(let ((nodename (and node (git-fileinfo->name (ewoc-data node)))))
643+
(while (and files (string-lessp (car files) name))
644+
(push (pop files) remaining))
645+
(when (and files (string-equal (car files) name))
646+
(setq files (cdr files)))
647+
(cond ((not nodename)
648+
(setq node (ewoc-enter-last status info))
649+
(setq info (pop infolist))
650+
(setq name (and info (git-fileinfo->name info))))
651+
((string-lessp nodename name)
652+
(setq node (ewoc-next status node)))
653+
((string-equal nodename name)
654+
;; preserve the marked flag
655+
(git-update-node-fileinfo node info)
656+
(setq info (pop infolist))
657+
(setq name (and info (git-fileinfo->name info))))
658+
(t
659+
(setq node (ewoc-enter-before status node info))
660+
(setq info (pop infolist))
661+
(setq name (and info (git-fileinfo->name info)))))))
662+
(nconc (nreverse remaining) files)))
650663

651664
(defun git-run-diff-index (status files)
652665
"Run git-diff-index on FILES and parse the results into STATUS.
653666
Return the list of files that haven't been handled."
654-
(let ((remaining (copy-sequence files))
655-
infolist)
667+
(let (infolist)
656668
(with-temp-buffer
657669
(apply #'git-call-process t "diff-index" "-z" "-M" "HEAD" "--" files)
658670
(goto-char (point-min))
@@ -669,11 +681,12 @@ Return the list of files that haven't been handled."
669681
(push (git-create-fileinfo 'added new-name old-perm new-perm 'copy name) infolist)
670682
(push (git-create-fileinfo 'deleted name 0 0 'rename new-name) infolist)
671683
(push (git-create-fileinfo 'added new-name old-perm new-perm 'rename name) infolist))
672-
(push (git-create-fileinfo (git-state-code state) name old-perm new-perm) infolist))
673-
(setq remaining (delete name remaining))
674-
(when new-name (setq remaining (delete new-name remaining))))))
675-
(git-insert-info-list status infolist)
676-
remaining))
684+
(push (git-create-fileinfo (git-state-code state) name old-perm new-perm) infolist)))))
685+
(setq infolist (sort (nreverse infolist)
686+
(lambda (info1 info2)
687+
(string-lessp (git-fileinfo->name info1)
688+
(git-fileinfo->name info2)))))
689+
(git-insert-info-list status infolist files)))
677690

678691
(defun git-find-status-file (status file)
679692
"Find a given file in the status ewoc and return its node."
@@ -693,27 +706,24 @@ Return the list of files that haven't been handled."
693706
(let ((name (match-string 1)))
694707
(push (git-create-fileinfo default-state name 0
695708
(if (string-equal "/" (match-string 2)) (lsh ?\110 9) 0))
696-
infolist)
697-
(setq files (delete name files)))))
698-
(git-insert-info-list status infolist)
699-
files))
709+
infolist))))
710+
(setq infolist (nreverse infolist)) ;; assume it is sorted already
711+
(git-insert-info-list status infolist files)))
700712

701713
(defun git-run-ls-files-cached (status files default-state)
702714
"Run git-ls-files -c on FILES and parse the results into STATUS.
703715
Return the list of files that haven't been handled."
704-
(let ((remaining (copy-sequence files))
705-
infolist)
716+
(let (infolist)
706717
(with-temp-buffer
707718
(apply #'git-call-process t "ls-files" "-z" "-s" "-c" "--" files)
708719
(goto-char (point-min))
709720
(while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} 0\t\\([^\0]+\\)\0" nil t)
710721
(let* ((new-perm (string-to-number (match-string 1) 8))
711722
(old-perm (if (eq default-state 'added) 0 new-perm))
712723
(name (match-string 2)))
713-
(push (git-create-fileinfo default-state name old-perm new-perm) infolist)
714-
(setq remaining (delete name remaining)))))
715-
(git-insert-info-list status infolist)
716-
remaining))
724+
(push (git-create-fileinfo default-state name old-perm new-perm) infolist))))
725+
(setq infolist (nreverse infolist)) ;; assume it is sorted already
726+
(git-insert-info-list status infolist files)))
717727

718728
(defun git-run-ls-unmerged (status files)
719729
"Run git-ls-files -u on FILES and parse the results into STATUS."
@@ -742,11 +752,17 @@ Return the list of files that haven't been handled."
742752
(concat "--exclude-per-directory=" git-per-dir-ignore-file)
743753
(append options (mapcar (lambda (f) (concat "--exclude-from=" f)) exclude-files)))))
744754

745-
(defun git-update-status-files (files &optional default-state)
755+
(defun git-update-status-files (&optional files)
746756
"Update the status of FILES from the index."
747757
(unless git-status (error "Not in git-status buffer."))
748-
(when (or git-show-uptodate files)
749-
(git-run-ls-files-cached git-status files 'uptodate))
758+
;; set the needs-update flag on existing files
759+
(if (setq files (sort files #'string-lessp))
760+
(git-status-filenames-map
761+
git-status (lambda (info) (setf (git-fileinfo->needs-update info) t)) files)
762+
(ewoc-map (lambda (info) (setf (git-fileinfo->needs-update info) t) nil) git-status)
763+
(git-call-process nil "update-index" "--refresh")
764+
(when git-show-uptodate
765+
(git-run-ls-files-cached git-status nil 'uptodate)))
750766
(let* ((remaining-files
751767
(if (git-empty-db-p) ; we need some special handling for an empty db
752768
(git-run-ls-files-cached git-status files 'added)
@@ -756,7 +772,11 @@ Return the list of files that haven't been handled."
756772
(setq remaining-files (git-run-ls-files-with-excludes git-status remaining-files 'unknown "-o")))
757773
(when (or remaining-files (and git-show-ignored (not files)))
758774
(setq remaining-files (git-run-ls-files-with-excludes git-status remaining-files 'ignored "-o" "-i")))
759-
(git-set-filenames-state git-status remaining-files default-state)
775+
(unless files
776+
(setq remaining-files (git-get-filenames (ewoc-collect git-status #'git-fileinfo->needs-update))))
777+
(when remaining-files
778+
(setq remaining-files (git-run-ls-files-cached git-status remaining-files 'uptodate)))
779+
(git-set-filenames-state git-status remaining-files nil)
760780
(git-refresh-files)
761781
(git-refresh-ewoc-hf git-status)))
762782

@@ -891,11 +911,9 @@ Return the list of files that haven't been handled."
891911
(condition-case nil (delete-file ".git/MERGE_HEAD") (error nil))
892912
(condition-case nil (delete-file ".git/MERGE_MSG") (error nil))
893913
(with-current-buffer buffer (erase-buffer))
894-
(git-update-status-files (git-get-filenames files) 'uptodate)
914+
(git-update-status-files (git-get-filenames files))
895915
(git-call-process nil "rerere")
896916
(git-call-process nil "gc" "--auto")
897-
(git-refresh-files)
898-
(git-refresh-ewoc-hf git-status)
899917
(message "Committed %s." commit)
900918
(git-run-hook "post-commit" nil)))
901919
(message "Commit aborted."))))
@@ -1009,7 +1027,7 @@ Return the list of files that haven't been handled."
10091027
(unless files
10101028
(push (file-relative-name (read-file-name "File to add: " nil nil t)) files))
10111029
(when (apply 'git-call-process-display-error "update-index" "--add" "--" files)
1012-
(git-update-status-files files 'uptodate)
1030+
(git-update-status-files files)
10131031
(git-success-message "Added" files))))
10141032

10151033
(defun git-ignore-file ()
@@ -1019,7 +1037,7 @@ Return the list of files that haven't been handled."
10191037
(unless files
10201038
(push (file-relative-name (read-file-name "File to ignore: " nil nil t)) files))
10211039
(dolist (f files) (git-append-to-ignore f))
1022-
(git-update-status-files files 'ignored)
1040+
(git-update-status-files files)
10231041
(git-success-message "Ignored" files)))
10241042

10251043
(defun git-remove-file ()
@@ -1037,7 +1055,7 @@ Return the list of files that haven't been handled."
10371055
(delete-directory name)
10381056
(delete-file name))))
10391057
(when (apply 'git-call-process-display-error "update-index" "--remove" "--" files)
1040-
(git-update-status-files files nil)
1058+
(git-update-status-files files)
10411059
(git-success-message "Removed" files)))
10421060
(message "Aborting"))))
10431061

@@ -1065,7 +1083,7 @@ Return the list of files that haven't been handled."
10651083
(apply 'git-call-process-display-error "update-index" "--force-remove" "--" added))
10661084
(or (not modified)
10671085
(apply 'git-call-process-display-error "checkout" "HEAD" modified)))))
1068-
(git-update-status-files (append added modified) 'uptodate)
1086+
(git-update-status-files (append added modified))
10691087
(when ok
10701088
(dolist (file modified)
10711089
(let ((buffer (get-file-buffer file)))
@@ -1078,7 +1096,7 @@ Return the list of files that haven't been handled."
10781096
(let ((files (git-get-filenames (git-marked-files-state 'unmerged))))
10791097
(when files
10801098
(when (apply 'git-call-process-display-error "update-index" "--" files)
1081-
(git-update-status-files files 'uptodate)
1099+
(git-update-status-files files)
10821100
(git-success-message "Resolved" files)))))
10831101

10841102
(defun git-remove-handled ()
@@ -1348,7 +1366,7 @@ amended version of it."
13481366
(git-call-process-display-error "reset" "--soft" "HEAD^")
13491367
(and (git-update-ref "ORIG_HEAD" commit)
13501368
(git-update-ref "HEAD" nil commit)))
1351-
(git-update-status-files (copy-sequence files) 'uptodate)
1369+
(git-update-status-files (copy-sequence files))
13521370
(git-mark-files git-status files)
13531371
(git-refresh-files)
13541372
(git-setup-commit-buffer commit)
@@ -1391,27 +1409,10 @@ amended version of it."
13911409
(defun git-refresh-status ()
13921410
"Refresh the git status buffer."
13931411
(interactive)
1394-
(let* ((status git-status)
1395-
(pos (ewoc-locate status))
1396-
(marked-files (git-get-filenames (ewoc-collect status (lambda (info) (git-fileinfo->marked info)))))
1397-
(cur-name (and pos (git-fileinfo->name (ewoc-data pos)))))
1398-
(unless status (error "Not in git-status buffer."))
1399-
(message "Refreshing git status...")
1400-
(git-call-process nil "update-index" "--refresh")
1401-
(git-clear-status status)
1402-
(git-update-status-files nil)
1403-
; restore file marks
1404-
(when marked-files
1405-
(git-status-filenames-map status
1406-
(lambda (info)
1407-
(setf (git-fileinfo->marked info) t)
1408-
(setf (git-fileinfo->needs-refresh info) t))
1409-
marked-files)
1410-
(git-refresh-files))
1411-
; move point to the current file name if any
1412-
(message "Refreshing git status...done")
1413-
(let ((node (and cur-name (git-find-status-file status cur-name))))
1414-
(when node (ewoc-goto-node status node)))))
1412+
(unless git-status (error "Not in git-status buffer."))
1413+
(message "Refreshing git status...")
1414+
(git-update-status-files)
1415+
(message "Refreshing git status...done"))
14151416

14161417
(defun git-status-quit ()
14171418
"Quit git-status mode."
@@ -1591,7 +1592,7 @@ Meant to be used in `after-save-hook'."
15911592
; skip files located inside the .git directory
15921593
(unless (string-match "^\\.git/" filename)
15931594
(git-call-process nil "add" "--refresh" "--" filename)
1594-
(git-update-status-files (list filename) 'uptodate)))))))
1595+
(git-update-status-files (list filename))))))))
15951596

15961597
(defun git-help ()
15971598
"Display help for Git mode."

0 commit comments

Comments
 (0)