diff --git a/lisp/magit-git.el b/lisp/magit-git.el index 0b6b8fd6a9..7fd28eeed0 100644 --- a/lisp/magit-git.el +++ b/lisp/magit-git.el @@ -1463,18 +1463,39 @@ Return a list of two integers: (A>B B>A)." ;;; Variables +(defun magit-config-get-from-cached-list (key) + (gethash + ;; `git config --list' downcases first and last components of the key. + (--> key + (replace-regexp-in-string "\\`[^.]+" #'downcase it t t) + (replace-regexp-in-string "[^.]+\\'" #'downcase it t t)) + (magit--with-refresh-cache (list 'config (magit-toplevel)) + (let ((configs (make-hash-table :test 'equal))) + (dolist (conf (magit-git-items "config" "--list" "-z")) + (let* ((nl-pos (cl-position ?\n conf)) + (key (substring conf 0 nl-pos)) + (val (if nl-pos (substring conf (1+ nl-pos)) ""))) + (puthash key (nconc (gethash key configs) (list val)) configs))) + configs)))) + (defun magit-get (&rest keys) "Return the value of Git config entry specified by KEYS." - (magit-git-str "config" (mapconcat 'identity keys "."))) + (car (last (apply 'magit-get-all keys)))) (defun magit-get-all (&rest keys) "Return all values of the Git config entry specified by KEYS." - (let ((magit-git-debug nil)) - (magit-git-items "config" "-z" "--get-all" (mapconcat 'identity keys ".")))) + (let ((magit-git-debug nil) + (key (mapconcat 'identity keys "."))) + (if magit--refresh-cache + (magit-config-get-from-cached-list key) + (magit-git-items "config" "-z" "--get-all" key)))) (defun magit-get-boolean (&rest keys) "Return the boolean value of Git config entry specified by KEYS." - (magit-git-true "config" "--bool" (mapconcat 'identity keys "."))) + (let ((key (mapconcat 'identity keys "."))) + (if magit--refresh-cache + (equal "true" (car (magit-config-get-from-cached-list key))) + (magit-git-true "config" "--bool" key)))) (defun magit-set (val &rest keys) "Set Git config settings specified by KEYS to VAL." diff --git a/t/magit-tests.el b/t/magit-tests.el index 11067ee1b3..ad421e0eb0 100644 --- a/t/magit-tests.el +++ b/t/magit-tests.el @@ -136,6 +136,37 @@ (should (equal (magit-toplevel "wrap/subsubdir-link") (expand-file-name "repo/")))) +(defun magit-test-magit-get () + (should (equal (magit-get-all "a.b") '("val1" "val2"))) + (should (equal (magit-get "a.b") "val2")) + (let ((default-directory (expand-file-name "../remote/"))) + (should (equal (magit-get "a.b") "remote-value"))) + (should (equal (magit-get "CAM.El.Case.VAR") "value")) + (should (equal (magit-get "a.b2") "line1\nline2"))) + +(ert-deftest magit-get () + (magit-with-test-directory + (magit-git "init" "remote") + (let ((default-directory (expand-file-name "remote/"))) + (magit-git "commit" "-m" "init" "--allow-empty") + (magit-git "config" "a.b" "remote-value")) + (magit-git "init" "super") + (setq default-directory (expand-file-name "super/")) + ;; Some tricky cases: + ;; Multiple config values. + (magit-git "config" "a.b" "val1") + (magit-git "config" "--add" "a.b" "val2") + ;; CamelCase variable names. + (magit-git "config" "Cam.El.Case.Var" "value") + ;; Values with newlines. + (magit-git "config" "a.b2" "line1\nline2") + ;; Config variables in submodules. + (magit-git "submodule" "add" "../remote" "repo/") + + (magit-test-magit-get) + (let ((magit--refresh-cache (list (cons 0 0)))) + (magit-test-magit-get)))) + (ert-deftest magit-get-boolean () (magit-with-test-repository (magit-git "config" "a.b" "true")