* bug#25683: 25.1.91; vc-dir shows conflicted files as "edited"
@ 2017-02-10 22:15 Tom Tromey
[not found] ` <handler.25683.B.148676496228355.ack@debbugs.gnu.org>
2017-02-15 4:18 ` bug#25683: done Tom Tromey
0 siblings, 2 replies; 12+ messages in thread
From: Tom Tromey @ 2017-02-10 22:15 UTC (permalink / raw)
To: 25683
I was doing a "git rebase" and it had some conflicts.
If I "git status" in the shell I can see conflicts like:
both modified: gdb/minidebug.c
However, if I use vc-dir, I just see:
edited gdb/minidebug.c
This isn't any different from a file that is touched by this change but
not in conflict.
I think it would be nicer if vc-dir showed me which files had conflicts
and which were merely "edited".
Tom
In GNU Emacs 25.1.91.2 (x86_64-unknown-linux-gnu, GTK+ Version 3.22.7)
of 2017-02-02 built on bapiya
Repository revision: 7e02a477bbcabb4e65aeecade79b67357c0b9dae
Windowing system distributor 'Fedora Project', version 11.0.11901000
System Description: Fedora release 25 (Twenty Five)
Configured using:
'configure --prefix=/home/tromey/Emacs/install/ --with-modules'
Configured features:
XPM JPEG TIFF GIF PNG RSVG IMAGEMAGICK SOUND GPM DBUS GCONF GSETTINGS
NOTIFY LIBSELINUX GNUTLS LIBXML2 FREETYPE M17N_FLT LIBOTF XFT ZLIB
TOOLKIT_SCROLL_BARS GTK3 X11 MODULES
Important settings:
value of $LANG: en_US.utf8
value of $XMODIFIERS: @im=ibus
locale-coding-system: utf-8-unix
Major mode: VC dir
Minor modes in effect:
vc-parent-buffer: *vc-dir*<binutils-gdb>
shell-dirtrack-mode: t
diff-auto-refine-mode: t
which-function-mode: t
erc-services-mode: t
erc-list-mode: t
erc-menu-mode: t
erc-autojoin-mode: t
erc-ring-mode: t
erc-networks-mode: t
erc-pcomplete-mode: t
erc-track-mode: t
erc-match-mode: t
erc-netsplit-mode: t
erc-hl-nicks-mode: t
erc-button-mode: t
erc-fill-mode: t
erc-stamp-mode: t
erc-irccontrols-mode: t
erc-noncommands-mode: t
erc-move-to-prompt-mode: t
erc-readonly-mode: t
savehist-mode: t
tooltip-mode: t
global-eldoc-mode: t
electric-indent-mode: t
mouse-wheel-mode: t
file-name-shadow-mode: t
global-font-lock-mode: t
font-lock-mode: t
auto-composition-mode: t
auto-encryption-mode: t
auto-compression-mode: t
buffer-read-only: t
column-number-mode: t
line-number-mode: t
transient-mark-mode: t
Recent messages:
Delete excess backup versions of /home/tromey/gdb/binutils-gdb/.git/COMMIT_EDITMSG? (y or n) y
Wrote /home/tromey/gdb/binutils-gdb/.git/COMMIT_EDITMSG
There are unresolved conflicts in /home/tromey/gdb/binutils-gdb/gdb/ui-out.h
Making completion list...
Mark saved where search started
Mark set
Mark saved where search started
C-x C-g is undefined
(No files need saving)
Hiding up-to-date and ignored items
Load-path shadows:
/home/tromey/.emacs.d/elpa/bubbles-0.5/bubbles hides /home/tromey/Emacs/install/share/emacs/25.1.91/lisp/play/bubbles
Features:
(shadow emacsbug conf-mode two-column iso-transl perl-mode sh-script
executable cal-move nnregistry python tramp-sh tramp tramp-compat
tramp-loaddefs trampver ucs-normalize make-mode etags cursor-sensor
mhtml-mode org-bullets org-element org-rmail org-mhe org-irc org-info
org-gnus org-docview doc-view image-mode org-bibtex bibtex org-bbdb
org-w3m org org-macro org-footnote org-pcomplete org-list org-faces
org-entities org-version ob-emacs-lisp ob ob-tangle ob-ref ob-lob
ob-table ob-exp org-src ob-keys ob-comint ob-core ob-eval org-compat
org-macs org-loaddefs gnus-fun gnus-draft noutline outline ido skeleton
css-mode smie eww url-queue trace find-dired descr-text gdb-shell
lisp-mnt url-handlers url-http url-gw url-auth lex edebug debug m4-mode
bbdb-sc supercite regi xref project log-edit js json map sgml-mode
flow-fill gnus-html xml url-cache mm-url url url-proxy url-privacy
url-expand url-methods url-history url-cookie url-domsuf eieio-opt
speedbar sb-image ezimage dframe find-func whitespace tcl log-view
pcvs-util vc-annotate term/xterm xterm smerge-mode goto-addr shell
find-file idutils derived bug-reference cc-mode cc-fonts cc-guess
cc-menus cc-cmds jka-compr mailalias mail-hist nnir sort gnus-cite
smiley shr-color url-util url-parse url-vars shr dom subr-x browse-url
mm-archive gnus-async gnus-bcklg qp gnus-ml disp-table gnus-topic
nndraft nnmh nnfolder utf-7 bbdb-gnus bbdb-mua bbdb-com crm
network-stream nsm starttls gnus-agent gnus-srvr gnus-score score-mode
nnvirtual gnus-msg nntp gnus-cache gnus-registry registry eieio-compat
eieio-base gnus-art mm-uu mml2015 mm-view mml-smime smime dig mailcap
gnus-sum gnus-group gnus-undo smtpmail gnus-start gnus-cloud nnimap
nnmail mail-source tls gnutls utf7 netrc nnoo parse-time gnus-spec
gnus-int gnus-range gnus-win gnus gnus-ems nnheader bbdb-message
sendmail mail-extr message idna dired rfc822 mml mml-sec epg mm-decode
mm-bodies mm-encode mail-parse rfc2231 rfc2047 rfc2045 ietf-drums
mailabbrev mail-utils gmm-utils mailheader gud dwarf-mode copyright
dabbrev misearch multi-isearch vc-mtn vc-hg vc-bzr vc-src vc-sccs vc-svn
vc-cvs vc-rcs add-log rx vc-git diff-mode easy-mmode rust-mode flyspell
ispell diminish edmacro kmacro projectile grep compile ibuf-ext ibuffer
dash appt diary-lib diary-loaddefs cal-menu calendar cal-loaddefs
which-func imenu minimap autorevert filenotify cus-start cus-load status
erc-services erc-list erc-menu erc-join erc-ring erc-networks
erc-pcomplete pcomplete erc-track erc-match erc-netsplit erc-hl-nicks
color erc-button erc-fill erc-stamp wid-edit erc-goodies erc erc-backend
erc-compat format-spec auth-source eieio gnus-util mm-util help-fns
mail-prsvr password-cache thingatpt pp warnings advice vc-dir ewoc vc
vc-dispatcher cc-styles cc-align cc-engine cc-vars cc-defs bbdb
bbdb-site timezone ange-ftp comint ansi-color ring server savehist
finder-inf dwarf-mode-autoloads gdb-shell-autoloads eieio-core
lisppaste-autoloads pydoc-info-autoloads info-look cl-seq cl-macs cl
weblogger-autoloads info package epg-config seq byte-opt gv bytecomp
byte-compile cl-extra help-mode easymenu cconv cl-loaddefs pcase cl-lib
bbdb-loaddefs time-date mule-util tooltip eldoc electric uniquify
ediff-hook vc-hooks lisp-float-type mwheel x-win term/common-win x-dnd
tool-bar dnd fontset image regexp-opt fringe tabulated-list newcomment
elisp-mode lisp-mode prog-mode register page menu-bar rfn-eshadow timer
select scroll-bar mouse jit-lock font-lock syntax facemenu font-core
frame cl-generic cham georgian utf-8-lang misc-lang vietnamese tibetan
thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek romanian
slovak czech european ethiopic indian cyrillic chinese charscript
case-table epa-hook jka-cmpr-hook help simple abbrev minibuffer
cl-preloaded nadvice loaddefs button faces cus-face macroexp files
text-properties overlay sha1 md5 base64 format env code-pages mule
custom widget hashtable-print-readable backquote dbusbind inotify
dynamic-setting system-font-setting font-render-setting move-toolbar gtk
x-toolkit x multi-tty make-network-process emacs)
Memory information:
((conses 16 1841388 223499)
(symbols 48 137600 13)
(miscs 40 30171 9433)
(strings 32 518292 186214)
(string-bytes 1 14434760)
(vectors 16 128453)
(vector-slots 8 2744148 100168)
(floats 8 924 1207)
(intervals 56 168057 715)
(buffers 976 269))
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#25683: semi-working patch
[not found] ` <handler.25683.B.148676496228355.ack@debbugs.gnu.org>
@ 2017-02-11 20:45 ` Tom Tromey
2017-02-11 21:40 ` Tom Tromey
0 siblings, 1 reply; 12+ messages in thread
From: Tom Tromey @ 2017-02-11 20:45 UTC (permalink / raw)
To: 25683
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"
^ permalink raw reply related [flat|nested] 12+ messages in thread
* bug#25683: semi-working patch
2017-02-11 20:45 ` bug#25683: semi-working patch Tom Tromey
@ 2017-02-11 21:40 ` Tom Tromey
2017-02-12 6:17 ` Tom Tromey
0 siblings, 1 reply; 12+ messages in thread
From: Tom Tromey @ 2017-02-11 21:40 UTC (permalink / raw)
To: Tom Tromey; +Cc: 25683
Tom> One fix for this might be to pass maintain more state here and only call
Tom> the update-function when all the passes are done.
I've implemented this idea.
Let me know what you think.
Tom
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index 24dabb6..de07ea2 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -401,11 +401,30 @@ vc-git-dir-printer
(vc-git-file-type-as-string old-perm new-perm)
(vc-git-rename-as-string state extra))))
-(defun vc-git-after-dir-status-stage (stage files update-function)
+(cl-defstruct (vc-git-dir-status-state
+ (:copier nil)
+ (:conc-name vc-git-dir-status-state->))
+ ;; Current stage.
+ stage
+ ;; List of files still to be processed.
+ files
+ ;; Update function to be called at the end.
+ update-function
+ ;; Hash table of entries for files we've computed so far.
+ (hash (make-hash-table :test 'equal)))
+
+(defsubst vc-git-dir-status-update-file (state filename file-state file-info)
+ (puthash filename (list file-state file-info)
+ (vc-git-dir-status-state->hash state))
+ (setf (vc-git-dir-status-state->files state)
+ (delete filename (vc-git-dir-status-state->files state))))
+
+(defun vc-git-after-dir-status-stage (git-state)
"Process sentinel for the various dir-status stages."
- (let (next-stage result)
+ (let (next-stage
+ (files (vc-git-dir-status-state->files git-state)))
(goto-char (point-min))
- (pcase stage
+ (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
@@ -413,29 +432,40 @@ vc-git-after-dir-status-stage
(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)))
- (push (list name 'added (vc-git-create-extra-fileinfo 0 new-perm))
- result))))
+ (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\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)))
+ (vc-git-dir-status-update-file
+ git-state name (if (equal state "0")
+ 'up-to-date
+ 'conflict)
+ (vc-git-create-extra-fileinfo perm perm)))))
+ (`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
- (vc-git-create-extra-fileinfo perm perm))
- result))))
+ (vc-git-dir-status-update-file
+ git-state name 'conflict
+ (vc-git-create-extra-fileinfo perm perm)))))
(`ls-files-unknown
(when files (setq next-stage 'ls-files-ignored))
(while (re-search-forward "\\([^\0]*?\\)\0" nil t 1)
- (push (list (match-string 1) 'unregistered
- (vc-git-create-extra-fileinfo 0 0))
- result)))
+ (vc-git-create-extra-fileinfo 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)
- (push (list (match-string 1) 'ignored
- (vc-git-create-extra-fileinfo 0 0))
- result)))
+ (vc-git-dir-status-update-file git-state (match-string 1) 'ignored
+ (vc-git-create-extra-fileinfo 0 0))))
(`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)
@@ -446,30 +476,34 @@ vc-git-after-dir-status-stage
(new-name (match-string 8)))
(if new-name ; Copy or rename.
(if (eq ?C (string-to-char state))
- (push (list new-name 'added
- (vc-git-create-extra-fileinfo old-perm new-perm
- 'copy name))
- result)
- (push (list name 'removed
- (vc-git-create-extra-fileinfo 0 0
- 'rename new-name))
- result)
- (push (list new-name 'added
- (vc-git-create-extra-fileinfo old-perm new-perm
- 'rename name))
- result))
- (push (list name (vc-git--state-code state)
- (vc-git-create-extra-fileinfo old-perm new-perm))
- result))))))
- (when result
- (setq result (nreverse result))
- (when files
- (dolist (entry result) (setq files (delete (car entry) files)))
- (unless files (setq next-stage nil))))
- (when (or result (not next-stage))
- (funcall update-function result next-stage))
- (when next-stage
- (vc-git-dir-status-goto-stage next-stage files update-function))))
+ (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 (vc-git--state-code state)
+ (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))))
;; Follows vc-git-command (or vc-do-async-command), which uses vc-do-command
;; from vc-dispatcher.
@@ -477,41 +511,48 @@ vc-git-after-dir-status-stage
;; Follows vc-exec-after.
(declare-function vc-set-async-update "vc-dispatcher" (process-buffer))
-(defun vc-git-dir-status-goto-stage (stage files update-function)
- (erase-buffer)
- (pcase stage
- (`update-index
- (if files
- (vc-git-command (current-buffer) 'async files "add" "--refresh" "--")
- (vc-git-command (current-buffer) 'async nil
- "update-index" "--refresh")))
- (`ls-files-added
- (vc-git-command (current-buffer) 'async files
- "ls-files" "-z" "-c" "-s" "--"))
- (`ls-files-up-to-date
- (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"
- "--no-empty-directory" "--exclude-standard" "--"))
- (`ls-files-ignored
- (vc-git-command (current-buffer) 'async files
- "ls-files" "-z" "-o" "-i" "--directory"
- "--no-empty-directory" "--exclude-standard" "--"))
- ;; --relative added in Git 1.5.5.
- (`diff-index
- (vc-git-command (current-buffer) 'async files
- "diff-index" "--relative" "-z" "-M" "HEAD" "--")))
- (vc-run-delayed
- (vc-git-after-dir-status-stage stage files update-function)))
+(defun vc-git-dir-status-goto-stage (git-state)
+ (let ((files (vc-git-dir-status-state->files git-state)))
+ (erase-buffer)
+ (pcase (vc-git-dir-status-state->stage git-state)
+ (`update-index
+ (if files
+ (vc-git-command (current-buffer) 'async files "add" "--refresh" "--")
+ (vc-git-command (current-buffer) 'async nil
+ "update-index" "--refresh")))
+ (`ls-files-added
+ (vc-git-command (current-buffer) 'async files
+ "ls-files" "-z" "-c" "-s" "--"))
+ (`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"
+ "--no-empty-directory" "--exclude-standard" "--"))
+ (`ls-files-ignored
+ (vc-git-command (current-buffer) 'async files
+ "ls-files" "-z" "-o" "-i" "--directory"
+ "--no-empty-directory" "--exclude-standard" "--"))
+ ;; --relative added in Git 1.5.5.
+ (`diff-index
+ (vc-git-command (current-buffer) 'async files
+ "diff-index" "--relative" "-z" "-M" "HEAD" "--")))
+ (vc-run-delayed
+ (vc-git-after-dir-status-stage git-state))))
(defun vc-git-dir-status-files (_dir files update-function)
"Return a list of (FILE STATE EXTRA) entries for DIR."
;; Further things that would have to be fixed later:
;; - how to handle unregistered directories
;; - how to support vc-dir on a subdir of the project tree
- (vc-git-dir-status-goto-stage 'update-index files update-function))
+ (vc-git-dir-status-goto-stage
+ (make-vc-git-dir-status-state :stage 'update-index
+ :files files
+ :update-function update-function)))
(defvar vc-git-stash-map
(let ((map (make-sparse-keymap)))
^ permalink raw reply related [flat|nested] 12+ messages in thread
* bug#25683: semi-working patch
2017-02-11 21:40 ` Tom Tromey
@ 2017-02-12 6:17 ` Tom Tromey
2017-02-14 1:12 ` Tom Tromey
0 siblings, 1 reply; 12+ messages in thread
From: Tom Tromey @ 2017-02-12 6:17 UTC (permalink / raw)
To: Tom Tromey; +Cc: 25683
Tom> I've implemented this idea.
Tom> Let me know what you think.
It seems that this patch regresses the case where a new file is created
and not registered. So, there's more debugging to be done.
I'd still appreciate comments on the direction.
Tom
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#25683: semi-working patch
2017-02-12 6:17 ` Tom Tromey
@ 2017-02-14 1:12 ` Tom Tromey
2017-02-14 14:03 ` Dmitry Gutov
0 siblings, 1 reply; 12+ messages in thread
From: Tom Tromey @ 2017-02-14 1:12 UTC (permalink / raw)
To: Tom Tromey; +Cc: 25683
Tom> It seems that this patch regresses the case where a new file is created
Tom> and not registered. So, there's more debugging to be done.
Tom> I'd still appreciate comments on the direction.
It was just a spot where I didn't properly update a call.
This version works.
Tom
commit 4921bfdbbd7009749e371a6ec2b76b78679e4a3d
Author: Tom Tromey <tom@tromey.com>
Date: Mon Feb 13 18:09:36 2017 -0700
Make vc-git detect conflict state for vc-dir
* lisp/vc/vc-git.el (vc-git-dir-status-state): New struct.
(vc-git-dir-status-update-file): New function.
(vc-git-after-dir-status-stage, vc-git-dir-status-goto-stage): Use
vc-git-dir-status-state; add 'ls-files-conflict state.
(vc-git-dir-status-files): Create a vc-git-dir-status-state.
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index d985cb3..713965e 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -401,11 +401,30 @@ vc-git-dir-printer
(vc-git-file-type-as-string old-perm new-perm)
(vc-git-rename-as-string state extra))))
-(defun vc-git-after-dir-status-stage (stage files update-function)
+(cl-defstruct (vc-git-dir-status-state
+ (:copier nil)
+ (:conc-name vc-git-dir-status-state->))
+ ;; Current stage.
+ stage
+ ;; List of files still to be processed.
+ files
+ ;; Update function to be called at the end.
+ update-function
+ ;; Hash table of entries for files we've computed so far.
+ (hash (make-hash-table :test 'equal)))
+
+(defsubst vc-git-dir-status-update-file (state filename file-state file-info)
+ (puthash filename (list file-state file-info)
+ (vc-git-dir-status-state->hash state))
+ (setf (vc-git-dir-status-state->files state)
+ (delete filename (vc-git-dir-status-state->files state))))
+
+(defun vc-git-after-dir-status-stage (git-state)
"Process sentinel for the various dir-status stages."
- (let (next-stage result)
+ (let (next-stage
+ (files (vc-git-dir-status-state->files git-state)))
(goto-char (point-min))
- (pcase stage
+ (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
@@ -413,29 +432,40 @@ vc-git-after-dir-status-stage
(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)))
- (push (list name 'added (vc-git-create-extra-fileinfo 0 new-perm))
- result))))
+ (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\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)))
+ (vc-git-dir-status-update-file
+ git-state name (if (equal state "0")
+ 'up-to-date
+ 'conflict)
+ (vc-git-create-extra-fileinfo perm perm)))))
+ (`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
- (vc-git-create-extra-fileinfo perm perm))
- result))))
+ (vc-git-dir-status-update-file
+ git-state name 'conflict
+ (vc-git-create-extra-fileinfo perm perm)))))
(`ls-files-unknown
(when files (setq next-stage 'ls-files-ignored))
(while (re-search-forward "\\([^\0]*?\\)\0" nil t 1)
- (push (list (match-string 1) 'unregistered
- (vc-git-create-extra-fileinfo 0 0))
- result)))
+ (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)
- (push (list (match-string 1) 'ignored
- (vc-git-create-extra-fileinfo 0 0))
- result)))
+ (vc-git-dir-status-update-file git-state (match-string 1) 'ignored
+ (vc-git-create-extra-fileinfo 0 0))))
(`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)
@@ -446,30 +476,34 @@ vc-git-after-dir-status-stage
(new-name (match-string 8)))
(if new-name ; Copy or rename.
(if (eq ?C (string-to-char state))
- (push (list new-name 'added
- (vc-git-create-extra-fileinfo old-perm new-perm
- 'copy name))
- result)
- (push (list name 'removed
- (vc-git-create-extra-fileinfo 0 0
- 'rename new-name))
- result)
- (push (list new-name 'added
- (vc-git-create-extra-fileinfo old-perm new-perm
- 'rename name))
- result))
- (push (list name (vc-git--state-code state)
- (vc-git-create-extra-fileinfo old-perm new-perm))
- result))))))
- (when result
- (setq result (nreverse result))
- (when files
- (dolist (entry result) (setq files (delete (car entry) files)))
- (unless files (setq next-stage nil))))
- (when (or result (not next-stage))
- (funcall update-function result next-stage))
- (when next-stage
- (vc-git-dir-status-goto-stage next-stage files update-function))))
+ (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 (vc-git--state-code state)
+ (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))))
;; Follows vc-git-command (or vc-do-async-command), which uses vc-do-command
;; from vc-dispatcher.
@@ -477,41 +511,48 @@ vc-git-after-dir-status-stage
;; Follows vc-exec-after.
(declare-function vc-set-async-update "vc-dispatcher" (process-buffer))
-(defun vc-git-dir-status-goto-stage (stage files update-function)
- (erase-buffer)
- (pcase stage
- (`update-index
- (if files
- (vc-git-command (current-buffer) 'async files "add" "--refresh" "--")
- (vc-git-command (current-buffer) 'async nil
- "update-index" "--refresh")))
- (`ls-files-added
- (vc-git-command (current-buffer) 'async files
- "ls-files" "-z" "-c" "-s" "--"))
- (`ls-files-up-to-date
- (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"
- "--no-empty-directory" "--exclude-standard" "--"))
- (`ls-files-ignored
- (vc-git-command (current-buffer) 'async files
- "ls-files" "-z" "-o" "-i" "--directory"
- "--no-empty-directory" "--exclude-standard" "--"))
- ;; --relative added in Git 1.5.5.
- (`diff-index
- (vc-git-command (current-buffer) 'async files
- "diff-index" "--relative" "-z" "-M" "HEAD" "--")))
- (vc-run-delayed
- (vc-git-after-dir-status-stage stage files update-function)))
+(defun vc-git-dir-status-goto-stage (git-state)
+ (let ((files (vc-git-dir-status-state->files git-state)))
+ (erase-buffer)
+ (pcase (vc-git-dir-status-state->stage git-state)
+ (`update-index
+ (if files
+ (vc-git-command (current-buffer) 'async files "add" "--refresh" "--")
+ (vc-git-command (current-buffer) 'async nil
+ "update-index" "--refresh")))
+ (`ls-files-added
+ (vc-git-command (current-buffer) 'async files
+ "ls-files" "-z" "-c" "-s" "--"))
+ (`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"
+ "--no-empty-directory" "--exclude-standard" "--"))
+ (`ls-files-ignored
+ (vc-git-command (current-buffer) 'async files
+ "ls-files" "-z" "-o" "-i" "--directory"
+ "--no-empty-directory" "--exclude-standard" "--"))
+ ;; --relative added in Git 1.5.5.
+ (`diff-index
+ (vc-git-command (current-buffer) 'async files
+ "diff-index" "--relative" "-z" "-M" "HEAD" "--")))
+ (vc-run-delayed
+ (vc-git-after-dir-status-stage git-state))))
(defun vc-git-dir-status-files (_dir files update-function)
"Return a list of (FILE STATE EXTRA) entries for DIR."
;; Further things that would have to be fixed later:
;; - how to handle unregistered directories
;; - how to support vc-dir on a subdir of the project tree
- (vc-git-dir-status-goto-stage 'update-index files update-function))
+ (vc-git-dir-status-goto-stage
+ (make-vc-git-dir-status-state :stage 'update-index
+ :files files
+ :update-function update-function)))
(defvar vc-git-stash-map
(let ((map (make-sparse-keymap)))
^ permalink raw reply related [flat|nested] 12+ messages in thread
* bug#25683: semi-working patch
2017-02-14 1:12 ` Tom Tromey
@ 2017-02-14 14:03 ` Dmitry Gutov
2017-02-14 21:05 ` Tom Tromey
0 siblings, 1 reply; 12+ messages in thread
From: Dmitry Gutov @ 2017-02-14 14:03 UTC (permalink / raw)
To: Tom Tromey; +Cc: 25683
Hey Tom,
On 14.02.2017 03:12, Tom Tromey wrote:
> It was just a spot where I didn't properly update a call.
> This version works.
This is looking good (working, too). Please feel free to install.
However, if you were looking for a more fundamental solution, switching
to parsing the output of 'git status --porcelain' should be faster and
ultimately less complex.
See vc-git-conflicted-files for the first example of its usage, and
https://debbugs.gnu.org/19343 for a related discussion.
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#25683: semi-working patch
2017-02-14 14:03 ` Dmitry Gutov
@ 2017-02-14 21:05 ` Tom Tromey
2017-02-15 0:07 ` Dmitry Gutov
0 siblings, 1 reply; 12+ messages in thread
From: Tom Tromey @ 2017-02-14 21:05 UTC (permalink / raw)
To: Dmitry Gutov; +Cc: Tom Tromey, 25683
>>>>> "Dmitry" == Dmitry Gutov <dgutov@yandex.ru> writes:
Dmitry> This is looking good (working, too). Please feel free to install.
Thanks!
Dmitry> However, if you were looking for a more fundamental solution,
Dmitry> switching to parsing the output of 'git status --porcelain' should be
Dmitry> faster and ultimately less complex.
I had looked at this a bit but I didn't see how get the permissions info
out of git status --porcelain; and then I found the bug you refer to and
it seemed like it was being dealt with by someone else already; and/or
maybe waiting until --porcelain was considered "old enough"?
Tom
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#25683: semi-working patch
2017-02-14 21:05 ` Tom Tromey
@ 2017-02-15 0:07 ` Dmitry Gutov
2017-02-15 4:17 ` Tom Tromey
0 siblings, 1 reply; 12+ messages in thread
From: Dmitry Gutov @ 2017-02-15 0:07 UTC (permalink / raw)
To: Tom Tromey; +Cc: 25683
On 14.02.2017 23:05, Tom Tromey wrote:
> I had looked at this a bit but I didn't see how get the permissions info
> out of git status --porcelain;
Good objection, and I don't know (this info might be in the porcelain=v2
format, but it was only added in Git 2.12 last year).
If we could fetch that data using just one extra call, that would be
great, though.
> and then I found the bug you refer to and
> it seemed like it was being dealt with by someone else already;
Someone else is yours truly, so not sure when that happens.
> and/or
> maybe waiting until --porcelain was considered "old enough"?
No, --porcelain is old enough, aside from the problem you mentioned. We
discussed the --ignored flag which still is "too new", but that's a
minor problem, only tangentially related.
Anyway, thanks for the fix! --porcelain can wait some more.
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#25683: semi-working patch
2017-02-15 0:07 ` Dmitry Gutov
@ 2017-02-15 4:17 ` Tom Tromey
2017-02-15 13:42 ` Dmitry Gutov
2017-05-01 14:33 ` Dmitry Gutov
0 siblings, 2 replies; 12+ messages in thread
From: Tom Tromey @ 2017-02-15 4:17 UTC (permalink / raw)
To: Dmitry Gutov; +Cc: Tom Tromey, 25683
Dmitry> Someone else is yours truly, so not sure when that happens.
Oops, sorry about that. I didn't read the bug very closely it seems...
Dmitry> Anyway, thanks for the fix! --porcelain can wait some more.
It's on my wish-list, but after a bunch of other things.
I think I look at the per-file state very rarely if at all;
whereas vc-dir is one of my main views when working on a project.
Tom
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#25683: done
2017-02-10 22:15 bug#25683: 25.1.91; vc-dir shows conflicted files as "edited" Tom Tromey
[not found] ` <handler.25683.B.148676496228355.ack@debbugs.gnu.org>
@ 2017-02-15 4:18 ` Tom Tromey
1 sibling, 0 replies; 12+ messages in thread
From: Tom Tromey @ 2017-02-15 4:18 UTC (permalink / raw)
To: 25683-done
Fix checked in.
Tom
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#25683: semi-working patch
2017-02-15 4:17 ` Tom Tromey
@ 2017-02-15 13:42 ` Dmitry Gutov
2017-05-01 14:33 ` Dmitry Gutov
1 sibling, 0 replies; 12+ messages in thread
From: Dmitry Gutov @ 2017-02-15 13:42 UTC (permalink / raw)
To: Tom Tromey; +Cc: 25683
On 15.02.2017 06:17, Tom Tromey wrote:
> It's on my wish-list, but after a bunch of other things.
Thanks.
> I think I look at the per-file state very rarely if at all;
> whereas vc-dir is one of my main views when working on a project.
Per-file state also affects the vc-dir view as well (that is the exact
situation in bug#19343). But I was only suggesting you reimplement
vc-git-dir-status-files based on 'git status --porcelain'.
The fact that reusing the resulting code in vc-git-status would be very
easy is just the icing. ;)
Anyway, the file permissions question complicates the issue.
^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#25683: semi-working patch
2017-02-15 4:17 ` Tom Tromey
2017-02-15 13:42 ` Dmitry Gutov
@ 2017-05-01 14:33 ` Dmitry Gutov
1 sibling, 0 replies; 12+ messages in thread
From: Dmitry Gutov @ 2017-05-01 14:33 UTC (permalink / raw)
To: Tom Tromey; +Cc: 25683
Hey Tom,
On 15.02.2017 6:17, Tom Tromey wrote:
> Dmitry> Anyway, thanks for the fix! --porcelain can wait some more.
>
> It's on my wish-list, but after a bunch of other things.
> I think I look at the per-file state very rarely if at all;
> whereas vc-dir is one of my main views when working on a project.
'git status --porcelain' for vc-git-state is now in. Did you have any
new ideas about getting the file permissions?
I have recently noticed that your patch makes vc-dir-status-files slower.
E.g., in Emacs's own repository checkout, a refresh took a fraction of a
second before 3fb9f5452fbd0458f90115b0a95151b8e7a482a1, and about 3
seconds now.
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2017-05-01 14:33 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-02-10 22:15 bug#25683: 25.1.91; vc-dir shows conflicted files as "edited" Tom Tromey
[not found] ` <handler.25683.B.148676496228355.ack@debbugs.gnu.org>
2017-02-11 20:45 ` bug#25683: semi-working patch Tom Tromey
2017-02-11 21:40 ` Tom Tromey
2017-02-12 6:17 ` Tom Tromey
2017-02-14 1:12 ` Tom Tromey
2017-02-14 14:03 ` Dmitry Gutov
2017-02-14 21:05 ` Tom Tromey
2017-02-15 0:07 ` Dmitry Gutov
2017-02-15 4:17 ` Tom Tromey
2017-02-15 13:42 ` Dmitry Gutov
2017-05-01 14:33 ` Dmitry Gutov
2017-02-15 4:18 ` bug#25683: done Tom Tromey
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).