diff options
Diffstat (limited to 'lisp/vc/vc-git.el')
-rw-r--r-- | lisp/vc/vc-git.el | 108 |
1 files changed, 69 insertions, 39 deletions
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index 935dc8b9aee..5c6a39aec96 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -242,14 +242,19 @@ included in the completions." ;;;###autoload (load "vc-git" nil t) ;;;###autoload (vc-git-registered file)))) -(defun vc-git--literal-pathspec (pathspec) - "Prepend :(literal) path magic to PATHSPEC." - ;; Good example of PATHSPEC that needs this: "test[56].xx". - (and pathspec (concat ":(literal)" pathspec))) - -(defun vc-git--literal-pathspecs (pathspecs) - "Prepend :(literal) path magic to PATHSPECS." - (mapcar #'vc-git--literal-pathspec pathspecs)) +;; Good example of file name that needs this: "test[56].xx". +(defun vc-git--literal-pathspec (file) + "Prepend :(literal) path magic to FILE." + (when file + ;; Expand abbreviated file names. + (when (file-name-absolute-p file) + (setq file (expand-file-name file))) + (concat ":(literal)" (file-local-name file)))) + +(defun vc-git--literal-pathspecs (files) + "Prepend :(literal) path magic to FILES." + (unless (vc-git--file-list-is-rootdir files) + (mapcar #'vc-git--literal-pathspec files))) (defun vc-git-registered (file) "Check whether FILE is registered with git." @@ -293,12 +298,14 @@ included in the completions." (vc-git--run-command-string nil "version"))) (setq vc-git--program-version (if (and version-string - ;; Git for Windows appends ".windows.N" to the - ;; numerical version reported by Git. - (string-match - "git version \\([0-9.]+\\)\\(\\.windows\\.[0-9]+\\)?$" - version-string)) - (match-string 1 version-string) + ;; Some Git versions append additional strings + ;; to the numerical version string. E.g., Git + ;; for Windows appends ".windows.N", while Git + ;; for Mac appends " (Apple Git-N)". Capture + ;; numerical version and ignore the rest. + (string-match "git version \\([0-9][0-9.]+\\)" + version-string)) + (string-trim-right (match-string 1 version-string) "\\.") "0"))))) (defun vc-git--git-status-to-vc-state (code-list) @@ -402,7 +409,7 @@ in the order given by `git status'." orig-name) ;; Original name for renames or copies. (defun vc-git-escape-file-name (name) - "Escape a file name if necessary." + "Escape filename NAME if necessary." (if (string-match "[\n\t\"\\]" name) (concat "\"" (mapconcat (lambda (c) @@ -891,8 +898,7 @@ The car of the list is the current branch." (declare-function log-edit--toggle-amend "log-edit" (last-msg-fn)) (defun vc-git-log-edit-toggle-signoff () - "Toggle whether to add the \"Signed-off-by\" line at the end of -the commit message." + "Toggle whether to add the \"Signed-off-by\" line at the end of commit message." (interactive) (log-edit-toggle-header "Sign-Off" "yes")) @@ -1142,6 +1148,14 @@ This prompts for a branch to merge from." (autoload 'vc-setup-buffer "vc-dispatcher") +;; It's a weird option due to how Git handles '--follow', and it can +;; hide certain (usually merge) commits in the `vc-print-log' buffers. +;; +;; (setq vc-git-log-switches '("-m")) can fix that, but at the cost of +;; duplicating many merge commits in the log. +;; +;; Long explanation here: +;; https://stackoverflow.com/questions/46487476/git-log-follow-graph-skips-commits (defcustom vc-git-print-log-follow nil "If true, follow renames in Git logs for a single file." :type 'boolean @@ -1244,7 +1258,10 @@ log entries." (defun vc-git-mergebase (rev1 &optional rev2) (unless rev2 (setq rev2 "HEAD")) - (string-trim-right (vc-git--run-command-string nil "merge-base" rev1 rev2))) + (let ((base (vc-git--run-command-string nil "merge-base" rev1 rev2))) + (if base + (string-trim-right base) + (error "No common ancestor for merge base")))) (defvar log-view-message-re) (defvar log-view-file-re) @@ -1311,7 +1328,7 @@ or BRANCH^ (where \"^\" can be repeated)." (defun vc-git-expanded-log-entry (revision) (with-temp-buffer - (apply #'vc-git-command t nil nil (list "log" revision "-1" "--")) + (apply #'vc-git-command t nil nil (list "log" revision "-1" "--no-color" "--")) (goto-char (point-min)) (unless (eobp) ;; Indent the expanded log entry. @@ -1552,10 +1569,10 @@ This requires git 1.8.4 or later, for the \"-L\" option of \"git log\"." (or (vc-git-symbolic-commit next-rev) next-rev))) (defun vc-git-delete-file (file) - (vc-git-command nil 0 (vc-git--literal-pathspecs file) "rm" "-f" "--")) + (vc-git-command nil 0 (vc-git--literal-pathspec file) "rm" "-f" "--")) (defun vc-git-rename-file (old new) - (vc-git-command nil 0 (vc-git--literal-pathspecs (list old new)) "mv" "-f" "--")) + (vc-git-command nil 0 (list old new) "mv" "-f" "--")) (defun vc-git-mark-resolved (files) (vc-git-command nil 0 (vc-git--literal-pathspecs files) "add")) @@ -1607,8 +1624,8 @@ before it is executed. With two \\[universal-argument] prefixes, directly edit and run `grep-command'. Collect output in a buffer. While git grep runs asynchronously, you -can use \\[next-error] (M-x next-error), or \\<grep-mode-map>\\[compile-goto-error] \ -in the grep output buffer, +can use \\[next-error] (`next-error'), or \\<grep-mode-map>\ +\\[compile-goto-error] in the grep output buffer, to go to the lines where grep found matches. This command shares argument histories with \\[rgrep] and \\[grep]." @@ -1673,7 +1690,7 @@ This command shares argument histories with \\[rgrep] and \\[grep]." (let ((stash (completing-read prompt (split-string - (or (vc-git--run-command-string nil "stash" "list") "") "\n") + (or (vc-git--run-command-string nil "stash" "list") "") "\n" t) nil :require-match nil 'vc-git-stash-read-history))) (if (string-equal stash "") (user-error "Not a stash") @@ -1718,12 +1735,11 @@ This command shares argument histories with \\[rgrep] and \\[grep]." (defun vc-git-stash-list () (when-let ((out (vc-git--run-command-string nil "stash" "list"))) - (delete - "" - (split-string - (replace-regexp-in-string - "^stash@" " " out) - "\n")))) + (split-string + (replace-regexp-in-string + "^stash@" " " out) + "\n" + t))) (defun vc-git-stash-get-at-point (point) (save-excursion @@ -1787,15 +1803,18 @@ The difference to vc-do-command is that this function always invokes '("GIT_OPTIONAL_LOCKS=0"))) process-environment))) (apply #'vc-do-command (or buffer "*vc*") okstatus vc-git-program - ;; https://debbugs.gnu.org/16897 - (unless (and (not (cdr-safe file-or-list)) - (let ((file (or (car-safe file-or-list) - file-or-list))) - (and file - (eq ?/ (aref file (1- (length file)))) - (equal file (vc-git-root file))))) - file-or-list) - (cons "--no-pager" flags)))) + ;; https://debbugs.gnu.org/16897 + (unless (vc-git--file-list-is-rootdir file-or-list) + file-or-list) + (cons "--no-pager" flags)))) + +(defun vc-git--file-list-is-rootdir (file-or-list) + (and (not (cdr-safe file-or-list)) + (let ((file (or (car-safe file-or-list) + file-or-list))) + (and file + (eq ?/ (aref file (1- (length file)))) + (equal file (vc-git-root file)))))) (defun vc-git--empty-db-p () "Check if the git db is empty (no commit done yet)." @@ -1853,6 +1872,17 @@ Returns nil if not possible." (1- (point-max))))))) (and name (not (string= name "undefined")) name)))) +(defvar-keymap vc-dir-git-mode-map + "z c" #'vc-git-stash + "z s" #'vc-git-stash-snapshot + "z p" #'vc-git-stash-pop) + +(define-minor-mode vc-dir-git-mode + "A minor mode for git-specific commands in `vc-dir-mode' buffers. +Also note that there are git stash commands available in the +\"Stash\" section at the head of the buffer." + :lighter " Git") + (provide 'vc-git) ;;; vc-git.el ends here |