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`.
This commit is contained in:
Daniel - 2023-03-23 19:50:35 +01:00
parent 13cbd90ec6
commit 6bac3973f9
Signed by: dbo
GPG Key ID: 784AA8DF0CCDF625
1 changed files with 33 additions and 21 deletions

View File

@ -83,38 +83,50 @@ git repository."
repo-dir) repo-dir)
(when (and (not (file-remote-p pwd)) (when (and (not (file-remote-p pwd))
(eshell-search-path "git") (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")) (if (string-prefix-p (file-truename (file-name-concat repo-dir ".git"))
(file-truename pwd)) (file-truename pwd))
"GIT_DIR" "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")) ;; When resolving HEAD fails, we do not have any commits yet.
(push "merge" state-list)) "UNINITIALIZED")))
state-list)
(when (= 1 (call-process "git" nil nil nil (when (and db/eshell-prompt-include-git-state
"diff" "--no-ext-diff" "--quiet" "--exit-code")) has-HEAD)
(push "dirty" state-list))
(when (= 1 (call-process "git" nil nil nil ;; XXX: This does not work in repositories with gitdir files
"diff" "--no-ext-diff" "--quiet" "--exit-code" "--cached")) (when (file-exists-p (file-name-concat repo-dir ".git" "MERGE_HEAD"))
(push "uncommitted" state-list)) (push "merge" state-list))
(when (with-temp-buffer (when (= 1 (call-process "git" nil nil nil
(and (= 0 (call-process "git" nil t nil "diff" "--no-ext-diff" "--quiet" "--exit-code"))
"stash" "list")) (push "dirty" state-list))
(not (= 0 (buffer-size)))))
(push "stash" 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 (if state-list
(format "%s@%s[%s]" git-branch base-dir (apply #'concat (-interpose "|" 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 () (defun eshell/default-prompt-function ()
"A prompt for eshell of the form "A prompt for eshell of the form