update packages and add valign

This commit is contained in:
2026-04-05 20:00:27 +02:00
parent b062fb98e3
commit 03fb00e374
640 changed files with 109768 additions and 39311 deletions

View File

@@ -1,6 +1,6 @@
;;; magit-git.el --- Git functionality -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors
;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -48,7 +48,6 @@
(defvar magit-buffer-file-name)
(defvar magit-buffer-log-args)
(defvar magit-buffer-log-files)
(defvar magit-buffer-refname)
(defvar magit-buffer-revision)
;; From `magit-process'.
@@ -72,6 +71,8 @@
(cl-pushnew 'orig-rev eieio--known-slot-names)
(cl-pushnew 'number eieio--known-slot-names))
(defvar crm-prompt) ; Emacs 31.1
;;; Options
;; For now this is shared between `magit-process' and `magit-git'.
@@ -393,7 +394,7 @@ to do the following.
* Prepend `magit-git-global-arguments' to ARGS.
* If ASYNC is non-nil and `magit-overriding-githook-directory' is non-nil
and valid, set `core.hooksPath' by adding additional aguments to ARGS.
and valid, set `core.hooksPath' by adding additional arguments to ARGS.
* Flatten ARGS, removing nil arguments.
* If `system-type' is `windows-nt', encode ARGS to `w32-ansi-code-page'."
(cond ((not async))
@@ -434,22 +435,6 @@ to do the following.
"Execute Git with ARGS, returning t if its exit code is 1."
(= (magit-git-exit-code args) 1))
(defun magit-git-string-p (&rest args)
"Execute Git with ARGS, returning the first line of its output.
If the exit code isn't zero or if there is no output, then return
nil. Neither of these results is considered an error; if that is
what you want, then use `magit-git-string-ng' instead.
This is an experimental replacement for `magit-git-string', and
still subject to major changes."
(magit--with-refresh-cache (cons default-directory args)
(magit--with-temp-process-buffer
(and (zerop (magit-process-git t args))
(not (bobp))
(progn
(goto-char (point-min))
(buffer-substring-no-properties (point) (line-end-position)))))))
(defun magit-git-string-ng (&rest args)
"Execute Git with ARGS, returning the first line of its output.
If the exit code isn't zero or if there is no output, then that
@@ -459,7 +444,7 @@ buffer (creating it if necessary) and the error message is shown
in the status buffer (provided it exists).
This is an experimental replacement for `magit-git-string', and
still subject to major changes. Also see `magit-git-string-p'."
still subject to major changes."
(magit--with-refresh-cache
(list default-directory 'magit-git-string-ng args)
(magit--with-temp-process-buffer
@@ -526,9 +511,9 @@ signal `magit-invalid-git-boolean'."
(defun magit-git-config-p (variable &optional default)
"Return the boolean value of the Git variable VARIABLE.
VARIABLE has to be specified as a string. Return DEFAULT (which
defaults to nil) if VARIABLE is unset. If VARIABLE's value isn't
a boolean, then raise an error."
VARIABLE has to be specified as a string. If VARIABLE is unset,
return nil by default, unless DEFAULT is non-nil, in which case
return t. Signal an error if VARIABLE is set but not a boolean."
(let ((args (list "config" "--bool" "--default" (if default "true" "false")
variable)))
(magit--with-refresh-cache (cons default-directory args)
@@ -561,12 +546,12 @@ insert the run command and stderr into the process buffer."
(goto-char (point-max))
(setq errmsg
(cond
((eq return-error 'full)
(let ((str (buffer-string)))
(and (not (equal str "")) str)))
((functionp magit-git-debug)
(funcall magit-git-debug (buffer-string)))
((magit--locate-error-message)))))
((eq return-error 'full)
(let ((str (buffer-string)))
(and (not (equal str "")) str)))
((functionp magit-git-debug)
(funcall magit-git-debug (buffer-string)))
((magit--locate-error-message)))))
(when magit-git-debug
(let ((magit-git-debug nil))
(with-current-buffer (magit-process-buffer t)
@@ -577,10 +562,12 @@ insert the run command and stderr into the process buffer."
exit log 'magit-section-secondary-heading)
exit)))))
(cond ((not magit-git-debug))
(errmsg (message "%s" errmsg))
(errmsg (message "magit--git-insert: %S" errmsg))
((zerop exit))
((message "Git returned with exit-code %s" exit))))
(or errmsg exit))
((message "magit--git-insert: %s %s"
"Git returned with exit-code" exit))))
(or (and return-error errmsg)
exit))
(ignore-errors (delete-file log))))
(magit-process-git (list t nil) args)))
@@ -591,16 +578,18 @@ insert the run command and stderr into the process buffer."
(match-str 1)))
(defun magit-git-string (&rest args)
"Execute Git with ARGS, returning the first line of its output.
If there is no output, return nil. If the output begins with a
newline, return an empty string."
"Execute Git with ARGS, returning the first line of its output (stdout).
If the exit code isn't zero or if there is no output, then return nil.
Neither of these results is considered an error; if that is what you
want, then use `magit-git-string-ng' instead."
(setq args (flatten-tree args))
(magit--with-refresh-cache (cons default-directory args)
(magit--with-temp-process-buffer
(apply #'magit-git-insert args)
(unless (bobp)
(goto-char (point-min))
(buffer-substring-no-properties (point) (line-end-position))))))
(and (zerop (apply #'magit-git-insert args))
(not (bobp))
(progn
(goto-char (point-min))
(buffer-substring-no-properties (point) (line-end-position)))))))
(defun magit-git-lines (&rest args)
"Execute Git with ARGS, returning its output as a list of lines.
@@ -708,29 +697,29 @@ format."
(status (magit-process-git t "version"))
(output (buffer-string)))
(cond
((not (zerop status))
(display-warning
'magit
(format "%S\n\nRunning \"%s --version\" failed with output:\n\n%s"
(if host
(format "Magit cannot find Git on host %S.\n
((not (zerop status))
(display-warning
'magit
(format "%S\n\nRunning \"%s --version\" failed with output:\n\n%s"
(if host
(format "Magit cannot find Git on host %S.\n
Check the value of `magit-remote-git-executable' using
`magit-debug-git-executable' and consult the info node
`(tramp)Remote programs'." host)
"Magit cannot find Git.\n
"Magit cannot find Git.\n
Check the values of `magit-git-executable' and `exec-path'
using `magit-debug-git-executable'.")
(magit-git-executable)
output)))
((save-match-data
(and (string-match magit--git-version-regexp output)
(let ((version (match-str 1 output)))
(push (cons host version)
magit--host-git-version-cache)
version))))
((error "Unexpected \"%s --version\" output: %S"
(magit-git-executable)
output)))))))))
(magit-git-executable)
output)))
((save-match-data
(and (string-match magit--git-version-regexp output)
(let ((version (match-str 1 output)))
(push (cons host version)
magit--host-git-version-cache)
version))))
((error "Unexpected \"%s --version\" output: %S"
(magit-git-executable)
output)))))))))
(defun magit-git-version-assert (&optional minimal who)
"Assert that the used Git version is greater than or equal to MINIMAL.
@@ -1019,9 +1008,7 @@ returning the truename."
(define-error 'magit-outside-git-repo "Not inside Git repository")
(define-error 'magit-corrupt-git-config "Corrupt Git configuration")
(define-error 'magit-git-executable-not-found
(concat "Git executable cannot be found "
"(see https://magit.vc/goto/e6a78ed2)"))
(define-error 'magit-git-executable-not-found "Git executable cannot be found")
(defun magit--assert-usable-git ()
(if (not (executable-find (magit-git-executable) t))
@@ -1121,8 +1108,8 @@ tracked file."
(file-relative-name file dir))))
(defun magit-file-ignored-p (file)
(magit-git-string-p "ls-files" "--others" "--ignored" "--exclude-standard"
"--" (magit-convert-filename-for-git file)))
(magit-git-string "ls-files" "--others" "--ignored" "--exclude-standard"
"--" (magit-convert-filename-for-git file)))
(defun magit-file-tracked-p (file)
(magit-git-success "ls-files" "--error-unmatch"
@@ -1145,6 +1132,16 @@ issue."
(and (not all) "--exclude-standard")
"--" files))
(defun magit--untracked-files (&optional directory all)
(magit-with-toplevel
(seq-keep (##and (eq (aref % 0) ??)
(substring % 3))
(magit-git-items "status" "-z" "--porcelain"
(if all
"--untracked-files=all"
"--untracked-files=normal")
"--" directory))))
(defun magit-list-untracked-files (&optional files)
"Return a list of untracked files.
@@ -1258,13 +1255,12 @@ or if no rename is detected."
(y (char-after (1+ pos)))
(file (buffer-substring (+ pos 3) (point))))
(forward-char)
(if (memq x '(?R ?C))
(progn
(setq pos (point))
(skip-chars-forward "[:print:]")
(push (list file (buffer-substring pos (point)) x y) status)
(forward-char))
(push (list file nil x y) status)))
(cond ((memq x '(?R ?C))
(setq pos (point))
(skip-chars-forward "[:print:]")
(push (list file (buffer-substring pos (point)) x y) status)
(forward-char))
((push (list file nil x y) status))))
(setq pos (point)))
status)))
@@ -1279,11 +1275,10 @@ or if no rename is detected."
"Failed to parse Cygwin mount: %S" mount)))
;; If --exec-path is not a native Windows path,
;; then we probably have a cygwin git.
(and (not (string-match-p
"\\`[a-zA-Z]:"
(car (magit--early-process-lines
magit-git-executable "--exec-path"))))
(magit--early-process-lines "mount")))
(and-let ((dirs (magit--early-process-lines
magit-git-executable "--exec-path")))
(and (not (string-match-p "\\`[a-zA-Z]:" (car dirs)))
(magit--early-process-lines "mount"))))
#'> :key (pcase-lambda (`(,cyg . ,_win)) (length cyg))))
"Alist of (CYGWIN . WIN32) directory names.
Sorted from longest to shortest CYGWIN name."
@@ -1344,6 +1339,36 @@ Sorted from longest to shortest CYGWIN name."
(and (derived-mode-p 'magit-log-mode)
(car magit-buffer-log-files))))
;;; Blobs
(defun magit-blob-p (obj)
(equal (magit-object-type obj) "blob"))
(defun magit-blob-oid (rev file)
(cond-let
((equal rev "{index}")
(cadr (car (magit--file-index-stages file))))
;; --object-only and --format were only added in Git v2.36.0.
([out (magit-git-string "ls-tree" "--full-tree" rev "--"
(magit-convert-filename-for-git file))]
(nth 2 (split-string out "[\s\t]")))))
(defun magit--file-index-stages (file)
(mapcar (##split-string % " ")
(magit-git-lines "ls-files" "--stage" "--"
(magit-convert-filename-for-git file))))
(defun magit--insert-blob-contents (obj file)
(let ((coding-system-for-read (or coding-system-for-read 'undecided)))
(if (magit-blob-p obj)
(magit-git-insert "cat-file" "blob" obj)
(magit-git-insert "cat-file" "-p"
(if (equal obj "{index}")
(concat ":" file)
(concat obj ":" file))))
(setq buffer-file-coding-system last-coding-system-used)
nil))
;;; Predicates
(defun magit-no-commit-p ()
@@ -1441,21 +1466,29 @@ string \"true\", otherwise return nil."
(equal (magit-git-str "rev-parse" args) "true"))
(defun magit-rev-verify (rev)
(magit-git-string-p "rev-parse" "--verify" rev))
(magit-git-string "rev-parse" "--verify" rev))
(defun magit-commit-p (rev)
"Return full hash for REV if it names an existing commit."
"Return non-nil if REV can be dereferences as a commit.
Otherwise return nil. Use `magit-commit-oid' if you actually need
the oid; eventually this function will return t instead of the oid,
as it currently does for backward compatibility."
;; TODO Return t instead of the oid.
(magit-rev-verify (magit--rev-dereference rev)))
(defalias 'magit-rev-verify-commit #'magit-commit-p)
(defalias 'magit-rev-hash #'magit-commit-p)
(defun magit-commit-oid (rev &optional noerror)
"Return commit oid for REV if it can be dereferences as a commit.
Otherwise signal an error, or return nil, if optional NOERROR is non-nil."
(cond ((magit-rev-verify (magit--rev-dereference rev)))
(noerror nil)
((error "%s cannot be dereferenced as a commit" rev))))
(defun magit--rev-dereference (rev)
"Return a rev that forces Git to interpret REV as a commit.
If REV is nil or has the form \":/TEXT\", return REV itself."
Do so by appending \"^{commit}\"; see \"--verify\" in git-rev-parse(1).
However, if REV is nil or has the form \":/TEXT\", return REV itself."
(cond ((not rev) nil)
((string-match-p "^:/" rev) rev)
((string-prefix-p ":/" rev) rev)
((concat rev "^{commit}"))))
(defun magit-rev-equal (a b)
@@ -1464,20 +1497,18 @@ If REV is nil or has the form \":/TEXT\", return REV itself."
(defun magit-rev-eq (a b)
"Return t if A and B refer to the same commit."
(let ((a (magit-commit-p a))
(b (magit-commit-p b)))
(and a b (equal a b))))
(and-let ((a (magit-commit-oid a t))
(b (magit-commit-oid b t)))
(equal a b)))
(defun magit-rev-ancestor-p (a b)
"Return non-nil if commit A is an ancestor of commit B."
(magit-git-success "merge-base" "--is-ancestor" a b))
(defun magit-rev-head-p (rev)
"Return t if REV can be dereferences as the `HEAD' commit."
(or (equal rev "HEAD")
(and rev
(not (string-search ".." rev))
(equal (magit-rev-parse rev)
(magit-rev-parse "HEAD")))))
(magit-rev-eq rev "HEAD")))
(defun magit-rev-author-p (rev)
"Return t if the user is the author of REV.
@@ -1584,9 +1615,9 @@ nil, then use \"heads/\"."
A symbolic-ref pointing to some ref, is `equal' to that ref,
as are two symbolic-refs pointing to the same ref. Refnames
may be abbreviated."
(let ((a (magit-ref-fullname a))
(b (magit-ref-fullname b)))
(and a b (equal a b))))
(and-let ((a (magit-ref-fullname a))
(b (magit-ref-fullname b)))
(equal a b)))
(defun magit-ref-eq (a b)
"Return t if the refnames A and B are `eq'.
@@ -1682,7 +1713,7 @@ to, or to some other symbolic-ref that points to the same ref."
(magit-current-blame-chunk))))
(oref chunk orig-rev))
(and magit-buffer-file-name
magit-buffer-refname)
magit-buffer-revision)
(and (derived-mode-p 'magit-stash-mode
'magit-merge-preview-mode
'magit-revision-mode)
@@ -1750,10 +1781,10 @@ The amount of time spent searching is limited by
(concat remote "/" newname))))
(pcase-dolist (`(,branch ,upstream) branches)
(cond
((equal upstream oldname)
(magit-set-upstream-branch branch new))
((equal upstream (concat remote "/" oldname))
(magit-set-upstream-branch branch (concat remote "/" newname))))))))
((equal upstream oldname)
(magit-set-upstream-branch branch new))
((equal upstream (concat remote "/" oldname))
(magit-set-upstream-branch branch (concat remote "/" newname))))))))
(defun magit--get-default-branch (&optional update)
(let ((remote (magit-primary-remote)))
@@ -1874,19 +1905,18 @@ according to the branch type."
(defun magit-get-push-branch (&optional branch verify)
(magit--with-refresh-cache
(list default-directory 'magit-get-push-branch branch verify)
(and-let* ((branch (or branch (setq branch (magit-get-current-branch))))
(remote (magit-get-push-remote branch))
(target (concat remote "/" branch)))
(and-let*
((branch (magit-ref-abbrev (or branch (magit-get-current-branch))))
(remote (magit-get-push-remote branch))
(target (concat remote "/" branch)))
(and (or (not verify)
(magit-rev-verify target))
(magit--propertize-face target 'magit-branch-remote)))))
(defun magit-get-@{push}-branch (&optional branch)
(let ((ref (magit-rev-parse "--symbolic-full-name"
(concat branch "@{push}"))))
(and ref
(string-prefix-p "refs/remotes/" ref)
(substring ref 13))))
(and-let* ((branch (magit-ref-abbrev (or branch (magit-get-current-branch))))
(target (magit-ref-fullname (concat branch "@{push}"))))
(magit-ref-abbrev target)))
(defun magit-get-remote (&optional branch)
(and (or branch (setq branch (magit-get-current-branch)))
@@ -2232,11 +2262,11 @@ specified using `core.worktree'."
(let* ((default-directory (car worktree))
(wt (and (not (magit-get-boolean "core.bare"))
(magit-get "core.worktree"))))
(if (and wt (file-exists-p (expand-file-name wt)))
(progn (setf (nth 0 worktree) (expand-file-name wt))
(setf (nth 2 worktree) (magit-rev-parse "HEAD"))
(setf (nth 3 worktree) (magit-get-current-branch)))
(setf (nth 3 worktree) t))))
(cond ((and wt (file-exists-p (expand-file-name wt)))
(setf (nth 0 worktree) (expand-file-name wt))
(setf (nth 2 worktree) (magit-rev-parse "HEAD"))
(setf (nth 3 worktree) (magit-get-current-branch)))
((setf (nth 3 worktree) t)))))
((string-equal line "detached")
(setf (nth 4 worktree) t))
((string-prefix-p line "locked")
@@ -2271,8 +2301,8 @@ specified using `core.worktree'."
'magit-branch-local
'magit-branch-remote)))
(defun magit-tag-p (rev)
(car (member rev (magit-list-tags))))
(defun magit-tag-p (obj)
(equal (magit-object-type obj) "tag"))
(defun magit-remote-p (string)
(car (member string (magit-list-remotes))))
@@ -2342,10 +2372,10 @@ If `first-parent' is set, traverse only first parents."
(defun magit-rev-abbrev (rev)
(magit-rev-parse (magit-abbrev-arg "short") rev))
(defun magit--abbrev-if-hash (rev)
(cond ((or (magit-ref-p rev) (member rev '("{index}" "{worktree}"))) rev)
((magit-rev-parse (magit-abbrev-arg "short") rev))
(rev)))
(defun magit--abbrev-if-oid (obj)
(cond ((or (magit-ref-p obj) (member obj '("{index}" "{worktree}"))) obj)
((magit-rev-parse (magit-abbrev-arg "short") obj))
(obj)))
(defun magit-commit-children (rev &optional args)
(seq-keep (lambda (line)
@@ -2469,18 +2499,18 @@ and this option only controls what face is used.")
(string-match "^[^/]*/" push)
(setq push (substring push 0 (match-end 0))))
(cond
((equal name current)
(setq head
(concat push
(magit--propertize-face
name 'magit-branch-current))))
((equal name target)
(setq upstream
(concat push
(magit--propertize-face
name '(magit-branch-upstream
magit-branch-local)))))
((push (concat push name) combined)))))
((equal name current)
(setq head
(concat push
(magit--propertize-face
name 'magit-branch-current))))
((equal name target)
(setq upstream
(concat push
(magit--propertize-face
name '(magit-branch-upstream
magit-branch-local)))))
((push (concat push name) combined)))))
(cond-let
((or upstream (not target)))
((member target remotes)
@@ -2568,8 +2598,8 @@ and this option only controls what face is used.")
(beg (or beg "HEAD"))
(end (or end "HEAD")))
(when abbrev
(setq beg (magit--abbrev-if-hash beg))
(setq end (magit--abbrev-if-hash end)))
(setq beg (magit--abbrev-if-oid beg))
(setq end (magit--abbrev-if-oid end)))
(pcase sep
(".." (cons beg end))
("..." (and$ (magit-git-string "merge-base" beg end)
@@ -2583,15 +2613,18 @@ and this option only controls what face is used.")
(list beg end sep)))))
(defun magit-hash-range (range)
"Return a string with the revisions in RANGE replaced with commit oids.
Either side of RANGE may be omitted, and RANGE may be just a revision.
If either revision cannot be dereferenced as a commit, signal an error."
(if (string-match magit-range-re range)
(magit-bind-match-strings (beg sep end) range
(and (or beg end)
(let ((beg-hash (and beg (magit-rev-hash beg)))
(end-hash (and end (magit-rev-hash end))))
(and (or (not beg) beg-hash)
(or (not end) end-hash)
(concat beg-hash sep end-hash)))))
(magit-rev-hash range)))
(let ((beg-oid (and beg (magit-commit-oid beg)))
(end-oid (and end (magit-commit-oid end))))
(and (or (not beg) beg-oid)
(or (not end) end-oid)
(concat beg-oid sep end-oid)))))
(magit-commit-oid range)))
(defvar magit-revision-faces
'(magit-hash
@@ -2645,7 +2678,7 @@ and this option only controls what face is used.")
(and (not (equal string "@"))
(or (and (>= (length string) 7)
(string-match-p "[a-z]" string)
(magit-commit-p string))
(magit-commit-oid string t))
(and (magit-ref-p string)
(member (get-text-property (point) 'face)
magit-revision-faces)))
@@ -2729,10 +2762,11 @@ and this option only controls what face is used.")
(lambda ()
(magit--minibuf-default-add-commit)
(setq-local crm-separator "\\.\\.\\.?"))
(magit-completing-read-multiple
(concat prompt ": ")
(magit-list-refnames)
nil 'any nil 'magit-revision-history default nil t)))
(let ((crm-prompt "%p"))
(magit-completing-read-multiple
(concat prompt ": ")
(magit-list-refnames)
nil 'any nil 'magit-revision-history default nil t))))
(defun magit-read-remote-branch
(prompt &optional remote default local-branch require-match)
@@ -2812,6 +2846,23 @@ and this option only controls what face is used.")
(magit-completing-read prompt (delete exclude (magit-list-refnames))
nil 'any nil 'magit-revision-history default))))
(defun magit-read-other-branches-or-commits
(prompt &optional exclude secondary-default)
(let* ((current (magit-get-current-branch))
(atpoint (magit-branch-or-commit-at-point))
(exclude (or exclude current))
(default (or (and (not (equal atpoint exclude))
(not (and (not current)
(magit-rev-equal atpoint "HEAD")))
atpoint)
(and (not (equal current exclude)) current)
secondary-default
(magit-get-previous-branch))))
(minibuffer-with-setup-hook #'magit--minibuf-default-add-commit
(magit-completing-read-multiple
prompt (delete exclude (magit-list-refnames))
nil 'any nil 'magit-revision-history default))))
(defun magit-read-other-local-branch
(prompt &optional exclude secondary-default)
(let* ((current (magit-get-current-branch))
@@ -2993,6 +3044,21 @@ out. Only existing branches can be selected."
(server-send-string client msg))))
;;; _
(define-obsolete-function-alias 'magit-git-string-p
#'magit-git-string "Magit 4.6.0")
(define-obsolete-function-alias 'magit-rev-verify-commit
#'magit-commit-p "Magit 4.6.0")
(define-obsolete-function-alias 'magit-rev-hash
#'magit-commit-p "Magit 4.6.0"
"Return oid for REV if it names an existing commit, nil otherwise.
Instead use `magit-commit-p' or `magit-commit-oid'.")
(define-obsolete-function-alias 'magit--abbrev-if-hash
#'magit--abbrev-if-oid "Magit 4.6.0")
(provide 'magit-git)
;; Local Variables:
;; read-symbol-shorthands: (
@@ -3000,6 +3066,7 @@ out. Only existing branches can be selected."
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")