From 36d2078ff19c849aef94f045bf2b4fb73a5098e8 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sat, 1 Nov 2008 20:34:33 +0100 Subject: git.el: Improve error handling for commits. Display all errors happening in the various subcommands of the commit sequence, and abort on any error. Signed-off-by: Alexandre Julliard --- contrib/emacs/git.el | 46 +++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el index c1cf1cbcc..d357b543e 100644 --- a/contrib/emacs/git.el +++ b/contrib/emacs/git.el @@ -208,6 +208,15 @@ and returns the process output as a string, or nil if the git failed." (and (eq 0 (apply #' git-call-process-env t env args)) (buffer-string)))) +(defun git-call-process-string-display-error (&rest args) + "Wrapper for call-process that displays error message and returns +the process output as a string, or nil if the git command failed." + (with-temp-buffer + (if (eq 0 (apply #'git-call-process-env (list t t) nil args)) + (buffer-string) + (display-message-or-buffer (current-buffer)) + nil))) + (defun git-run-process-region (buffer start end program args) "Run a git process with a buffer region as input." (let ((output-buffer (current-buffer)) @@ -391,14 +400,16 @@ and returns the process output as a string, or nil if the git failed." (defun git-read-tree (tree &optional index-file) "Read a tree into the index file." - (apply #'git-call-process-env nil - (if index-file `(("GIT_INDEX_FILE" . ,index-file)) nil) - "read-tree" (if tree (list tree)))) + (let ((process-environment + (append (and index-file (list (concat "GIT_INDEX_FILE=" index-file))) process-environment))) + (apply 'git-call-process-display-error "read-tree" (if tree (list tree))))) (defun git-write-tree (&optional index-file) "Call git-write-tree and return the resulting tree SHA1 as a string." - (git-get-string-sha1 - (git-call-process-env-string (and index-file `(("GIT_INDEX_FILE" . ,index-file))) "write-tree"))) + (let ((process-environment + (append (and index-file (list (concat "GIT_INDEX_FILE=" index-file))) process-environment))) + (git-get-string-sha1 + (git-call-process-string-display-error "write-tree")))) (defun git-commit-tree (buffer tree head) "Call git-commit-tree with buffer as input and return the resulting commit SHA1." @@ -824,19 +835,18 @@ Return the list of files that haven't been handled." (defun git-update-index (index-file files) "Run git-update-index on a list of files." - (let ((env (and index-file `(("GIT_INDEX_FILE" . ,index-file)))) + (let ((process-environment (append (and index-file (list (concat "GIT_INDEX_FILE=" index-file))) + process-environment)) added deleted modified) (dolist (info files) (case (git-fileinfo->state info) ('added (push info added)) ('deleted (push info deleted)) ('modified (push info modified)))) - (when added - (apply #'git-call-process-env nil env "update-index" "--add" "--" (git-get-filenames added))) - (when deleted - (apply #'git-call-process-env nil env "update-index" "--remove" "--" (git-get-filenames deleted))) - (when modified - (apply #'git-call-process-env nil env "update-index" "--" (git-get-filenames modified))))) + (and + (or (not added) (apply #'git-call-process-display-error "update-index" "--add" "--" (git-get-filenames added))) + (or (not deleted) (apply #'git-call-process-display-error "update-index" "--remove" "--" (git-get-filenames deleted))) + (or (not modified) (apply #'git-call-process-display-error "update-index" "--" (git-get-filenames modified)))))) (defun git-run-pre-commit-hook () "Run the pre-commit hook if any." @@ -862,17 +872,19 @@ Return the list of files that haven't been handled." (message "You cannot commit unmerged files, resolve them first.") (unwind-protect (let ((files (git-marked-files-state 'added 'deleted 'modified)) - head head-tree) + head tree head-tree) (unless (git-empty-db-p) (setq head (git-rev-parse "HEAD") head-tree (git-rev-parse "HEAD^{tree}"))) (if files (progn (message "Running git commit...") - (git-read-tree head-tree index-file) - (git-update-index nil files) ;update both the default index - (git-update-index index-file files) ;and the temporary one - (let ((tree (git-write-tree index-file))) + (when + (and + (git-read-tree head-tree index-file) + (git-update-index nil files) ;update both the default index + (git-update-index index-file files) ;and the temporary one + (setq tree (git-write-tree index-file))) (if (or (not (string-equal tree head-tree)) (yes-or-no-p "The tree was not modified, do you really want to perform an empty commit? ")) (let ((commit (git-commit-tree buffer tree head))) -- cgit v1.2.1 From 9ddf6d7c105e58d76ea6762d8cc8eebdf463903e Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sat, 1 Nov 2008 20:42:39 +0100 Subject: git.el: Remove the env parameter in git-call-process and git-call-process-string. All callers that need to change the environment now set process-environment themselves. Signed-off-by: Alexandre Julliard --- contrib/emacs/git.el | 54 +++++++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el index d357b543e..d28b45e55 100644 --- a/contrib/emacs/git.el +++ b/contrib/emacs/git.el @@ -183,11 +183,9 @@ if there is already one that displays the same directory." "Build a list of NAME=VALUE strings from a list of environment strings." (mapcar (lambda (entry) (concat (car entry) "=" (cdr entry))) env)) -(defun git-call-process-env (buffer env &rest args) +(defun git-call-process (buffer &rest args) "Wrapper for call-process that sets environment strings." - (let ((process-environment (append (git-get-env-strings env) - process-environment))) - (apply #'call-process "git" nil buffer nil args))) + (apply #'call-process "git" nil buffer nil args)) (defun git-call-process-display-error (&rest args) "Wrapper for call-process that displays error messages." @@ -197,22 +195,22 @@ if there is already one that displays the same directory." (let ((default-directory dir) (buffer-read-only nil)) (erase-buffer) - (eq 0 (apply 'call-process "git" nil (list buffer t) nil args)))))) + (eq 0 (apply #'git-call-process (list buffer t) args)))))) (unless ok (display-message-or-buffer buffer)) ok)) -(defun git-call-process-env-string (env &rest args) - "Wrapper for call-process that sets environment strings, -and returns the process output as a string, or nil if the git failed." +(defun git-call-process-string (&rest args) + "Wrapper for call-process that returns the process output as a string, +or nil if the git command failed." (with-temp-buffer - (and (eq 0 (apply #' git-call-process-env t env args)) + (and (eq 0 (apply #'git-call-process t args)) (buffer-string)))) (defun git-call-process-string-display-error (&rest args) "Wrapper for call-process that displays error message and returns the process output as a string, or nil if the git command failed." (with-temp-buffer - (if (eq 0 (apply #'git-call-process-env (list t t) nil args)) + (if (eq 0 (apply #'git-call-process (list t t) args)) (buffer-string) (display-message-or-buffer (current-buffer)) nil))) @@ -235,7 +233,7 @@ the process output as a string, or nil if the git command failed." (let ((default-directory dir) (buffer-read-only nil)) (erase-buffer) - (apply #'git-call-process-env buffer nil args))) + (apply #'git-call-process buffer args))) (message "Running git %s...done" (car args)) buffer)) @@ -336,7 +334,7 @@ the process output as a string, or nil if the git command failed." (let ((cdup (with-output-to-string (with-current-buffer standard-output (cd dir) - (unless (eq 0 (call-process "git" nil t nil "rev-parse" "--show-cdup")) + (unless (eq 0 (git-call-process t "rev-parse" "--show-cdup")) (error "cannot find top-level git tree for %s." dir)))))) (expand-file-name (concat (file-name-as-directory dir) (car (split-string cdup "\n")))))) @@ -357,7 +355,7 @@ the process output as a string, or nil if the git command failed." (sort-lines nil (point-min) (point-max)) (save-buffer)) (when created - (git-call-process-env nil nil "update-index" "--add" "--" (file-relative-name ignore-name))) + (git-call-process nil "update-index" "--add" "--" (file-relative-name ignore-name))) (git-update-status-files (list (file-relative-name ignore-name)) 'unknown))) ; propertize definition for XEmacs, stolen from erc-compat @@ -376,16 +374,16 @@ the process output as a string, or nil if the git command failed." (defun git-rev-parse (rev) "Parse a revision name and return its SHA1." (git-get-string-sha1 - (git-call-process-env-string nil "rev-parse" rev))) + (git-call-process-string "rev-parse" rev))) (defun git-config (key) "Retrieve the value associated to KEY in the git repository config file." - (let ((str (git-call-process-env-string nil "config" key))) + (let ((str (git-call-process-string "config" key))) (and str (car (split-string str "\n"))))) (defun git-symbolic-ref (ref) "Wrapper for the git-symbolic-ref command." - (let ((str (git-call-process-env-string nil "symbolic-ref" ref))) + (let ((str (git-call-process-string "symbolic-ref" ref))) (and str (car (split-string str "\n"))))) (defun git-update-ref (ref newval &optional oldval reason) @@ -463,7 +461,7 @@ the process output as a string, or nil if the git command failed." (defun git-empty-db-p () "Check if the git db is empty (no commit done yet)." - (not (eq 0 (call-process "git" nil nil nil "rev-parse" "--verify" "HEAD")))) + (not (eq 0 (git-call-process nil "rev-parse" "--verify" "HEAD")))) (defun git-get-merge-heads () "Retrieve the merge heads from the MERGE_HEAD file if present." @@ -479,7 +477,7 @@ the process output as a string, or nil if the git command failed." (defun git-get-commit-description (commit) "Get a one-line description of COMMIT." (let ((coding-system-for-read (git-get-logoutput-coding-system))) - (let ((descr (git-call-process-env-string nil "log" "--max-count=1" "--pretty=oneline" commit))) + (let ((descr (git-call-process-string "log" "--max-count=1" "--pretty=oneline" commit))) (if (and descr (string-match "\\`\\([0-9a-f]\\{40\\}\\) *\\(.*\\)$" descr)) (concat (substring (match-string 1 descr) 0 10) " - " (match-string 2 descr)) descr)))) @@ -655,7 +653,7 @@ Return the list of files that haven't been handled." (let ((remaining (copy-sequence files)) infolist) (with-temp-buffer - (apply #'git-call-process-env t nil "diff-index" "-z" "-M" "HEAD" "--" files) + (apply #'git-call-process t "diff-index" "-z" "-M" "HEAD" "--" files) (goto-char (point-min)) (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" @@ -688,7 +686,7 @@ Return the list of files that haven't been handled." Return the list of files that haven't been handled." (let (infolist) (with-temp-buffer - (apply #'git-call-process-env t nil "ls-files" "-z" (append options (list "--") files)) + (apply #'git-call-process t "ls-files" "-z" (append options (list "--") files)) (goto-char (point-min)) (while (re-search-forward "\\([^\0]*?\\)\\(/?\\)\0" nil t 1) (let ((name (match-string 1))) @@ -705,7 +703,7 @@ Return the list of files that haven't been handled." (let ((remaining (copy-sequence files)) infolist) (with-temp-buffer - (apply #'git-call-process-env t nil "ls-files" "-z" "-s" "-c" "--" files) + (apply #'git-call-process t "ls-files" "-z" "-s" "-c" "--" files) (goto-char (point-min)) (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)) @@ -719,7 +717,7 @@ Return the list of files that haven't been handled." (defun git-run-ls-unmerged (status files) "Run git-ls-files -u on FILES and parse the results into STATUS." (with-temp-buffer - (apply #'git-call-process-env t nil "ls-files" "-z" "-u" "--" files) + (apply #'git-call-process t "ls-files" "-z" "-u" "--" files) (goto-char (point-min)) (let (unmerged-files) (while (re-search-forward "[0-7]\\{6\\} [0-9a-f]\\{40\\} [123]\t\\([^\0]+\\)\0" nil t) @@ -893,8 +891,8 @@ Return the list of files that haven't been handled." (condition-case nil (delete-file ".git/MERGE_MSG") (error nil)) (with-current-buffer buffer (erase-buffer)) (git-update-status-files (git-get-filenames files) 'uptodate) - (git-call-process-env nil nil "rerere") - (git-call-process-env nil nil "gc" "--auto") + (git-call-process nil "rerere") + (git-call-process nil "gc" "--auto") (git-refresh-files) (git-refresh-ewoc-hf git-status) (message "Committed %s." commit) @@ -1311,7 +1309,7 @@ Return the list of files that haven't been handled." (let (author-name author-email subject date msg) (with-temp-buffer (let ((coding-system (git-get-logoutput-coding-system))) - (git-call-process-env t nil "log" "-1" "--pretty=medium" commit) + (git-call-process t "log" "-1" "--pretty=medium" commit) (goto-char (point-min)) (when (re-search-forward "^Author: *\\(.*\\) <\\(.*\\)>$" nil t) (setq author-name (match-string 1)) @@ -1331,7 +1329,7 @@ Return the list of files that haven't been handled." "Retrieve the list of files modified by COMMIT." (let (files) (with-temp-buffer - (git-call-process-env t nil "diff-tree" "-r" "-z" "--name-only" "--no-commit-id" commit) + (git-call-process t "diff-tree" "-r" "-z" "--name-only" "--no-commit-id" commit) (goto-char (point-min)) (while (re-search-forward "\\([^\0]*\\)\0" nil t 1) (push (match-string 1) files))) @@ -1395,7 +1393,7 @@ amended version of it." (cur-name (and pos (git-fileinfo->name (ewoc-data pos))))) (unless status (error "Not in git-status buffer.")) (message "Refreshing git status...") - (git-call-process-env nil nil "update-index" "--refresh") + (git-call-process nil "update-index" "--refresh") (git-clear-status status) (git-update-status-files nil) ; restore file marks @@ -1588,7 +1586,7 @@ Meant to be used in `after-save-hook'." (let ((filename (file-relative-name file dir))) ; skip files located inside the .git directory (unless (string-match "^\\.git/" filename) - (git-call-process-env nil nil "add" "--refresh" "--" filename) + (git-call-process nil "add" "--refresh" "--" filename) (git-update-status-files (list filename) 'uptodate))))))) (defun git-help () -- cgit v1.2.1 From 6fb204266cc985284b554e9f9f1894ec8360b2f5 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sat, 2 Aug 2008 18:04:31 +0200 Subject: git.el: Simplify handling of merge heads in the commit log-edit buffer. Use a single Merge: header instead of one Parent: header for each parent, and don't list the current HEAD as a merged head. Support symbolic references too. Signed-off-by: Alexandre Julliard --- contrib/emacs/git.el | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el index d28b45e55..53ada39b4 100644 --- a/contrib/emacs/git.el +++ b/contrib/emacs/git.el @@ -173,7 +173,7 @@ if there is already one that displays the same directory." (defconst git-log-msg-separator "--- log message follows this line ---") (defvar git-log-edit-font-lock-keywords - `(("^\\(Author:\\|Date:\\|Parent:\\|Signed-off-by:\\)\\(.*\\)$" + `(("^\\(Author:\\|Date:\\|Merge:\\|Signed-off-by:\\)\\(.*\\)$" (1 font-lock-keyword-face) (2 font-lock-function-name-face)) (,(concat "^\\(" (regexp-quote git-log-msg-separator) "\\)$") @@ -433,11 +433,11 @@ the process output as a string, or nil if the git command failed." (when (re-search-forward "^Date: +\\(.*\\)$" nil t) (setq author-date (match-string 1))) (goto-char (point-min)) - (while (re-search-forward "^Parent: +\\([0-9a-f]+\\)" nil t) - (unless (string-equal head (match-string 1)) - (setq subject "commit (merge): ") + (when (re-search-forward "^Merge: +\\(.*\\)" nil t) + (setq subject "commit (merge): ") + (dolist (parent (split-string (match-string 1) " +" t)) (push "-p" args) - (push (match-string 1) args)))) + (push parent args)))) (setq log-start (point-min))) (setq log-end (point-max)) (goto-char log-start) @@ -1253,9 +1253,8 @@ Return the list of files that haven't been handled." (or author-email committer-email) (if date (format "Date: %s\n" date) "") (if merge-heads - (format "Parent: %s\n%s\n" - (git-rev-parse "HEAD") - (mapconcat (lambda (str) (concat "Parent: " str)) merge-heads "\n")) + (format "Merge: %s\n" + (mapconcat 'identity merge-heads " ")) "")) 'face 'git-header-face) (propertize git-log-msg-separator 'face 'git-separator-face) -- cgit v1.2.1 From ef5133df7c9d0304ce2fc437abc74c220f49dabd Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sat, 2 Aug 2008 18:05:58 +0200 Subject: git.el: Properly handle merge commits in git-amend-commit. Signed-off-by: Alexandre Julliard --- contrib/emacs/git.el | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el index 53ada39b4..207ff0ba2 100644 --- a/contrib/emacs/git.el +++ b/contrib/emacs/git.el @@ -1235,11 +1235,10 @@ Return the list of files that haven't been handled." (goto-char (point-max)) (insert sign-off "\n")))) -(defun git-setup-log-buffer (buffer &optional author-name author-email subject date msg) +(defun git-setup-log-buffer (buffer &optional merge-heads author-name author-email subject date msg) "Setup the log buffer for a commit." (unless git-status (error "Not in git-status buffer.")) - (let ((merge-heads (git-get-merge-heads)) - (dir default-directory) + (let ((dir default-directory) (committer-name (git-get-committer-name)) (committer-email (git-get-committer-email)) (sign-off git-append-signed-off-by)) @@ -1294,7 +1293,7 @@ Return the list of files that haven't been handled." (goto-char (point-min)) (when (re-search-forward "^Date: \\(.*\\)$" nil t) (setq date (match-string 1))))) - (git-setup-log-buffer buffer author-name author-email subject date)) + (git-setup-log-buffer buffer (git-get-merge-heads) author-name author-email subject date)) (if (boundp 'log-edit-diff-function) (log-edit 'git-do-commit nil '((log-edit-listfun . git-log-edit-files) (log-edit-diff-function . git-log-edit-diff)) buffer) @@ -1305,11 +1304,13 @@ Return the list of files that haven't been handled." (defun git-setup-commit-buffer (commit) "Setup the commit buffer with the contents of COMMIT." - (let (author-name author-email subject date msg) + (let (parents author-name author-email subject date msg) (with-temp-buffer (let ((coding-system (git-get-logoutput-coding-system))) - (git-call-process t "log" "-1" "--pretty=medium" commit) + (git-call-process t "log" "-1" "--pretty=medium" "--abbrev=40" commit) (goto-char (point-min)) + (when (re-search-forward "^Merge: *\\(.*\\)$" nil t) + (setq parents (cdr (split-string (match-string 1) " +")))) (when (re-search-forward "^Author: *\\(.*\\) <\\(.*\\)>$" nil t) (setq author-name (match-string 1)) (setq author-email (match-string 2))) @@ -1321,14 +1322,14 @@ Return the list of files that haven't been handled." (setq subject (pop msg)) (while (and msg (zerop (length (car msg))) (pop msg))))) (git-setup-log-buffer (get-buffer-create "*git-commit*") - author-name author-email subject date + parents author-name author-email subject date (mapconcat #'identity msg "\n")))) (defun git-get-commit-files (commit) "Retrieve the list of files modified by COMMIT." (let (files) (with-temp-buffer - (git-call-process t "diff-tree" "-r" "-z" "--name-only" "--no-commit-id" commit) + (git-call-process t "diff-tree" "-m" "-r" "-z" "--name-only" "--no-commit-id" commit) (goto-char (point-min)) (while (re-search-forward "\\([^\0]*\\)\0" nil t 1) (push (match-string 1) files))) -- cgit v1.2.1 From db18a182a28f254fa514179dcd49ceb3d95cd9d8 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sat, 2 Aug 2008 20:35:20 +0200 Subject: git.el: Fix git-amend-commit to support amending an initial commit. Signed-off-by: Alexandre Julliard --- contrib/emacs/git.el | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el index 207ff0ba2..2dd97eeb5 100644 --- a/contrib/emacs/git.el +++ b/contrib/emacs/git.el @@ -389,11 +389,12 @@ the process output as a string, or nil if the git command failed." (defun git-update-ref (ref newval &optional oldval reason) "Update a reference by calling git-update-ref." (let ((args (and oldval (list oldval)))) - (push newval args) + (when newval (push newval args)) (push ref args) (when reason (push reason args) (push "-m" args)) + (unless newval (push "-d" args)) (apply 'git-call-process-display-error "update-ref" args))) (defun git-read-tree (tree &optional index-file) @@ -1329,7 +1330,7 @@ Return the list of files that haven't been handled." "Retrieve the list of files modified by COMMIT." (let (files) (with-temp-buffer - (git-call-process t "diff-tree" "-m" "-r" "-z" "--name-only" "--no-commit-id" commit) + (git-call-process t "diff-tree" "-m" "-r" "-z" "--name-only" "--no-commit-id" "--root" commit) (goto-char (point-min)) (while (re-search-forward "\\([^\0]*\\)\0" nil t 1) (push (match-string 1) files))) @@ -1343,7 +1344,10 @@ amended version of it." (when (git-empty-db-p) (error "No commit to amend.")) (let* ((commit (git-rev-parse "HEAD")) (files (git-get-commit-files commit))) - (when (git-call-process-display-error "reset" "--soft" "HEAD^") + (when (if (git-rev-parse "HEAD^") + (git-call-process-display-error "reset" "--soft" "HEAD^") + (and (git-update-ref "ORIG_HEAD" commit) + (git-update-ref "HEAD" nil commit))) (git-update-status-files (copy-sequence files) 'uptodate) (git-mark-files git-status files) (git-refresh-files) -- cgit v1.2.1 From 433ee03f9748a8a5d0e0495bbf4b054ae922103b Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sat, 2 Aug 2008 20:35:52 +0200 Subject: 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 --- contrib/emacs/git.el | 169 ++++++++++++++++++++++++++------------------------- 1 file changed, 85 insertions(+), 84 deletions(-) diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el index 2dd97eeb5..67c527599 100644 --- a/contrib/emacs/git.el +++ b/contrib/emacs/git.el @@ -356,7 +356,7 @@ the process output as a string, or nil if the git command failed." (save-buffer)) (when created (git-call-process nil "update-index" "--add" "--" (file-relative-name ignore-name))) - (git-update-status-files (list (file-relative-name ignore-name)) 'unknown))) + (git-update-status-files (list (file-relative-name ignore-name))))) ; propertize definition for XEmacs, stolen from erc-compat (eval-when-compile @@ -497,14 +497,11 @@ the process output as a string, or nil if the git command failed." old-perm new-perm ;; permission flags rename-state ;; rename or copy state orig-name ;; original name for renames or copies + needs-update ;; whether file needs to be updated needs-refresh) ;; whether file needs to be refreshed (defvar git-status nil) -(defun git-clear-status (status) - "Remove everything from the status list." - (ewoc-filter status (lambda (info) nil))) - (defun git-set-fileinfo-state (info state) "Set the state of a file info." (unless (eq (git-fileinfo->state info) state) @@ -512,6 +509,7 @@ the process output as a string, or nil if the git command failed." (git-fileinfo->new-perm info) (git-fileinfo->old-perm info) (git-fileinfo->rename-state info) nil (git-fileinfo->orig-name info) nil + (git-fileinfo->needs-update info) nil (git-fileinfo->needs-refresh info) t))) (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." (let ((file (pop files)) (node (ewoc-nth status 0))) (while (and file node) - (let ((info (ewoc-data node))) - (if (string-lessp (git-fileinfo->name info) file) + (let* ((info (ewoc-data node)) + (name (git-fileinfo->name info))) + (if (string-lessp name file) (setq node (ewoc-next status node)) - (if (string-equal (git-fileinfo->name info) file) + (if (string-equal name file) (apply func info args)) (setq file (pop files)))))))) @@ -622,37 +621,50 @@ the process output as a string, or nil if the git command failed." (git-file-type-as-string old-perm new-perm) (git-rename-as-string info))))) -(defun git-insert-info-list (status infolist) - "Insert a list of file infos in the status buffer, replacing existing ones if any." - (setq infolist (sort infolist - (lambda (info1 info2) - (string-lessp (git-fileinfo->name info1) - (git-fileinfo->name info2))))) - (let ((info (pop infolist)) - (node (ewoc-nth status 0))) +(defun git-update-node-fileinfo (node info) + "Update the fileinfo of the specified node. The names are assumed to match already." + (let ((data (ewoc-data node))) + (setf + ;; preserve the marked flag + (git-fileinfo->marked info) (git-fileinfo->marked data) + (git-fileinfo->needs-update data) nil) + (when (not (equal info data)) + (setf (git-fileinfo->needs-refresh info) t + (ewoc-data node) info)))) + +(defun git-insert-info-list (status infolist files) + "Insert a sorted list of file infos in the status buffer, replacing existing ones if any." + (let* ((info (pop infolist)) + (node (ewoc-nth status 0)) + (name (and info (git-fileinfo->name info))) + remaining) (while info - (cond ((not node) - (setq node (ewoc-enter-last status info)) - (setq info (pop infolist))) - ((string-lessp (git-fileinfo->name (ewoc-data node)) - (git-fileinfo->name info)) - (setq node (ewoc-next status node))) - ((string-equal (git-fileinfo->name (ewoc-data node)) - (git-fileinfo->name info)) - ;; preserve the marked flag - (setf (git-fileinfo->marked info) (git-fileinfo->marked (ewoc-data node))) - (setf (git-fileinfo->needs-refresh info) t) - (setf (ewoc-data node) info) - (setq info (pop infolist))) - (t - (setq node (ewoc-enter-before status node info)) - (setq info (pop infolist))))))) + (let ((nodename (and node (git-fileinfo->name (ewoc-data node))))) + (while (and files (string-lessp (car files) name)) + (push (pop files) remaining)) + (when (and files (string-equal (car files) name)) + (setq files (cdr files))) + (cond ((not nodename) + (setq node (ewoc-enter-last status info)) + (setq info (pop infolist)) + (setq name (and info (git-fileinfo->name info)))) + ((string-lessp nodename name) + (setq node (ewoc-next status node))) + ((string-equal nodename name) + ;; preserve the marked flag + (git-update-node-fileinfo node info) + (setq info (pop infolist)) + (setq name (and info (git-fileinfo->name info)))) + (t + (setq node (ewoc-enter-before status node info)) + (setq info (pop infolist)) + (setq name (and info (git-fileinfo->name info))))))) + (nconc (nreverse remaining) files))) (defun git-run-diff-index (status files) "Run git-diff-index on FILES and parse the results into STATUS. Return the list of files that haven't been handled." - (let ((remaining (copy-sequence files)) - infolist) + (let (infolist) (with-temp-buffer (apply #'git-call-process t "diff-index" "-z" "-M" "HEAD" "--" files) (goto-char (point-min)) @@ -669,11 +681,12 @@ Return the list of files that haven't been handled." (push (git-create-fileinfo 'added new-name old-perm new-perm 'copy name) infolist) (push (git-create-fileinfo 'deleted name 0 0 'rename new-name) infolist) (push (git-create-fileinfo 'added new-name old-perm new-perm 'rename name) infolist)) - (push (git-create-fileinfo (git-state-code state) name old-perm new-perm) infolist)) - (setq remaining (delete name remaining)) - (when new-name (setq remaining (delete new-name remaining)))))) - (git-insert-info-list status infolist) - remaining)) + (push (git-create-fileinfo (git-state-code state) name old-perm new-perm) infolist))))) + (setq infolist (sort (nreverse infolist) + (lambda (info1 info2) + (string-lessp (git-fileinfo->name info1) + (git-fileinfo->name info2))))) + (git-insert-info-list status infolist files))) (defun git-find-status-file (status file) "Find a given file in the status ewoc and return its node." @@ -693,16 +706,14 @@ Return the list of files that haven't been handled." (let ((name (match-string 1))) (push (git-create-fileinfo default-state name 0 (if (string-equal "/" (match-string 2)) (lsh ?\110 9) 0)) - infolist) - (setq files (delete name files))))) - (git-insert-info-list status infolist) - files)) + infolist)))) + (setq infolist (nreverse infolist)) ;; assume it is sorted already + (git-insert-info-list status infolist files))) (defun git-run-ls-files-cached (status files default-state) "Run git-ls-files -c on FILES and parse the results into STATUS. Return the list of files that haven't been handled." - (let ((remaining (copy-sequence files)) - infolist) + (let (infolist) (with-temp-buffer (apply #'git-call-process t "ls-files" "-z" "-s" "-c" "--" files) (goto-char (point-min)) @@ -710,10 +721,9 @@ Return the list of files that haven't been handled." (let* ((new-perm (string-to-number (match-string 1) 8)) (old-perm (if (eq default-state 'added) 0 new-perm)) (name (match-string 2))) - (push (git-create-fileinfo default-state name old-perm new-perm) infolist) - (setq remaining (delete name remaining))))) - (git-insert-info-list status infolist) - remaining)) + (push (git-create-fileinfo default-state name old-perm new-perm) infolist)))) + (setq infolist (nreverse infolist)) ;; assume it is sorted already + (git-insert-info-list status infolist files))) (defun git-run-ls-unmerged (status files) "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." (concat "--exclude-per-directory=" git-per-dir-ignore-file) (append options (mapcar (lambda (f) (concat "--exclude-from=" f)) exclude-files))))) -(defun git-update-status-files (files &optional default-state) +(defun git-update-status-files (&optional files) "Update the status of FILES from the index." (unless git-status (error "Not in git-status buffer.")) - (when (or git-show-uptodate files) - (git-run-ls-files-cached git-status files 'uptodate)) + ;; set the needs-update flag on existing files + (if (setq files (sort files #'string-lessp)) + (git-status-filenames-map + git-status (lambda (info) (setf (git-fileinfo->needs-update info) t)) files) + (ewoc-map (lambda (info) (setf (git-fileinfo->needs-update info) t) nil) git-status) + (git-call-process nil "update-index" "--refresh") + (when git-show-uptodate + (git-run-ls-files-cached git-status nil 'uptodate))) (let* ((remaining-files (if (git-empty-db-p) ; we need some special handling for an empty db (git-run-ls-files-cached git-status files 'added) @@ -756,7 +772,11 @@ Return the list of files that haven't been handled." (setq remaining-files (git-run-ls-files-with-excludes git-status remaining-files 'unknown "-o"))) (when (or remaining-files (and git-show-ignored (not files))) (setq remaining-files (git-run-ls-files-with-excludes git-status remaining-files 'ignored "-o" "-i"))) - (git-set-filenames-state git-status remaining-files default-state) + (unless files + (setq remaining-files (git-get-filenames (ewoc-collect git-status #'git-fileinfo->needs-update)))) + (when remaining-files + (setq remaining-files (git-run-ls-files-cached git-status remaining-files 'uptodate))) + (git-set-filenames-state git-status remaining-files nil) (git-refresh-files) (git-refresh-ewoc-hf git-status))) @@ -891,11 +911,9 @@ Return the list of files that haven't been handled." (condition-case nil (delete-file ".git/MERGE_HEAD") (error nil)) (condition-case nil (delete-file ".git/MERGE_MSG") (error nil)) (with-current-buffer buffer (erase-buffer)) - (git-update-status-files (git-get-filenames files) 'uptodate) + (git-update-status-files (git-get-filenames files)) (git-call-process nil "rerere") (git-call-process nil "gc" "--auto") - (git-refresh-files) - (git-refresh-ewoc-hf git-status) (message "Committed %s." commit) (git-run-hook "post-commit" nil))) (message "Commit aborted.")))) @@ -1009,7 +1027,7 @@ Return the list of files that haven't been handled." (unless files (push (file-relative-name (read-file-name "File to add: " nil nil t)) files)) (when (apply 'git-call-process-display-error "update-index" "--add" "--" files) - (git-update-status-files files 'uptodate) + (git-update-status-files files) (git-success-message "Added" files)))) (defun git-ignore-file () @@ -1019,7 +1037,7 @@ Return the list of files that haven't been handled." (unless files (push (file-relative-name (read-file-name "File to ignore: " nil nil t)) files)) (dolist (f files) (git-append-to-ignore f)) - (git-update-status-files files 'ignored) + (git-update-status-files files) (git-success-message "Ignored" files))) (defun git-remove-file () @@ -1037,7 +1055,7 @@ Return the list of files that haven't been handled." (delete-directory name) (delete-file name)))) (when (apply 'git-call-process-display-error "update-index" "--remove" "--" files) - (git-update-status-files files nil) + (git-update-status-files files) (git-success-message "Removed" files))) (message "Aborting")))) @@ -1065,7 +1083,7 @@ Return the list of files that haven't been handled." (apply 'git-call-process-display-error "update-index" "--force-remove" "--" added)) (or (not modified) (apply 'git-call-process-display-error "checkout" "HEAD" modified))))) - (git-update-status-files (append added modified) 'uptodate) + (git-update-status-files (append added modified)) (when ok (dolist (file modified) (let ((buffer (get-file-buffer file))) @@ -1078,7 +1096,7 @@ Return the list of files that haven't been handled." (let ((files (git-get-filenames (git-marked-files-state 'unmerged)))) (when files (when (apply 'git-call-process-display-error "update-index" "--" files) - (git-update-status-files files 'uptodate) + (git-update-status-files files) (git-success-message "Resolved" files))))) (defun git-remove-handled () @@ -1348,7 +1366,7 @@ amended version of it." (git-call-process-display-error "reset" "--soft" "HEAD^") (and (git-update-ref "ORIG_HEAD" commit) (git-update-ref "HEAD" nil commit))) - (git-update-status-files (copy-sequence files) 'uptodate) + (git-update-status-files (copy-sequence files)) (git-mark-files git-status files) (git-refresh-files) (git-setup-commit-buffer commit) @@ -1391,27 +1409,10 @@ amended version of it." (defun git-refresh-status () "Refresh the git status buffer." (interactive) - (let* ((status git-status) - (pos (ewoc-locate status)) - (marked-files (git-get-filenames (ewoc-collect status (lambda (info) (git-fileinfo->marked info))))) - (cur-name (and pos (git-fileinfo->name (ewoc-data pos))))) - (unless status (error "Not in git-status buffer.")) - (message "Refreshing git status...") - (git-call-process nil "update-index" "--refresh") - (git-clear-status status) - (git-update-status-files nil) - ; restore file marks - (when marked-files - (git-status-filenames-map status - (lambda (info) - (setf (git-fileinfo->marked info) t) - (setf (git-fileinfo->needs-refresh info) t)) - marked-files) - (git-refresh-files)) - ; move point to the current file name if any - (message "Refreshing git status...done") - (let ((node (and cur-name (git-find-status-file status cur-name)))) - (when node (ewoc-goto-node status node))))) + (unless git-status (error "Not in git-status buffer.")) + (message "Refreshing git status...") + (git-update-status-files) + (message "Refreshing git status...done")) (defun git-status-quit () "Quit git-status mode." @@ -1591,7 +1592,7 @@ Meant to be used in `after-save-hook'." ; skip files located inside the .git directory (unless (string-match "^\\.git/" filename) (git-call-process nil "add" "--refresh" "--" filename) - (git-update-status-files (list filename) 'uptodate))))))) + (git-update-status-files (list filename)))))))) (defun git-help () "Display help for Git mode." -- cgit v1.2.1 From b0a53e9e56d0a501aebc99d3614be413e91613f6 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 4 Aug 2008 09:30:42 +0200 Subject: git.el: Add an insert file command. This allows to insert a file in the buffer no matter what its state is, making it possible for instance to remove an up-to-date file. Signed-off-by: Alexandre Julliard --- contrib/emacs/git.el | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el index 67c527599..6119c31d0 100644 --- a/contrib/emacs/git.el +++ b/contrib/emacs/git.el @@ -1019,6 +1019,11 @@ Return the list of files that haven't been handled." (setq node (ewoc-prev git-status node))) (ewoc-goto-node git-status last))) +(defun git-insert-file (file) + "Insert file(s) into the git-status buffer." + (interactive "fInsert file: ") + (git-update-status-files (list (file-relative-name file)))) + (defun git-add-file () "Add marked file(s) to the index cache." (interactive) @@ -1449,6 +1454,7 @@ amended version of it." (define-key map "\r" 'git-find-file) (define-key map "g" 'git-refresh-status) (define-key map "i" 'git-ignore-file) + (define-key map "I" 'git-insert-file) (define-key map "l" 'git-log-file) (define-key map "m" 'git-mark-file) (define-key map "M" 'git-mark-all) @@ -1505,6 +1511,7 @@ amended version of it." ["Revert File" git-revert-file t] ["Ignore File" git-ignore-file t] ["Remove File" git-remove-file t] + ["Insert File" git-insert-file t] "--------" ["Find File" git-find-file t] ["View File" git-view-file t] -- cgit v1.2.1 From c4e8b72f228b20d3ed6cfba0586364ea8ca431af Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sat, 1 Nov 2008 20:14:10 +0100 Subject: git.el: Add possibility to mark files directly in git-update-status-files. This avoids the need to go through the list twice, which helps performance on large file lists. Signed-off-by: Alexandre Julliard --- contrib/emacs/git.el | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el index 6119c31d0..9e9101b17 100644 --- a/contrib/emacs/git.el +++ b/contrib/emacs/git.el @@ -752,7 +752,7 @@ Return the list of files that haven't been handled." (concat "--exclude-per-directory=" git-per-dir-ignore-file) (append options (mapcar (lambda (f) (concat "--exclude-from=" f)) exclude-files))))) -(defun git-update-status-files (&optional files) +(defun git-update-status-files (&optional files mark-files) "Update the status of FILES from the index." (unless git-status (error "Not in git-status buffer.")) ;; set the needs-update flag on existing files @@ -777,12 +777,12 @@ Return the list of files that haven't been handled." (when remaining-files (setq remaining-files (git-run-ls-files-cached git-status remaining-files 'uptodate))) (git-set-filenames-state git-status remaining-files nil) + (when mark-files (git-mark-files git-status files)) (git-refresh-files) (git-refresh-ewoc-hf git-status))) (defun git-mark-files (status files) "Mark all the specified FILES, and unmark the others." - (setq files (sort files #'string-lessp)) (let ((file (and files (pop files))) (node (ewoc-nth status 0))) (while node @@ -1371,9 +1371,7 @@ amended version of it." (git-call-process-display-error "reset" "--soft" "HEAD^") (and (git-update-ref "ORIG_HEAD" commit) (git-update-ref "HEAD" nil commit))) - (git-update-status-files (copy-sequence files)) - (git-mark-files git-status files) - (git-refresh-files) + (git-update-status-files files t) (git-setup-commit-buffer commit) (git-commit-file)))) -- cgit v1.2.1 From 1905a8666a676f7070ba15c6f56f98bb1da20f7b Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Fri, 7 Nov 2008 14:28:09 +0100 Subject: git.el: Allow to commit even if there are no marked files. This can be useful to commit a merge that didn't result in any changes. Signed-off-by: Alexandre Julliard --- contrib/emacs/git.el | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el index 9e9101b17..09e8bae3a 100644 --- a/contrib/emacs/git.el +++ b/contrib/emacs/git.el @@ -895,29 +895,26 @@ Return the list of files that haven't been handled." (unless (git-empty-db-p) (setq head (git-rev-parse "HEAD") head-tree (git-rev-parse "HEAD^{tree}"))) - (if files - (progn - (message "Running git commit...") - (when - (and - (git-read-tree head-tree index-file) - (git-update-index nil files) ;update both the default index - (git-update-index index-file files) ;and the temporary one - (setq tree (git-write-tree index-file))) - (if (or (not (string-equal tree head-tree)) - (yes-or-no-p "The tree was not modified, do you really want to perform an empty commit? ")) - (let ((commit (git-commit-tree buffer tree head))) - (when commit - (condition-case nil (delete-file ".git/MERGE_HEAD") (error nil)) - (condition-case nil (delete-file ".git/MERGE_MSG") (error nil)) - (with-current-buffer buffer (erase-buffer)) - (git-update-status-files (git-get-filenames files)) - (git-call-process nil "rerere") - (git-call-process nil "gc" "--auto") - (message "Committed %s." commit) - (git-run-hook "post-commit" nil))) - (message "Commit aborted.")))) - (message "No files to commit."))) + (message "Running git commit...") + (when + (and + (git-read-tree head-tree index-file) + (git-update-index nil files) ;update both the default index + (git-update-index index-file files) ;and the temporary one + (setq tree (git-write-tree index-file))) + (if (or (not (string-equal tree head-tree)) + (yes-or-no-p "The tree was not modified, do you really want to perform an empty commit? ")) + (let ((commit (git-commit-tree buffer tree head))) + (when commit + (condition-case nil (delete-file ".git/MERGE_HEAD") (error nil)) + (condition-case nil (delete-file ".git/MERGE_MSG") (error nil)) + (with-current-buffer buffer (erase-buffer)) + (git-update-status-files (git-get-filenames files)) + (git-call-process nil "rerere") + (git-call-process nil "gc" "--auto") + (message "Committed %s." commit) + (git-run-hook "post-commit" nil))) + (message "Commit aborted.")))) (delete-file index-file)))))) -- cgit v1.2.1