From 6bac3973f96a65efe94c20eb77b62cf23d3e6426 Mon Sep 17 00:00:00 2001 From: Daniel Borchmann Date: Thu, 23 Mar 2023 19:50:35 +0100 Subject: [PATCH] Make eshell git prompt function more robust When checking whether we are in a git repository or not, remove all symbolic links in the current path before looking for a .git in the current path; otherwise, symbolic links might mislead `locate-dominating-file` to find some .git directory which is only reachable via symbolic links, which subsequently is ignored by git (rightly so!) and thus yields errors. Also, catch the case that the current git repository is not initialized yet by checking the return value of `git rev-parse --abbrev-ref HEAD`. --- site-lisp/db-eshell.el | 54 ++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/site-lisp/db-eshell.el b/site-lisp/db-eshell.el index fb47775..6cef0b4 100644 --- a/site-lisp/db-eshell.el +++ b/site-lisp/db-eshell.el @@ -83,38 +83,50 @@ git repository." repo-dir) (when (and (not (file-remote-p pwd)) (eshell-search-path "git") - (setq repo-dir (locate-dominating-file pwd ".git"))) + (setq repo-dir (locate-dominating-file (file-truename pwd) ".git"))) + (if (string-prefix-p (file-truename (file-name-concat repo-dir ".git")) (file-truename pwd)) "GIT_DIR" - (save-match-data - (let* ((git-branch (string-trim - (shell-command-to-string "git rev-parse --abbrev-ref HEAD"))) - (base-dir (file-name-nondirectory (directory-file-name repo-dir))) - state-list) - (when db/eshell-prompt-include-git-state + (save-match-data + (let* ((has-HEAD nil) + (git-branch (with-temp-buffer + (if (zerop (call-process "git" nil t nil + "rev-parse" "--abbrev-ref" "HEAD")) + (progn + (setq has-HEAD t) + (string-trim (buffer-string))) - (when (file-exists-p (file-name-concat repo-dir ".git" "MERGE_HEAD")) - (push "merge" state-list)) + ;; When resolving HEAD fails, we do not have any commits yet. + "UNINITIALIZED"))) + state-list) - (when (= 1 (call-process "git" nil nil nil - "diff" "--no-ext-diff" "--quiet" "--exit-code")) - (push "dirty" state-list)) + (when (and db/eshell-prompt-include-git-state + has-HEAD) - (when (= 1 (call-process "git" nil nil nil - "diff" "--no-ext-diff" "--quiet" "--exit-code" "--cached")) - (push "uncommitted" state-list)) + ;; XXX: This does not work in repositories with gitdir files + (when (file-exists-p (file-name-concat repo-dir ".git" "MERGE_HEAD")) + (push "merge" state-list)) - (when (with-temp-buffer - (and (= 0 (call-process "git" nil t nil - "stash" "list")) - (not (= 0 (buffer-size))))) - (push "stash" state-list))) + (when (= 1 (call-process "git" nil nil nil + "diff" "--no-ext-diff" "--quiet" "--exit-code")) + (push "dirty" state-list)) + (when (= 1 (call-process "git" nil nil nil + "diff" "--no-ext-diff" "--quiet" "--exit-code" "--cached")) + (push "uncommitted" state-list)) + + (when (with-temp-buffer + (and (= 0 (call-process "git" nil t nil + "stash" "list")) + (not (= 0 (buffer-size))))) + (push "stash" state-list))) + + (let ((base-dir (file-name-nondirectory (directory-file-name repo-dir)))) (if state-list (format "%s@%s[%s]" git-branch base-dir (apply #'concat (-interpose "|" state-list))) - (format "%s@%s" git-branch base-dir)))))))) + (format "%s@%s" git-branch base-dir))))))))) (defun eshell/default-prompt-function () "A prompt for eshell of the form