config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

magit-git.el (124689B)


      1 ;;; magit-git.el --- Git functionality  -*- lexical-binding:t -*-
      2 
      3 ;; Copyright (C) 2008-2024 The Magit Project Contributors
      4 
      5 ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
      6 ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
      7 
      8 ;; SPDX-License-Identifier: GPL-3.0-or-later
      9 
     10 ;; Magit is free software: you can redistribute it and/or modify it
     11 ;; under the terms of the GNU General Public License as published by
     12 ;; the Free Software Foundation, either version 3 of the License, or
     13 ;; (at your option) any later version.
     14 ;;
     15 ;; Magit is distributed in the hope that it will be useful, but WITHOUT
     16 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     17 ;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     18 ;; License for more details.
     19 ;;
     20 ;; You should have received a copy of the GNU General Public License
     21 ;; along with Magit.  If not, see <https://www.gnu.org/licenses/>.
     22 
     23 ;;; Commentary:
     24 
     25 ;; This library implements wrappers for various Git plumbing commands.
     26 
     27 ;;; Code:
     28 
     29 (require 'magit-base)
     30 
     31 (require 'format-spec)
     32 
     33 ;; From `magit-branch'.
     34 (defvar magit-branch-prefer-remote-upstream)
     35 (defvar magit-published-branches)
     36 
     37 ;; From `magit-margin'.
     38 (declare-function magit-maybe-make-margin-overlay "magit-margin" ())
     39 
     40 ;; From `magit-mode'.
     41 (declare-function magit-get-mode-buffer "magit-mode"
     42                   (mode &optional value frame))
     43 (declare-function magit-refresh "magit-mode" ())
     44 (defvar magit-buffer-diff-type)
     45 (defvar magit-buffer-diff-args)
     46 (defvar magit-buffer-file-name)
     47 (defvar magit-buffer-log-args)
     48 (defvar magit-buffer-log-files)
     49 (defvar magit-buffer-refname)
     50 (defvar magit-buffer-revision)
     51 
     52 ;; From `magit-process'.
     53 (declare-function magit-call-git "magit-process" (&rest args))
     54 (declare-function magit-git "magit-process" (&rest args))
     55 (declare-function magit-process-buffer "magit-process" (&optional nodisplay))
     56 (declare-function magit-process-file "magit-process"
     57                   (process &optional infile buffer display &rest args))
     58 (declare-function magit-process-finish-section "magit-process"
     59                   (section exit-code))
     60 (declare-function magit-process-git "magit-process" (destination &rest args))
     61 (declare-function magit-process-insert-section "magit-process"
     62                   (pwd program args &optional errcode errlog face))
     63 (defvar magit-this-error)
     64 (defvar magit-process-error-message-regexps)
     65 
     66 (eval-when-compile
     67   (cl-pushnew 'orig-rev eieio--known-slot-names)
     68   (cl-pushnew 'number eieio--known-slot-names))
     69 
     70 ;;; Options
     71 
     72 ;; For now this is shared between `magit-process' and `magit-git'.
     73 (defgroup magit-process nil
     74   "Git and other external processes used by Magit."
     75   :group 'magit)
     76 
     77 (defvar magit-git-environment
     78   (list (format "INSIDE_EMACS=%s,magit" emacs-version))
     79   "Prepended to `process-environment' while running git.")
     80 
     81 (defcustom magit-git-output-coding-system
     82   (and (eq system-type 'windows-nt) 'utf-8)
     83   "Coding system for receiving output from Git.
     84 
     85 If non-nil, the Git config value `i18n.logOutputEncoding' should
     86 be set via `magit-git-global-arguments' to value consistent with
     87 this."
     88   :package-version '(magit . "2.9.0")
     89   :group 'magit-process
     90   :type '(choice (coding-system :tag "Coding system to decode Git output")
     91                  (const :tag "Use system default" nil)))
     92 
     93 (defvar magit-git-w32-path-hack nil
     94   "Alist of (EXE . (PATHENTRY)).
     95 This specifies what additional PATH setting needs to be added to
     96 the environment in order to run the non-wrapper git executables
     97 successfully.")
     98 
     99 (defcustom magit-git-executable
    100   (or (and (eq system-type 'windows-nt)
    101            ;; Avoid the wrappers "cmd/git.exe" and "cmd/git.cmd",
    102            ;; which are much slower than using "bin/git.exe" directly.
    103            (and-let* ((exec (executable-find "git")))
    104              (ignore-errors
    105                ;; Git for Windows 2.x provides cygpath so we can
    106                ;; ask it for native paths.
    107                (let* ((core-exe
    108                        (car
    109                         (process-lines
    110                          exec "-c"
    111                          "alias.X=!x() { which \"$1\" | cygpath -mf -; }; x"
    112                          "X" "git")))
    113                       (hack-entry (assoc core-exe magit-git-w32-path-hack))
    114                       ;; Running the libexec/git-core executable
    115                       ;; requires some extra PATH entries.
    116                       (path-hack
    117                        (list (concat "PATH="
    118                                      (car (process-lines
    119                                            exec "-c"
    120                                            "alias.P=!cygpath -wp \"$PATH\""
    121                                            "P"))))))
    122                  ;; The defcustom STANDARD expression can be
    123                  ;; evaluated many times, so make sure it is
    124                  ;; idempotent.
    125                  (if hack-entry
    126                      (setcdr hack-entry path-hack)
    127                    (push (cons core-exe path-hack) magit-git-w32-path-hack))
    128                  core-exe))))
    129       (and (eq system-type 'darwin)
    130            (executable-find "git"))
    131       "git")
    132   "The Git executable used by Magit on the local host.
    133 On remote machines `magit-remote-git-executable' is used instead."
    134   :package-version '(magit . "3.2.0")
    135   :group 'magit-process
    136   :type 'string)
    137 
    138 (defcustom magit-remote-git-executable "git"
    139   "The Git executable used by Magit on remote machines.
    140 On the local host `magit-git-executable' is used instead.
    141 Consider customizing `tramp-remote-path' instead of this
    142 option."
    143   :package-version '(magit . "3.2.0")
    144   :group 'magit-process
    145   :type 'string)
    146 
    147 (defcustom magit-git-global-arguments
    148   `("--no-pager" "--literal-pathspecs"
    149     "-c" "core.preloadindex=true"
    150     "-c" "log.showSignature=false"
    151     "-c" "color.ui=false"
    152     "-c" "color.diff=false"
    153     ,@(and (eq system-type 'windows-nt)
    154            (list "-c" "i18n.logOutputEncoding=UTF-8")))
    155   "Global Git arguments.
    156 
    157 The arguments set here are used every time the git executable is
    158 run as a subprocess.  They are placed right after the executable
    159 itself and before the git command - as in `git HERE... COMMAND
    160 REST'.  See the manpage `git(1)' for valid arguments.
    161 
    162 Be careful what you add here, especially if you are using Tramp
    163 to connect to servers with ancient Git versions.  Never remove
    164 anything that is part of the default value, unless you really
    165 know what you are doing.  And think very hard before adding
    166 something; it will be used every time Magit runs Git for any
    167 purpose."
    168   :package-version '(magit . "2.9.0")
    169   :group 'magit-commands
    170   :group 'magit-process
    171   :type '(repeat string))
    172 
    173 (defcustom magit-prefer-remote-upstream nil
    174   "Whether to favor remote branches when reading the upstream branch.
    175 
    176 This controls whether commands that read a branch from the user
    177 and then set it as the upstream branch, offer a local or a remote
    178 branch as default completion candidate, when they have the choice.
    179 
    180 This affects all commands that use `magit-read-upstream-branch'
    181 or `magit-read-starting-point', which includes most commands
    182 that change the upstream and many that create new branches."
    183   :package-version '(magit . "2.4.2")
    184   :group 'magit-commands
    185   :type 'boolean)
    186 
    187 (defcustom magit-list-refs-namespaces
    188   '("refs/heads"
    189     "refs/remotes"
    190     "refs/tags"
    191     "refs/pullreqs")
    192   "List of ref namespaces considered when reading a ref.
    193 
    194 This controls the order of refs returned by `magit-list-refs',
    195 which is called by functions like `magit-list-branch-names' to
    196 generate the collection of refs."
    197   :package-version '(magit . "3.1.0")
    198   :group 'magit-commands
    199   :type '(repeat string))
    200 
    201 (defcustom magit-list-refs-sortby nil
    202   "How to sort the ref collection in the prompt.
    203 
    204 This affects commands that read a ref.  More specifically, it
    205 controls the order of refs returned by `magit-list-refs', which
    206 is called by functions like `magit-list-branch-names' to generate
    207 the collection of refs.  By default, refs are sorted according to
    208 their full refname (i.e., \"refs/...\").
    209 
    210 Any value accepted by the `--sort' flag of \"git for-each-ref\" can
    211 be used.  For example, \"-creatordate\" places refs with more
    212 recent committer or tagger dates earlier in the list.  A list of
    213 strings can also be given in order to pass multiple sort keys to
    214 \"git for-each-ref\".
    215 
    216 Note that, depending on the completion framework you use, this
    217 may not be sufficient to change the order in which the refs are
    218 displayed.  It only controls the order of the collection passed
    219 to `magit-completing-read' or, for commands that support reading
    220 multiple strings, `read-from-minibuffer'.  The completion
    221 framework ultimately determines how the collection is displayed."
    222   :package-version '(magit . "2.11.0")
    223   :group 'magit-miscellaneous
    224   :type '(choice string (repeat string)))
    225 
    226 ;;; Git
    227 
    228 (defvar magit-git-debug nil
    229   "Whether to enable additional reporting of git errors.
    230 
    231 Magit basically calls git for one of these two reasons: for
    232 side-effects or to do something with its standard output.
    233 
    234 When git is run for side-effects then its output, including error
    235 messages, go into the process buffer which is shown when using \
    236 \\<magit-status-mode-map>\\[magit-process-buffer].
    237 
    238 When git's output is consumed in some way, then it would be too
    239 expensive to also insert it into this buffer, but when this
    240 option is non-nil and git returns with a non-zero exit status,
    241 then at least its standard error is inserted into this buffer.
    242 
    243 This is only intended for debugging purposes.  Do not enable this
    244 permanently, that would negatively affect performance.  Also note
    245 that just because git exits with a non-zero exit status and prints
    246 an error message that usually doesn't mean that it is an error as
    247 far as Magit is concerned, which is another reason we usually hide
    248 these error messages.  Whether some error message is relevant in
    249 the context of some unexpected behavior has to be judged on a case
    250 by case basis.
    251 
    252 The command `magit-toggle-git-debug' changes the value of this
    253 variable.
    254 
    255 Also see `magit-process-extreme-logging'.")
    256 
    257 (defun magit-toggle-git-debug ()
    258   "Toggle whether additional git errors are reported.
    259 See info node `(magit)Debugging Tools' for more information."
    260   (interactive)
    261   (setq magit-git-debug (not magit-git-debug))
    262   (message "Additional reporting of Git errors %s"
    263            (if magit-git-debug "enabled" "disabled")))
    264 
    265 (defvar magit--refresh-cache nil)
    266 
    267 (defmacro magit--with-refresh-cache (key &rest body)
    268   (declare (indent 1) (debug (form body)))
    269   (let ((k (cl-gensym))
    270         (hit (cl-gensym)))
    271     `(if magit--refresh-cache
    272          (let ((,k ,key))
    273            (if-let ((,hit (assoc ,k (cdr magit--refresh-cache))))
    274                (progn (cl-incf (caar magit--refresh-cache))
    275                       (cdr ,hit))
    276              (cl-incf (cdar magit--refresh-cache))
    277              (let ((value ,(macroexp-progn body)))
    278                (push (cons ,k value)
    279                      (cdr magit--refresh-cache))
    280                value)))
    281        ,@body)))
    282 
    283 (defvar magit-with-editor-envvar "GIT_EDITOR"
    284   "The environment variable exported by `magit-with-editor'.
    285 Set this to \"GIT_SEQUENCE_EDITOR\" if you do not want to use
    286 Emacs to edit commit messages but would like to do so to edit
    287 rebase sequences.")
    288 
    289 (defmacro magit-with-editor (&rest body)
    290   "Like `with-editor*' but let-bind some more variables.
    291 Also respect the value of `magit-with-editor-envvar'."
    292   (declare (indent 0) (debug (body)))
    293   `(let ((magit-process-popup-time -1)
    294          ;; The user may have customized `shell-file-name' to
    295          ;; something which results in `w32-shell-dos-semantics' nil
    296          ;; (which changes the quoting style used by
    297          ;; `shell-quote-argument'), but Git for Windows expects shell
    298          ;; quoting in the dos style.
    299          (shell-file-name (if (and (eq system-type 'windows-nt)
    300                                    ;; If we have Cygwin mount points,
    301                                    ;; the git flavor is cygwin, so dos
    302                                    ;; shell quoting is probably wrong.
    303                                    (not magit-cygwin-mount-points))
    304                               "cmdproxy"
    305                             shell-file-name)))
    306      (with-editor* magit-with-editor-envvar
    307        ,@body)))
    308 
    309 (defmacro magit--with-temp-process-buffer (&rest body)
    310   "Like `with-temp-buffer', but always propagate `process-environment'.
    311 When that var is buffer-local in the calling buffer, it is not
    312 propagated by `with-temp-buffer', so we explicitly ensure that
    313 happens, so that processes will be invoked consistently.  BODY is
    314 as for that macro."
    315   (declare (indent 0) (debug (body)))
    316   (let ((p (cl-gensym)))
    317     `(let ((,p process-environment))
    318        (with-temp-buffer
    319          (setq-local process-environment ,p)
    320          ,@body))))
    321 
    322 (defsubst magit-git-executable ()
    323   "Return value of `magit-git-executable' or `magit-remote-git-executable'.
    324 The variable is chosen depending on whether `default-directory'
    325 is remote."
    326   (if (file-remote-p default-directory)
    327       magit-remote-git-executable
    328     magit-git-executable))
    329 
    330 (defun magit-process-git-arguments (args)
    331   "Prepare ARGS for a function that invokes Git.
    332 
    333 Magit has many specialized functions for running Git; they all
    334 pass arguments through this function before handing them to Git,
    335 to do the following.
    336 
    337 * Flatten ARGS, removing nil arguments.
    338 * Prepend `magit-git-global-arguments' to ARGS.
    339 * On w32 systems, encode to `w32-ansi-code-page'."
    340   (setq args (append magit-git-global-arguments (flatten-tree args)))
    341   (if (and (eq system-type 'windows-nt) (boundp 'w32-ansi-code-page))
    342       ;; On w32, the process arguments *must* be encoded in the
    343       ;; current code-page (see #3250).
    344       (mapcar (lambda (arg)
    345                 (encode-coding-string
    346                  arg (intern (format "cp%d" w32-ansi-code-page))))
    347               args)
    348     args))
    349 
    350 (defun magit-git-exit-code (&rest args)
    351   "Execute Git with ARGS, returning its exit code."
    352   (magit-process-git nil args))
    353 
    354 (defun magit-git-success (&rest args)
    355   "Execute Git with ARGS, returning t if its exit code is 0."
    356   (= (magit-git-exit-code args) 0))
    357 
    358 (defun magit-git-failure (&rest args)
    359   "Execute Git with ARGS, returning t if its exit code is 1."
    360   (= (magit-git-exit-code args) 1))
    361 
    362 (defun magit-git-string-p (&rest args)
    363   "Execute Git with ARGS, returning the first line of its output.
    364 If the exit code isn't zero or if there is no output, then return
    365 nil.  Neither of these results is considered an error; if that is
    366 what you want, then use `magit-git-string-ng' instead.
    367 
    368 This is an experimental replacement for `magit-git-string', and
    369 still subject to major changes."
    370   (magit--with-refresh-cache (cons default-directory args)
    371     (magit--with-temp-process-buffer
    372       (and (zerop (magit-process-git t args))
    373            (not (bobp))
    374            (progn
    375              (goto-char (point-min))
    376              (buffer-substring-no-properties (point) (line-end-position)))))))
    377 
    378 (defun magit-git-string-ng (&rest args)
    379   "Execute Git with ARGS, returning the first line of its output.
    380 If the exit code isn't zero or if there is no output, then that
    381 is considered an error, but instead of actually signaling an
    382 error, return nil.  Additionally the output is put in the process
    383 buffer (creating it if necessary) and the error message is shown
    384 in the status buffer (provided it exists).
    385 
    386 This is an experimental replacement for `magit-git-string', and
    387 still subject to major changes.  Also see `magit-git-string-p'."
    388   (magit--with-refresh-cache
    389       (list default-directory 'magit-git-string-ng args)
    390     (magit--with-temp-process-buffer
    391       (let* ((args (magit-process-git-arguments args))
    392              (status (magit-process-git t args)))
    393         (if (zerop status)
    394             (and (not (bobp))
    395                  (progn
    396                    (goto-char (point-min))
    397                    (buffer-substring-no-properties
    398                     (point) (line-end-position))))
    399           (let ((buf (current-buffer)))
    400             (with-current-buffer (magit-process-buffer t)
    401               (magit-process-insert-section default-directory
    402                                             magit-git-executable args
    403                                             status buf
    404                                             'magit-section-secondary-heading)))
    405           (when-let ((status-buf (magit-get-mode-buffer 'magit-status-mode)))
    406             (let ((msg (magit--locate-error-message)))
    407               (with-current-buffer status-buf
    408                 (setq magit-this-error msg))))
    409           nil)))))
    410 
    411 (defun magit-git-str (&rest args)
    412   "Execute Git with ARGS, returning the first line of its output.
    413 If there is no output, return nil.  If the output begins with a
    414 newline, return an empty string.  Like `magit-git-string' but
    415 ignore `magit-git-debug'."
    416   (setq args (flatten-tree args))
    417   (magit--with-refresh-cache (cons default-directory args)
    418     (magit--with-temp-process-buffer
    419       (magit-process-git (list t nil) args)
    420       (unless (bobp)
    421         (goto-char (point-min))
    422         (buffer-substring-no-properties (point) (line-end-position))))))
    423 
    424 (defun magit-git-output (&rest args)
    425   "Execute Git with ARGS, returning its output."
    426   (setq args (flatten-tree args))
    427   (magit--with-refresh-cache (cons default-directory args)
    428     (magit--with-temp-process-buffer
    429       (magit-process-git (list t nil) args)
    430       (buffer-substring-no-properties (point-min) (point-max)))))
    431 
    432 (define-error 'magit-invalid-git-boolean "Not a Git boolean")
    433 
    434 (defun magit-git-true (&rest args)
    435   "Execute Git with ARGS, returning t if it prints \"true\".
    436 If it prints \"false\", then return nil.  For any other output
    437 signal `magit-invalid-git-boolean'."
    438   (pcase (magit-git-output args)
    439     ((or "true"  "true\n")  t)
    440     ((or "false" "false\n") nil)
    441     (output (signal 'magit-invalid-git-boolean (list output)))))
    442 
    443 (defun magit-git-false (&rest args)
    444   "Execute Git with ARGS, returning t if it prints \"false\".
    445 If it prints \"true\", then return nil.  For any other output
    446 signal `magit-invalid-git-boolean'."
    447   (pcase (magit-git-output args)
    448     ((or "true"  "true\n")  nil)
    449     ((or "false" "false\n") t)
    450     (output (signal 'magit-invalid-git-boolean (list output)))))
    451 
    452 (defun magit-git-config-p (variable &optional default)
    453   "Return the boolean value of the Git variable VARIABLE.
    454 VARIABLE has to be specified as a string.  Return DEFAULT (which
    455 defaults to nil) if VARIABLE is unset.  If VARIABLE's value isn't
    456 a boolean, then raise an error."
    457   (let ((args (list "config" "--bool" "--default" (if default "true" "false")
    458                     variable)))
    459     (magit--with-refresh-cache (cons default-directory args)
    460       (magit--with-temp-process-buffer
    461         (let ((status (magit-process-git t args))
    462               (output (buffer-substring (point-min) (1- (point-max)))))
    463           (if (zerop status)
    464               (equal output "true")
    465             (signal 'magit-invalid-git-boolean (list output))))))))
    466 
    467 (defun magit-git-insert (&rest args)
    468   "Execute Git with ARGS, insert stdout at point and return exit code.
    469 If `magit-git-debug' in non-nil and the exit code is non-zero, then
    470 insert the run command and stderr into the process buffer."
    471   (apply #'magit--git-insert nil args))
    472 
    473 (defun magit--git-insert (return-error &rest args)
    474   (setq args (flatten-tree args))
    475   (if (or return-error magit-git-debug)
    476       (let (log)
    477         (unwind-protect
    478             (let (exit errmsg)
    479               (setq log (make-temp-file "magit-stderr"))
    480               (delete-file log)
    481               (setq exit (magit-process-git (list t log) args))
    482               (when (or (> exit 0) (eq magit-git-debug 'all))
    483                 (when (file-exists-p log)
    484                   (with-temp-buffer
    485                     (insert-file-contents log)
    486                     (goto-char (point-max))
    487                     (setq errmsg
    488                           (if (functionp magit-git-debug)
    489                               (funcall magit-git-debug (buffer-string))
    490                             (magit--locate-error-message))))
    491                   (when magit-git-debug
    492                     (let ((magit-git-debug nil))
    493                       (with-current-buffer (magit-process-buffer t)
    494                         (magit-process-finish-section
    495                          (magit-process-insert-section
    496                           default-directory magit-git-executable
    497                           (magit-process-git-arguments args)
    498                           exit log 'magit-section-secondary-heading)
    499                          exit)))))
    500                 (cond ((not magit-git-debug))
    501                       (errmsg (message "%s" errmsg))
    502                       ((zerop exit))
    503                       ((message "Git returned with exit-code %s" exit))))
    504               (or errmsg exit))
    505           (ignore-errors (delete-file log))))
    506     (magit-process-git (list t nil) args)))
    507 
    508 (defun magit--locate-error-message ()
    509   (goto-char (point-max))
    510   (and (run-hook-wrapped 'magit-process-error-message-regexps
    511                          (lambda (re) (re-search-backward re nil t)))
    512        (match-string-no-properties 1)))
    513 
    514 (defun magit-git-string (&rest args)
    515   "Execute Git with ARGS, returning the first line of its output.
    516 If there is no output, return nil.  If the output begins with a
    517 newline, return an empty string."
    518   (setq args (flatten-tree args))
    519   (magit--with-refresh-cache (cons default-directory args)
    520     (magit--with-temp-process-buffer
    521       (apply #'magit-git-insert args)
    522       (unless (bobp)
    523         (goto-char (point-min))
    524         (buffer-substring-no-properties (point) (line-end-position))))))
    525 
    526 (defun magit-git-lines (&rest args)
    527   "Execute Git with ARGS, returning its output as a list of lines.
    528 Empty lines anywhere in the output are omitted.
    529 
    530 If Git exits with a non-zero exit status, then report show a
    531 message and add a section in the respective process buffer."
    532   (magit--with-temp-process-buffer
    533     (apply #'magit-git-insert args)
    534     (split-string (buffer-string) "\n" t)))
    535 
    536 (defun magit-git-items (&rest args)
    537   "Execute Git with ARGS, returning its null-separated output as a list.
    538 Empty items anywhere in the output are omitted.
    539 
    540 If Git exits with a non-zero exit status, then report show a
    541 message and add a section in the respective process buffer."
    542   (magit--with-temp-process-buffer
    543     (apply #'magit-git-insert args)
    544     (split-string (buffer-string) "\0" t)))
    545 
    546 (defvar magit--git-wash-keep-error nil) ; experimental
    547 
    548 (defun magit-git-wash (washer &rest args)
    549   "Execute Git with ARGS, inserting washed output at point.
    550 Actually first insert the raw output at point.  If there is no
    551 output, call `magit-cancel-section'.  Otherwise temporarily narrow
    552 the buffer to the inserted text, move to its beginning, and then
    553 call function WASHER with ARGS as its sole argument."
    554   (declare (indent 1))
    555   (apply #'magit--git-wash washer magit--git-wash-keep-error args))
    556 
    557 (defun magit--git-wash (washer keep-error &rest args)
    558   (declare (indent 2))
    559   (setq args (flatten-tree args))
    560   (let ((beg (point))
    561         (exit (magit--git-insert keep-error args)))
    562     (when (stringp exit)
    563       (goto-char beg)
    564       (insert (propertize exit 'face 'error))
    565       (unless (bolp)
    566         (insert "\n")))
    567     (if (= (point) beg)
    568         (magit-cancel-section)
    569       (unless (bolp)
    570         (insert "\n"))
    571       (when (or (equal exit 0)
    572                 (eq keep-error 'wash-anyway))
    573         (save-restriction
    574           (narrow-to-region beg (point))
    575           (goto-char beg)
    576           (funcall washer args))
    577         (when (or (= (point) beg)
    578                   (= (point) (1+ beg)))
    579           (magit-cancel-section))
    580         (magit-maybe-make-margin-overlay)))
    581     exit))
    582 
    583 (defun magit-git-executable-find (command)
    584   "Search for COMMAND in Git's exec path, falling back to `exec-path'.
    585 Like `executable-find', return the absolute file name of the
    586 executable."
    587   (or (locate-file command
    588                    (list (concat
    589                           (file-remote-p default-directory)
    590                           (or (magit-git-string "--exec-path")
    591                               (error "`git --exec-path' failed"))))
    592                    exec-suffixes
    593                    #'file-executable-p)
    594       (compat-call executable-find command t)))
    595 
    596 ;;; Git Version
    597 
    598 (defconst magit--git-version-regexp
    599   "\\`git version \\([0-9]+\\(\\.[0-9]+\\)\\{1,2\\}\\)")
    600 
    601 (defvar magit--host-git-version-cache nil)
    602 
    603 (defun magit-git-version>= (n)
    604   "Return t if `magit-git-version's value is greater than or equal to N."
    605   (magit--version>= (magit-git-version) n))
    606 
    607 (defun magit-git-version< (n)
    608   "Return t if `magit-git-version's value is smaller than N."
    609   (version< (magit-git-version) n))
    610 
    611 (defun magit-git-version ()
    612   "Return the Git version used for `default-directory'.
    613 Raise an error if Git cannot be found, if it exits with a
    614 non-zero status, or the output does not have the expected
    615 format."
    616   (magit--with-refresh-cache default-directory
    617     (let ((host (file-remote-p default-directory)))
    618       (or (cdr (assoc host magit--host-git-version-cache))
    619           (magit--with-temp-process-buffer
    620             ;; Unset global arguments for ancient Git versions.
    621             (let* ((magit-git-global-arguments nil)
    622                    (status (magit-process-git t "version"))
    623                    (output (buffer-string)))
    624               (cond
    625                ((not (zerop status))
    626                 (display-warning
    627                  'magit
    628                  (format "%S\n\nRunning \"%s --version\" failed with output:\n\n%s"
    629                          (if host
    630                              (format "Magit cannot find Git on host %S.\n
    631 Check the value of `magit-remote-git-executable' using
    632 `magit-debug-git-executable' and consult the info node
    633 `(tramp)Remote programs'." host)
    634                            "Magit cannot find Git.\n
    635 Check the values of `magit-git-executable' and `exec-path'
    636 using `magit-debug-git-executable'.")
    637                          (magit-git-executable)
    638                          output)))
    639                ((save-match-data
    640                   (and (string-match magit--git-version-regexp output)
    641                        (let ((version (match-string 1 output)))
    642                          (push (cons host version)
    643                                magit--host-git-version-cache)
    644                          version))))
    645                ((error "Unexpected \"%s --version\" output: %S"
    646                        (magit-git-executable)
    647                        output)))))))))
    648 
    649 (defun magit-git-version-assert (&optional minimal who)
    650   "Assert that the used Git version is greater than or equal to MINIMAL.
    651 If optional MINIMAL is nil, compare with `magit--minimal-git'
    652 instead.  Optional WHO if non-nil specifies what functionality
    653 needs at least MINIMAL, otherwise it defaults to \"Magit\"."
    654   (when (magit-git-version< (or minimal magit--minimal-git))
    655     (let* ((host (file-remote-p default-directory))
    656            (msg (format-spec
    657                  (cond (host "\
    658 %w requires Git %m or greater, but on %h the version is %v.
    659 
    660 If multiple Git versions are installed on the host, then the
    661 problem might be that TRAMP uses the wrong executable.
    662 
    663 Check the value of `magit-remote-git-executable' and consult
    664 the info node `(tramp)Remote programs'.\n")
    665                        (t "\
    666 %w requires Git %m or greater, but you are using %v.
    667 
    668 If you have multiple Git versions installed, then check the
    669 values of `magit-remote-git-executable' and `exec-path'.\n"))
    670                  `((?w . ,(or who "Magit"))
    671                    (?m . ,(or minimal magit--minimal-git))
    672                    (?v . ,(magit-git-version))
    673                    (?h . ,host)))))
    674       (display-warning 'magit msg :error))))
    675 
    676 (defun magit--safe-git-version ()
    677   "Return the Git version used for `default-directory' or an error message."
    678   (magit--with-temp-process-buffer
    679     (let* ((magit-git-global-arguments nil)
    680            (status (magit-process-git t "version"))
    681            (output (buffer-string)))
    682       (cond ((not (zerop status)) output)
    683             ((save-match-data
    684                (and (string-match magit--git-version-regexp output)
    685                     (match-string 1 output))))
    686             (t output)))))
    687 
    688 (defun magit-debug-git-executable ()
    689   "Display a buffer with information about `magit-git-executable'.
    690 Also include information about `magit-remote-git-executable'.
    691 See info node `(magit)Debugging Tools' for more information."
    692   (interactive)
    693   (with-current-buffer (get-buffer-create "*magit-git-debug*")
    694     (pop-to-buffer (current-buffer))
    695     (erase-buffer)
    696     (insert (format "magit-remote-git-executable: %S\n"
    697                     magit-remote-git-executable))
    698     (insert (concat
    699              (format "magit-git-executable: %S" magit-git-executable)
    700              (and (not (file-name-absolute-p magit-git-executable))
    701                   (format " [%S]" (executable-find magit-git-executable)))
    702              (format " (%s)\n" (magit--safe-git-version))))
    703     (insert (format "exec-path: %S\n" exec-path))
    704     (when-let ((diff (cl-set-difference
    705                       (seq-filter #'file-exists-p (remq nil (parse-colon-path
    706                                                              (getenv "PATH"))))
    707                       (seq-filter #'file-exists-p (remq nil exec-path))
    708                       :test #'file-equal-p)))
    709       (insert (format "  entries in PATH, but not in exec-path: %S\n" diff)))
    710     (dolist (execdir exec-path)
    711       (insert (format "  %s (%s)\n" execdir (car (file-attributes execdir))))
    712       (when (file-directory-p execdir)
    713         (dolist (exec (directory-files
    714                        execdir t (concat
    715                                   "\\`git" (regexp-opt exec-suffixes) "\\'")))
    716           (insert (format "    %s (%s)\n" exec
    717                           (magit--safe-git-version))))))))
    718 
    719 ;;; Variables
    720 
    721 (defun magit-config-get-from-cached-list (key)
    722   (gethash
    723    ;; `git config --list' downcases first and last components of the key.
    724    (let* ((key (replace-regexp-in-string "\\`[^.]+" #'downcase key t t))
    725           (key (replace-regexp-in-string "[^.]+\\'" #'downcase key t t)))
    726      key)
    727    (magit--with-refresh-cache (cons (magit-toplevel) 'config)
    728      (let ((configs (make-hash-table :test #'equal)))
    729        (dolist (conf (magit-git-items "config" "--list" "-z"))
    730          (let* ((nl-pos (cl-position ?\n conf))
    731                 (key (substring conf 0 nl-pos))
    732                 (val (if nl-pos (substring conf (1+ nl-pos)) "")))
    733            (puthash key (nconc (gethash key configs) (list val)) configs)))
    734        configs))))
    735 
    736 (defun magit-get (&rest keys)
    737   "Return the value of the Git variable specified by KEYS."
    738   (car (last (apply #'magit-get-all keys))))
    739 
    740 (defun magit-get-all (&rest keys)
    741   "Return all values of the Git variable specified by KEYS."
    742   (let ((magit-git-debug nil)
    743         (arg (and (or (null (car keys))
    744                       (string-prefix-p "--" (car keys)))
    745                   (pop keys)))
    746         (key (string-join keys ".")))
    747     (if (and magit--refresh-cache (not arg))
    748         (magit-config-get-from-cached-list key)
    749       (magit-git-items "config" arg "-z" "--get-all" "--include" key))))
    750 
    751 (defun magit-get-boolean (&rest keys)
    752   "Return the boolean value of the Git variable specified by KEYS.
    753 Also see `magit-git-config-p'."
    754   (let ((arg (and (or (null (car keys))
    755                       (string-prefix-p "--" (car keys)))
    756                   (pop keys)))
    757         (key (string-join keys ".")))
    758     (equal (if magit--refresh-cache
    759                (car (last (magit-config-get-from-cached-list key)))
    760              (magit-git-str "config" arg "--bool" "--include" key))
    761            "true")))
    762 
    763 (defun magit-set (value &rest keys)
    764   "Set the value of the Git variable specified by KEYS to VALUE."
    765   (let ((arg (and (or (null (car keys))
    766                       (string-prefix-p "--" (car keys)))
    767                   (pop keys)))
    768         (key (string-join keys ".")))
    769     (if value
    770         (magit-git-success "config" arg key value)
    771       (magit-git-success "config" arg "--unset" key))
    772     value))
    773 
    774 (gv-define-setter magit-get (val &rest keys)
    775   `(magit-set ,val ,@keys))
    776 
    777 (defun magit-set-all (values &rest keys)
    778   "Set all values of the Git variable specified by KEYS to VALUES."
    779   (let ((arg (and (or (null (car keys))
    780                       (string-prefix-p "--" (car keys)))
    781                   (pop keys)))
    782         (var (string-join keys ".")))
    783     (when (magit-get var)
    784       (magit-call-git "config" arg "--unset-all" var))
    785     (dolist (v values)
    786       (magit-call-git "config" arg "--add" var v))))
    787 
    788 ;;; Files
    789 
    790 (defun magit--safe-default-directory (&optional file)
    791   (catch 'unsafe-default-dir
    792     (let ((dir (file-name-as-directory
    793                 (expand-file-name (or file default-directory))))
    794           (previous nil))
    795       (while (not (file-accessible-directory-p dir))
    796         (setq dir (file-name-directory (directory-file-name dir)))
    797         (when (equal dir previous)
    798           (throw 'unsafe-default-dir nil))
    799         (setq previous dir))
    800       dir)))
    801 
    802 (defmacro magit--with-safe-default-directory (file &rest body)
    803   (declare (indent 1) (debug (form body)))
    804   `(when-let ((default-directory (magit--safe-default-directory ,file)))
    805      ,@body))
    806 
    807 (defun magit-git-dir (&optional path)
    808   "Like (expand-file-name PATH (magit-gitdir)) or just (magit-gitdir)."
    809   (declare (obsolete 'magit-gitdir "Magit 4.0.0"))
    810   (and-let* ((dir (magit-gitdir)))
    811     (if path
    812         (expand-file-name (convert-standard-filename path) dir)
    813       dir)))
    814 
    815 (defun magit-gitdir (&optional directory)
    816   "Return the absolute and resolved path of the .git directory.
    817 
    818 If the `GIT_DIR' environment variable is defined, return that.
    819 Otherwise return the .git directory for DIRECTORY, or if that is
    820 nil, then for `default-directory' instead.  If the directory is
    821 not located inside a Git repository, then return nil."
    822   (let ((default-directory (or directory default-directory)))
    823     (magit--with-refresh-cache (list default-directory 'magit-gitdir)
    824       (magit--with-safe-default-directory nil
    825         (and-let*
    826             ((dir (magit-rev-parse-safe "--git-dir"))
    827              (dir (file-name-as-directory (magit-expand-git-file-name dir))))
    828           (if (file-remote-p dir)
    829               dir
    830             (concat (file-remote-p default-directory) dir)))))))
    831 
    832 (defvar magit--separated-gitdirs nil)
    833 
    834 (defun magit--record-separated-gitdir ()
    835   (let ((topdir (magit-toplevel))
    836         (gitdir (magit-gitdir)))
    837     ;; Kludge: git-annex converts submodule gitdirs to symlinks. See #3599.
    838     (when (file-symlink-p (directory-file-name gitdir))
    839       (setq gitdir (file-truename gitdir)))
    840     ;; We want to delete the entry for `topdir' here, rather than within
    841     ;; (unless ...), in case a `--separate-git-dir' repository was switched to
    842     ;; the standard structure (i.e., "topdir/.git/").
    843     (setq magit--separated-gitdirs (cl-delete topdir
    844                                               magit--separated-gitdirs
    845                                               :key #'car :test #'equal))
    846     (unless (equal (file-name-as-directory (expand-file-name ".git" topdir))
    847                    gitdir)
    848       (push (cons topdir gitdir) magit--separated-gitdirs))))
    849 
    850 (defun magit-toplevel (&optional directory)
    851   "Return the absolute path to the toplevel of the current repository.
    852 
    853 From within the working tree or control directory of a repository
    854 return the absolute path to the toplevel directory of the working
    855 tree.  As a special case, from within a bare repository return
    856 the control directory instead.  When called outside a repository
    857 then return nil.
    858 
    859 When optional DIRECTORY is non-nil then return the toplevel for
    860 that directory instead of the one for `default-directory'.
    861 
    862 Try to respect the option `find-file-visit-truename', i.e.,  when
    863 the value of that option is nil, then avoid needlessly returning
    864 the truename.  When a symlink to a sub-directory of the working
    865 tree is involved, or when called from within a sub-directory of
    866 the gitdir or from the toplevel of a gitdir, which itself is not
    867 located within the working tree, then it is not possible to avoid
    868 returning the truename."
    869   (or
    870    (magit--with-refresh-cache
    871        (cons (or directory default-directory) 'magit-toplevel)
    872      (magit--with-safe-default-directory directory
    873        (if-let ((topdir (magit-rev-parse-safe "--show-toplevel")))
    874            (let (updir)
    875              (setq topdir (magit-expand-git-file-name topdir))
    876              (cond
    877               ((and
    878                 ;; Always honor these settings.
    879                 (not find-file-visit-truename)
    880                 (not (getenv "GIT_WORK_TREE"))
    881                 ;; `--show-cdup' is the relative path to the toplevel
    882                 ;; from `(file-truename default-directory)'.  Here we
    883                 ;; pretend it is relative to `default-directory', and
    884                 ;; go to that directory.  Then we check whether
    885                 ;; `--show-toplevel' still returns the same value and
    886                 ;; whether `--show-cdup' now is the empty string.  If
    887                 ;; both is the case, then we are at the toplevel of
    888                 ;; the same working tree, but also avoided needlessly
    889                 ;; following any symlinks.
    890                 (progn
    891                   (setq updir (file-name-as-directory
    892                                (magit-rev-parse-safe "--show-cdup")))
    893                   (setq updir (if (file-name-absolute-p updir)
    894                                   (concat (file-remote-p default-directory)
    895                                           updir)
    896                                 (expand-file-name updir)))
    897                   (and-let*
    898                       ((default-directory updir)
    899                        (top (and (string-equal
    900                                   (magit-rev-parse-safe "--show-cdup") "")
    901                                  (magit-rev-parse-safe "--show-toplevel"))))
    902                     (string-equal (magit-expand-git-file-name top) topdir))))
    903                updir)
    904               ((concat (file-remote-p default-directory)
    905                        (file-name-as-directory topdir)))))
    906          (and-let* ((gitdir (magit-rev-parse-safe "--git-dir"))
    907                     (gitdir (file-name-as-directory
    908                              (if (file-name-absolute-p gitdir)
    909                                  ;; We might have followed a symlink.
    910                                  (concat (file-remote-p default-directory)
    911                                          (magit-expand-git-file-name gitdir))
    912                                (expand-file-name gitdir)))))
    913            (if (magit-bare-repo-p)
    914                gitdir
    915              (let* ((link (expand-file-name "gitdir" gitdir))
    916                     (wtree (and (file-exists-p link)
    917                                 (magit-file-line link))))
    918                (cond
    919                 ((and wtree
    920                       ;; Ignore .git/gitdir files that result from a
    921                       ;; Git bug.  See #2364.
    922                       (not (equal wtree ".git")))
    923                  ;; Return the linked working tree.
    924                  (concat (file-remote-p default-directory)
    925                          (file-name-directory wtree)))
    926                 ;; The working directory may not be the parent
    927                 ;; directory of .git if it was set up with
    928                 ;; "git init --separate-git-dir".  See #2955.
    929                 ((car (rassoc gitdir magit--separated-gitdirs)))
    930                 (;; Step outside the control directory to enter the
    931                  ;; working tree.
    932                  (file-name-directory (directory-file-name gitdir))))))))))))
    933 
    934 (defun magit--toplevel-safe ()
    935   (or (magit-toplevel)
    936       (magit--not-inside-repository-error)))
    937 
    938 (defmacro magit-with-toplevel (&rest body)
    939   (declare (indent defun) (debug (body)))
    940   `(let ((default-directory (magit--toplevel-safe)))
    941      ,@body))
    942 
    943 (define-error 'magit-outside-git-repo "Not inside Git repository")
    944 (define-error 'magit-corrupt-git-config "Corrupt Git configuration")
    945 (define-error 'magit-git-executable-not-found
    946               (concat "Git executable cannot be found "
    947                       "(see https://magit.vc/goto/e6a78ed2)"))
    948 
    949 (defun magit--assert-usable-git ()
    950   (if (not (compat-call executable-find (magit-git-executable) t))
    951       (signal 'magit-git-executable-not-found (magit-git-executable))
    952     (let ((magit-git-debug
    953            (lambda (err)
    954              (signal 'magit-corrupt-git-config
    955                      (format "%s: %s" default-directory err)))))
    956       ;; This should always succeed unless there's a corrupt config
    957       ;; (or at least a similarly severe failing state).  Note that
    958       ;; git-config's --default is avoided because it's not available
    959       ;; until Git 2.18.
    960       (magit-git-string "config" "--get-color" "" "reset"))
    961     nil))
    962 
    963 (defun magit--not-inside-repository-error ()
    964   (magit--assert-usable-git)
    965   (signal 'magit-outside-git-repo default-directory))
    966 
    967 (defun magit-inside-gitdir-p (&optional noerror)
    968   "Return t if `default-directory' is below the repository directory.
    969 If it is below the working directory, then return nil.
    970 If it isn't below either, then signal an error unless NOERROR
    971 is non-nil, in which case return nil."
    972   (and (magit--assert-default-directory noerror)
    973        ;; Below a repository directory that is not located below the
    974        ;; working directory "git rev-parse --is-inside-git-dir" prints
    975        ;; "false", which is wrong.
    976        (let ((gitdir (magit-gitdir)))
    977          (cond (gitdir (file-in-directory-p default-directory gitdir))
    978                (noerror nil)
    979                ((signal 'magit-outside-git-repo default-directory))))))
    980 
    981 (defun magit-inside-worktree-p (&optional noerror)
    982   "Return t if `default-directory' is below the working directory.
    983 If it is below the repository directory, then return nil.
    984 If it isn't below either, then signal an error unless NOERROR
    985 is non-nil, in which case return nil."
    986   (and (magit--assert-default-directory noerror)
    987        (condition-case nil
    988            (magit-rev-parse-true "--is-inside-work-tree")
    989          (magit-invalid-git-boolean
    990           (and (not noerror)
    991                (signal 'magit-outside-git-repo default-directory))))))
    992 
    993 (cl-defgeneric magit-bare-repo-p (&optional noerror)
    994   "Return t if the current repository is bare.
    995 If it is non-bare, then return nil.  If `default-directory'
    996 isn't below a Git repository, then signal an error unless
    997 NOERROR is non-nil, in which case return nil."
    998   (and (magit--assert-default-directory noerror)
    999        (condition-case nil
   1000            (magit-rev-parse-true "--is-bare-repository")
   1001          (magit-invalid-git-boolean
   1002           (and (not noerror)
   1003                (signal 'magit-outside-git-repo default-directory))))))
   1004 
   1005 (defun magit--assert-default-directory (&optional noerror)
   1006   (or (file-directory-p default-directory)
   1007       (and (not noerror)
   1008            (let ((exists (file-exists-p default-directory)))
   1009              (signal (if exists 'file-error 'file-missing)
   1010                      (list "Running git in directory"
   1011                            (if exists
   1012                                "Not a directory"
   1013                              "No such file or directory")
   1014                            default-directory))))))
   1015 
   1016 (defun magit-git-repo-p (directory &optional non-bare)
   1017   "Return t if DIRECTORY is a Git repository.
   1018 When optional NON-BARE is non-nil also return nil if DIRECTORY is
   1019 a bare repository."
   1020   (and (file-directory-p directory) ; Avoid archives, see #3397.
   1021        (or (file-regular-p (expand-file-name ".git" directory))
   1022            (file-directory-p (expand-file-name ".git" directory))
   1023            (and (not non-bare)
   1024                 (file-regular-p (expand-file-name "HEAD" directory))
   1025                 (file-directory-p (expand-file-name "refs" directory))
   1026                 (file-directory-p (expand-file-name "objects" directory))))))
   1027 
   1028 (defun magit-file-relative-name (&optional file tracked)
   1029   "Return the path of FILE relative to the repository root.
   1030 
   1031 If optional FILE is nil or omitted, return the relative path of
   1032 the file being visited in the current buffer, if any, else nil.
   1033 If the file is not inside a Git repository, then return nil.
   1034 
   1035 If TRACKED is non-nil, return the path only if it matches a
   1036 tracked file."
   1037   (unless file
   1038     (with-current-buffer (or (buffer-base-buffer)
   1039                              (current-buffer))
   1040       (setq file (or magit-buffer-file-name buffer-file-name
   1041                      (and (derived-mode-p 'dired-mode) default-directory)))))
   1042   (when (and file (or (not tracked)
   1043                       (magit-file-tracked-p (file-relative-name file))))
   1044     (and-let* ((dir (magit-toplevel
   1045                      (magit--safe-default-directory
   1046                       (directory-file-name (file-name-directory file))))))
   1047       (file-relative-name file dir))))
   1048 
   1049 (defun magit-file-ignored-p (file)
   1050   (magit-git-string-p "ls-files" "--others" "--ignored" "--exclude-standard"
   1051                       "--" (magit-convert-filename-for-git file)))
   1052 
   1053 (defun magit-file-tracked-p (file)
   1054   (magit-git-success "ls-files" "--error-unmatch"
   1055                      "--" (magit-convert-filename-for-git file)))
   1056 
   1057 (defun magit-list-files (&rest args)
   1058   (apply #'magit-git-items "ls-files" "-z" "--full-name" args))
   1059 
   1060 (defun magit-tracked-files ()
   1061   (magit-list-files "--cached"))
   1062 
   1063 (defun magit-untracked-files (&optional all files compact)
   1064   (if compact
   1065       (--mapcat (and (eq (aref it 0) ??)
   1066                      (list (substring it 3)))
   1067                 (magit-git-items "status" "-z" "--porcelain"
   1068                                  (magit-ignore-submodules-p t)
   1069                                  "--" files))
   1070     (magit-list-files "--other"
   1071                       (and (not all) "--exclude-standard")
   1072                       "--" files)))
   1073 
   1074 (defun magit-modified-files (&optional nomodules files)
   1075   (magit-git-items "diff-index" "-z" "--name-only"
   1076                    ;; Work around a bug in Git v2.46.0. See #5212 and #5221.
   1077                    (if nomodules "--ignore-submodules" "--submodule=short")
   1078                    (magit-headish) "--" files))
   1079 
   1080 (defun magit-unstaged-files (&optional nomodules files)
   1081   (magit-git-items "diff-files" "-z" "--name-only" "--diff-filter=u"
   1082                    ;; Work around a bug in Git v2.46.0. See #5212 and #5221.
   1083                    (if nomodules "--ignore-submodules" "--submodule=short")
   1084                    "--" files))
   1085 
   1086 (defun magit-staged-files (&optional nomodules files)
   1087   (magit-git-items "diff-index" "-z" "--name-only" "--cached"
   1088                    ;; Work around a bug in Git v2.46.0. See #5212 and #5221.
   1089                    (if nomodules "--ignore-submodules" "--submodule=short")
   1090                    (magit-headish) "--" files))
   1091 
   1092 (defun magit-binary-files (&rest args)
   1093   (--mapcat (and (string-match "^-\t-\t\\(.+\\)" it)
   1094                  (list (match-string 1 it)))
   1095             (apply #'magit-git-items
   1096                    "diff" "-z" "--numstat" "--ignore-submodules"
   1097                    args)))
   1098 
   1099 (defun magit-unmerged-files ()
   1100   (magit-git-items "diff-files" "-z" "--name-only" "--diff-filter=U"))
   1101 
   1102 (defun magit-ignored-files ()
   1103   (magit-git-items "ls-files" "-z" "--others" "--ignored"
   1104                    "--exclude-standard" "--directory"))
   1105 
   1106 (defun magit-stashed-files (stash)
   1107   (magit-git-items "stash" "show" "-z" "--name-only" stash))
   1108 
   1109 (defun magit-skip-worktree-files ()
   1110   (--keep (and (= (aref it 0) ?S)
   1111                (substring it 2))
   1112           (magit-list-files "-t")))
   1113 
   1114 (defun magit-assume-unchanged-files ()
   1115   (--keep (and (memq (aref it 0) '(?h ?s ?m ?r ?c ?k))
   1116                (substring it 2))
   1117           (magit-list-files "-v")))
   1118 
   1119 (defun magit-revision-files (rev)
   1120   (magit-with-toplevel
   1121     (magit-git-items "ls-tree" "-z" "-r" "--name-only" rev)))
   1122 
   1123 (defun magit-revision-directories (rev)
   1124   "List directories that contain a tracked file in revision REV."
   1125   (magit-with-toplevel
   1126     (mapcar #'file-name-as-directory
   1127             (magit-git-items "ls-tree" "-z" "-r" "-d" "--name-only" rev))))
   1128 
   1129 (defun magit-changed-files (rev-or-range &optional other-rev)
   1130   "Return list of files the have changed between two revisions.
   1131 If OTHER-REV is non-nil, REV-OR-RANGE should be a revision, not a
   1132 range.  Otherwise, it can be any revision or range accepted by
   1133 \"git diff\" (i.e., <rev>, <revA>..<revB>, or <revA>...<revB>)."
   1134   (magit-with-toplevel
   1135     (magit-git-items "diff" "-z" "--name-only" rev-or-range other-rev)))
   1136 
   1137 (defun magit-renamed-files (revA revB)
   1138   (mapcar (pcase-lambda (`(,_status ,fileA ,fileB))
   1139             (cons fileA fileB))
   1140           (seq-partition (magit-git-items "diff" "-z" "--name-status"
   1141                                           "--find-renames"
   1142                                           "--diff-filter=R" revA revB)
   1143                          3)))
   1144 
   1145 (defun magit--rev-file-name (file rev other-rev)
   1146   "For FILE, potentially renamed between REV and OTHER-REV, return name in REV.
   1147 Return nil, if FILE appears neither in REV nor OTHER-REV,
   1148 or if no rename is detected."
   1149   (or (car (member file (magit-revision-files rev)))
   1150       (and-let* ((renamed (magit-renamed-files rev other-rev)))
   1151         (car (rassoc file renamed)))))
   1152 
   1153 (defun magit-file-status (&rest args)
   1154   (magit--with-temp-process-buffer
   1155     (save-excursion (magit-git-insert "status" "-z" args))
   1156     (let ((pos (point)) status)
   1157       (while (> (skip-chars-forward "[:print:]") 0)
   1158         (let ((x (char-after     pos))
   1159               (y (char-after (1+ pos)))
   1160               (file (buffer-substring (+ pos 3) (point))))
   1161           (forward-char)
   1162           (if (memq x '(?R ?C))
   1163               (progn
   1164                 (setq pos (point))
   1165                 (skip-chars-forward "[:print:]")
   1166                 (push (list file (buffer-substring pos (point)) x y) status)
   1167                 (forward-char))
   1168             (push (list file nil x y) status)))
   1169         (setq pos (point)))
   1170       status)))
   1171 
   1172 (defcustom magit-cygwin-mount-points
   1173   (and (eq system-type 'windows-nt)
   1174        (cl-sort (--map (if (string-match "^\\(.*\\) on \\(.*\\) type" it)
   1175                            (cons (file-name-as-directory (match-string 2 it))
   1176                                  (file-name-as-directory (match-string 1 it)))
   1177                          (lwarn '(magit) :error
   1178                                 "Failed to parse Cygwin mount: %S" it))
   1179                        ;; If --exec-path is not a native Windows path,
   1180                        ;; then we probably have a cygwin git.
   1181                        (let ((process-environment
   1182                               (append magit-git-environment
   1183                                       process-environment)))
   1184                          (and (not (string-match-p
   1185                                     "\\`[a-zA-Z]:"
   1186                                     (car (process-lines
   1187                                           magit-git-executable "--exec-path"))))
   1188                               (ignore-errors (process-lines "mount")))))
   1189                 #'> :key (pcase-lambda (`(,cyg . ,_win)) (length cyg))))
   1190   "Alist of (CYGWIN . WIN32) directory names.
   1191 Sorted from longest to shortest CYGWIN name."
   1192   :package-version '(magit . "2.3.0")
   1193   :group 'magit-process
   1194   :type '(alist :key-type string :value-type directory))
   1195 
   1196 (defun magit-expand-git-file-name (filename)
   1197   (unless (file-name-absolute-p filename)
   1198     (setq filename (expand-file-name filename)))
   1199   (if-let ((cyg:win (and (not (file-remote-p default-directory)) ; see #4976
   1200                          (cl-assoc filename magit-cygwin-mount-points
   1201                                    :test (lambda (f cyg) (string-prefix-p cyg f))))))
   1202       (concat (cdr cyg:win)
   1203               (substring filename (length (car cyg:win))))
   1204     filename))
   1205 
   1206 (defun magit-convert-filename-for-git (filename)
   1207   "Convert FILENAME so that it can be passed to git.
   1208 1. If it is a absolute filename, then pass it through
   1209    `expand-file-name' to replace things such as \"~/\" that
   1210    Git does not understand.
   1211 2. If it is a remote filename, then remove the remote part.
   1212 3. Deal with an `windows-nt' Emacs vs. Cygwin Git incompatibility."
   1213   (if (file-name-absolute-p filename)
   1214       (if-let ((cyg:win (cl-rassoc filename magit-cygwin-mount-points
   1215                                    :test (lambda (f win) (string-prefix-p win f)))))
   1216           (concat (car cyg:win)
   1217                   (substring filename (length (cdr cyg:win))))
   1218         (let ((expanded (expand-file-name filename)))
   1219           (or (file-remote-p expanded 'localname)
   1220               expanded)))
   1221     filename))
   1222 
   1223 (defun magit-decode-git-path (path)
   1224   (if (eq (aref path 0) ?\")
   1225       (decode-coding-string (read path)
   1226                             (or magit-git-output-coding-system
   1227                                 (car default-process-coding-system))
   1228                             t)
   1229     path))
   1230 
   1231 (defun magit-file-at-point (&optional expand assert)
   1232   (if-let ((file (magit-section-case
   1233                    (file (oref it value))
   1234                    (hunk (magit-section-parent-value it)))))
   1235       (if expand
   1236           (expand-file-name file (magit-toplevel))
   1237         file)
   1238     (when assert
   1239       (user-error "No file at point"))))
   1240 
   1241 (defun magit-current-file ()
   1242   (or (magit-file-relative-name)
   1243       (magit-file-at-point)
   1244       (and (derived-mode-p 'magit-log-mode)
   1245            (car magit-buffer-log-files))))
   1246 
   1247 ;;; Predicates
   1248 
   1249 (defun magit-no-commit-p ()
   1250   "Return t if there is no commit in the current Git repository."
   1251   (not (magit-rev-verify "HEAD")))
   1252 
   1253 (defun magit-merge-commit-p (commit)
   1254   "Return t if COMMIT is a merge commit."
   1255   (length> (magit-commit-parents commit) 1))
   1256 
   1257 (defun magit-anything-staged-p (&optional ignore-submodules &rest files)
   1258   "Return t if there are any staged changes.
   1259 If optional FILES is non-nil, then only changes to those files
   1260 are considered."
   1261   (magit-git-failure "diff" "--quiet" "--cached"
   1262                      (if ignore-submodules
   1263                          "--ignore-submodules"
   1264                        ;; Work around a bug in Git v2.46.0. See #5212 and #5221.
   1265                        "--submodule=short")
   1266                      "--" files))
   1267 
   1268 (defun magit-anything-unstaged-p (&optional ignore-submodules &rest files)
   1269   "Return t if there are any unstaged changes.
   1270 If optional FILES is non-nil, then only changes to those files
   1271 are considered."
   1272   (magit-git-failure "diff" "--quiet"
   1273                      (if ignore-submodules
   1274                          "--ignore-submodules"
   1275                        ;; Work around a bug in Git v2.46.0. See #5212 and #5221.
   1276                        "--submodule=short")
   1277                      "--" files))
   1278 
   1279 (defun magit-anything-modified-p (&optional ignore-submodules &rest files)
   1280   "Return t if there are any staged or unstaged changes.
   1281 If optional FILES is non-nil, then only changes to those files
   1282 are considered."
   1283   (or (apply #'magit-anything-staged-p   ignore-submodules files)
   1284       (apply #'magit-anything-unstaged-p ignore-submodules files)))
   1285 
   1286 (defun magit-anything-unmerged-p (&rest files)
   1287   "Return t if there are any merge conflicts.
   1288 If optional FILES is non-nil, then only conflicts in those files
   1289 are considered."
   1290   (and (magit-git-string "ls-files" "--unmerged" files) t))
   1291 
   1292 (defun magit-module-worktree-p (module)
   1293   (magit-with-toplevel
   1294     (file-exists-p (expand-file-name ".git" module))))
   1295 
   1296 (defun magit-module-no-worktree-p (module)
   1297   (not (magit-module-worktree-p module)))
   1298 
   1299 (defun magit-ignore-submodules-p (&optional return-argument)
   1300   (or (cl-find-if (lambda (arg)
   1301                     (string-prefix-p "--ignore-submodules" arg))
   1302                   magit-buffer-diff-args)
   1303       (and-let* ((value (magit-get "diff.ignoreSubmodules")))
   1304         (if return-argument
   1305             (concat "--ignore-submodules=" value)
   1306           (concat "diff.ignoreSubmodules=" value)))))
   1307 
   1308 ;;; Revisions and References
   1309 
   1310 (defun magit-rev-parse (&rest args)
   1311   "Execute `git rev-parse ARGS', returning first line of output.
   1312 If there is no output, return nil."
   1313   (apply #'magit-git-string "rev-parse" args))
   1314 
   1315 (defun magit-rev-parse-safe (&rest args)
   1316   "Execute `git rev-parse ARGS', returning first line of output.
   1317 If there is no output, return nil.  Like `magit-rev-parse' but
   1318 ignore `magit-git-debug'."
   1319   (apply #'magit-git-str "rev-parse" args))
   1320 
   1321 (defun magit-rev-parse-true (&rest args)
   1322   "Execute `git rev-parse ARGS', returning t if it prints \"true\".
   1323 If it prints \"false\", then return nil.  For any other output
   1324 signal an error."
   1325   (magit-git-true "rev-parse" args))
   1326 
   1327 (defun magit-rev-parse-false (&rest args)
   1328   "Execute `git rev-parse ARGS', returning t if it prints \"false\".
   1329 If it prints \"true\", then return nil.  For any other output
   1330 signal an error."
   1331   (magit-git-false "rev-parse" args))
   1332 
   1333 (defun magit-rev-parse-p (&rest args)
   1334   "Execute `git rev-parse ARGS', returning t if it prints \"true\".
   1335 Return t if the first (and usually only) output line is the
   1336 string \"true\", otherwise return nil."
   1337   (equal (magit-git-str "rev-parse" args) "true"))
   1338 
   1339 (defun magit-rev-verify (rev)
   1340   (magit-git-string-p "rev-parse" "--verify" rev))
   1341 
   1342 (defun magit-commit-p (rev)
   1343   "Return full hash for REV if it names an existing commit."
   1344   (magit-rev-verify (magit--rev-dereference rev)))
   1345 
   1346 (defalias 'magit-rev-verify-commit #'magit-commit-p)
   1347 
   1348 (defalias 'magit-rev-hash #'magit-commit-p)
   1349 
   1350 (defun magit--rev-dereference (rev)
   1351   "Return a rev that forces Git to interpret REV as a commit.
   1352 If REV is nil or has the form \":/TEXT\", return REV itself."
   1353   (cond ((not rev) nil)
   1354         ((string-match-p "^:/" rev) rev)
   1355         ((concat rev "^{commit}"))))
   1356 
   1357 (defun magit-rev-equal (a b)
   1358   "Return t if there are no differences between the commits A and B."
   1359   (magit-git-success "diff" "--quiet" a b))
   1360 
   1361 (defun magit-rev-eq (a b)
   1362   "Return t if A and B refer to the same commit."
   1363   (let ((a (magit-commit-p a))
   1364         (b (magit-commit-p b)))
   1365     (and a b (equal a b))))
   1366 
   1367 (defun magit-rev-ancestor-p (a b)
   1368   "Return non-nil if commit A is an ancestor of commit B."
   1369   (magit-git-success "merge-base" "--is-ancestor" a b))
   1370 
   1371 (defun magit-rev-head-p (rev)
   1372   (or (equal rev "HEAD")
   1373       (and rev
   1374            (not (string-search ".." rev))
   1375            (equal (magit-rev-parse rev)
   1376                   (magit-rev-parse "HEAD")))))
   1377 
   1378 (defun magit-rev-author-p (rev)
   1379   "Return t if the user is the author of REV.
   1380 More precisely return t if `user.name' is equal to the author
   1381 name of REV and/or `user.email' is equal to the author email
   1382 of REV."
   1383   (or (equal (magit-get "user.name")  (magit-rev-format "%an" rev))
   1384       (equal (magit-get "user.email") (magit-rev-format "%ae" rev))))
   1385 
   1386 (defun magit-rev-name (rev &optional pattern not-anchored)
   1387   "Return a symbolic name for REV using `git-name-rev'.
   1388 
   1389 PATTERN can be used to limit the result to a matching ref.
   1390 Unless NOT-ANCHORED is non-nil, the beginning of the ref must
   1391 match PATTERN.
   1392 
   1393 An anchored lookup is done using the arguments
   1394 \"--exclude=*/<PATTERN> --exclude=*/HEAD\" in addition to
   1395 \"--refs=<PATTERN>\", provided at least version v2.13 of Git is
   1396 used.  Older versions did not support the \"--exclude\" argument.
   1397 When \"--exclude\" cannot be used and `git-name-rev' returns a
   1398 ref that should have been excluded, then that is discarded and
   1399 this function returns nil instead.  This is unfortunate because
   1400 there might be other refs that do match.  To fix that, update
   1401 Git."
   1402   (if (magit-git-version< "2.13")
   1403       (and-let*
   1404           ((ref (magit-git-string "name-rev" "--name-only" "--no-undefined"
   1405                                   (and pattern (concat "--refs=" pattern))
   1406                                   rev)))
   1407         (if (and pattern
   1408                  (string-match-p "\\`refs/[^/]+/\\*\\'" pattern))
   1409             (let ((namespace (substring pattern 0 -1)))
   1410               (and (not (or (string-suffix-p "HEAD" ref)
   1411                             (and (string-match-p namespace ref)
   1412                                  (not (magit-rev-verify
   1413                                        (concat namespace ref))))))
   1414                    ref))
   1415           ref))
   1416     (magit-git-string "name-rev" "--name-only" "--no-undefined"
   1417                       (and pattern (concat "--refs=" pattern))
   1418                       (and pattern
   1419                            (not not-anchored)
   1420                            (list "--exclude=*/HEAD"
   1421                                  (concat "--exclude=*/" pattern)))
   1422                       rev)))
   1423 
   1424 (defun magit-rev-branch (rev)
   1425   (and-let* ((name (magit-rev-name rev "refs/heads/*")))
   1426     (and (not (string-match-p "[~^]" name)) name)))
   1427 
   1428 (defun magit-rev-fixup-target (rev)
   1429   (let ((msg (magit-rev-format "%s" rev)))
   1430     (save-match-data
   1431       (and (string-match "\\`\\(fixup\\|squash\\)! \\(.+\\)" msg)
   1432            (magit-rev-format
   1433             "%h" (format "%s^{/^%s}" rev
   1434                          (magit--ext-regexp-quote (match-string 2 msg))))))))
   1435 
   1436 (defun magit-get-shortname (rev)
   1437   (let* ((fn (apply-partially #'magit-rev-name rev))
   1438          (name (or (funcall fn "refs/tags/*")
   1439                    (funcall fn "refs/heads/*")
   1440                    (funcall fn "refs/remotes/*"))))
   1441     (cond ((not name)
   1442            (magit-rev-parse "--short" rev))
   1443           ((string-match "^\\(?:tags\\|remotes\\)/\\(.+\\)" name)
   1444            (if (magit-ref-ambiguous-p (match-string 1 name))
   1445                name
   1446              (match-string 1 name)))
   1447           ((magit-ref-maybe-qualify name)))))
   1448 
   1449 (defun magit-name-branch (rev &optional lax)
   1450   (or (magit-name-local-branch rev)
   1451       (magit-name-remote-branch rev)
   1452       (and lax (or (magit-name-local-branch rev t)
   1453                    (magit-name-remote-branch rev t)))))
   1454 
   1455 (defun magit-name-local-branch (rev &optional lax)
   1456   (and-let* ((name (magit-rev-name rev "refs/heads/*")))
   1457     (and (or lax (not (string-match-p "[~^]" name))) name)))
   1458 
   1459 (defun magit-name-remote-branch (rev &optional lax)
   1460   (and-let* ((name (magit-rev-name rev "refs/remotes/*")))
   1461     (and (or lax (not (string-match-p "[~^]" name)))
   1462          (substring name 8))))
   1463 
   1464 (defun magit-name-tag (rev &optional lax)
   1465   (and-let* ((name (magit-rev-name rev "refs/tags/*")))
   1466     ;; The progn is necessary to work around debbugs#31840.  This, and all
   1467     ;; the other instances, can be removed once we require at least Emacs 27.
   1468     (progn
   1469       (when (string-suffix-p "^0" name)
   1470         (setq name (substring name 0 -2)))
   1471       (and (or lax (not (string-match-p "[~^]" name)))
   1472            (substring name 5)))))
   1473 
   1474 (defun magit-ref-abbrev (refname)
   1475   "Return an unambiguous abbreviation of REFNAME."
   1476   (magit-rev-parse "--verify" "--abbrev-ref" refname))
   1477 
   1478 (defun magit-ref-fullname (refname)
   1479   "Return fully qualified refname for REFNAME.
   1480 If REFNAME is ambiguous, return nil."
   1481   (magit-rev-parse "--verify" "--symbolic-full-name" refname))
   1482 
   1483 (defun magit-ref-ambiguous-p (refname)
   1484   (save-match-data
   1485     (if (string-match "\\`\\([^^~]+\\)\\(.*\\)" refname)
   1486         (not (magit-ref-fullname (match-string 1 refname)))
   1487       (error "%S has an unrecognized format" refname))))
   1488 
   1489 (defun magit-ref-maybe-qualify (refname &optional prefix)
   1490   "If REFNAME is ambiguous, try to disambiguate it by prepend PREFIX to it.
   1491 Return an unambiguous refname, either REFNAME or that prefixed
   1492 with PREFIX, nil otherwise.  If REFNAME has an offset suffix
   1493 such as \"~1\", then that is preserved.  If optional PREFIX is
   1494 nil, then use \"heads/\".  "
   1495   (if (magit-ref-ambiguous-p refname)
   1496       (let ((refname (concat (or prefix "heads/") refname)))
   1497         (and (not (magit-ref-ambiguous-p refname)) refname))
   1498     refname))
   1499 
   1500 (defun magit-ref-exists-p (ref)
   1501   (magit-git-success "show-ref" "--verify" ref))
   1502 
   1503 (defun magit-ref-equal (a b)
   1504   "Return t if the refnames A and B are `equal'.
   1505 A symbolic-ref pointing to some ref, is `equal' to that ref,
   1506 as are two symbolic-refs pointing to the same ref.  Refnames
   1507 may be abbreviated."
   1508   (let ((a (magit-ref-fullname a))
   1509         (b (magit-ref-fullname b)))
   1510     (and a b (equal a b))))
   1511 
   1512 (defun magit-ref-eq (a b)
   1513   "Return t if the refnames A and B are `eq'.
   1514 A symbolic-ref is `eq' to itself, but not to the ref it points
   1515 to, or to some other symbolic-ref that points to the same ref."
   1516   (let ((symbolic-a (magit-symbolic-ref-p a))
   1517         (symbolic-b (magit-symbolic-ref-p b)))
   1518     (or (and symbolic-a
   1519              symbolic-b
   1520              (equal a b))
   1521         (and (not symbolic-a)
   1522              (not symbolic-b)
   1523              (magit-ref-equal a b)))))
   1524 
   1525 (defun magit-headish ()
   1526   "Return the `HEAD' or if that doesn't exist the hash of the empty tree."
   1527   (if (magit-no-commit-p)
   1528       (magit-git-string "mktree")
   1529     "HEAD"))
   1530 
   1531 (defun magit-branch-at-point ()
   1532   (magit-section-case
   1533     (branch (oref it value))
   1534     (commit (or (magit--painted-branch-at-point)
   1535                 (magit-name-branch (oref it value))))))
   1536 
   1537 (defun magit--painted-branch-at-point (&optional type)
   1538   (or (and (not (eq type 'remote))
   1539            (memq (get-text-property (magit-point) 'font-lock-face)
   1540                  (list 'magit-branch-local
   1541                        'magit-branch-current))
   1542            (and-let* ((branch (magit-thing-at-point 'git-revision t)))
   1543              (cdr (magit-split-branch-name branch))))
   1544       (and (not (eq type 'local))
   1545            (memq (get-text-property (magit-point) 'font-lock-face)
   1546                  (list 'magit-branch-remote
   1547                        'magit-branch-remote-head))
   1548            (thing-at-point 'git-revision t))))
   1549 
   1550 (defun magit-local-branch-at-point ()
   1551   (magit-section-case
   1552     (branch (let ((branch (magit-ref-maybe-qualify (oref it value))))
   1553               (when (member branch (magit-list-local-branch-names))
   1554                 branch)))
   1555     (commit (or (magit--painted-branch-at-point 'local)
   1556                 (magit-name-local-branch (oref it value))))))
   1557 
   1558 (defun magit-remote-branch-at-point ()
   1559   (magit-section-case
   1560     (branch (let ((branch (oref it value)))
   1561               (when (member branch (magit-list-remote-branch-names))
   1562                 branch)))
   1563     (commit (or (magit--painted-branch-at-point 'remote)
   1564                 (magit-name-remote-branch (oref it value))))))
   1565 
   1566 (defun magit-commit-at-point ()
   1567   (or (magit-section-value-if 'commit)
   1568       (magit-thing-at-point 'git-revision t)
   1569       (and-let* ((chunk (and (bound-and-true-p magit-blame-mode)
   1570                              (fboundp 'magit-current-blame-chunk)
   1571                              (magit-current-blame-chunk))))
   1572         (oref chunk orig-rev))
   1573       (and (derived-mode-p 'magit-stash-mode
   1574                            'magit-merge-preview-mode
   1575                            'magit-revision-mode)
   1576            magit-buffer-revision)))
   1577 
   1578 (defun magit-branch-or-commit-at-point ()
   1579   (or (magit-section-case
   1580         (branch (magit-ref-maybe-qualify (oref it value)))
   1581         (commit (or (magit--painted-branch-at-point)
   1582                     (let ((rev (oref it value)))
   1583                       (or (magit-name-branch rev) rev))))
   1584         (tag (magit-ref-maybe-qualify (oref it value) "tags/"))
   1585         (pullreq (or (and (fboundp 'forge--pullreq-branch)
   1586                           (magit-branch-p
   1587                            (forge--pullreq-branch (oref it value))))
   1588                      (magit-ref-p (format "refs/pullreqs/%s"
   1589                                           (oref (oref it value) number)))))
   1590         ((unpulled unpushed)
   1591          (magit-ref-abbrev
   1592           (replace-regexp-in-string "\\.\\.\\.?" "" (oref it value)))))
   1593       (magit-thing-at-point 'git-revision t)
   1594       (and-let* ((chunk (and (bound-and-true-p magit-blame-mode)
   1595                              (fboundp 'magit-current-blame-chunk)
   1596                              (magit-current-blame-chunk))))
   1597         (oref chunk orig-rev))
   1598       (and magit-buffer-file-name
   1599            magit-buffer-refname)
   1600       (and (derived-mode-p 'magit-stash-mode
   1601                            'magit-merge-preview-mode
   1602                            'magit-revision-mode)
   1603            magit-buffer-revision)))
   1604 
   1605 (defun magit-tag-at-point ()
   1606   (magit-section-case
   1607     (tag    (oref it value))
   1608     (commit (magit-name-tag (oref it value)))))
   1609 
   1610 (defun magit-stash-at-point ()
   1611   (magit-section-value-if 'stash))
   1612 
   1613 (defun magit-remote-at-point ()
   1614   (magit-section-case
   1615     (remote (oref it value))
   1616     ([branch remote] (magit-section-parent-value it))))
   1617 
   1618 (defun magit-module-at-point (&optional predicate)
   1619   (when (magit-section-match 'module)
   1620     (let ((module (oref (magit-current-section) value)))
   1621       (and (or (not predicate)
   1622                (funcall predicate module))
   1623            module))))
   1624 
   1625 (defun magit-get-current-branch ()
   1626   "Return the refname of the currently checked out branch.
   1627 Return nil if no branch is currently checked out."
   1628   (magit-git-string "symbolic-ref" "--short" "HEAD"))
   1629 
   1630 (defvar magit-get-previous-branch-timeout 0.5
   1631   "Maximum time to spend in `magit-get-previous-branch'.
   1632 Given as a number of seconds.")
   1633 
   1634 (defun magit-get-previous-branch ()
   1635   "Return the refname of the previously checked out branch.
   1636 Return nil if no branch can be found in the `HEAD' reflog
   1637 which is different from the current branch and still exists.
   1638 The amount of time spent searching is limited by
   1639 `magit-get-previous-branch-timeout'."
   1640   (let ((t0 (float-time))
   1641         (current (magit-get-current-branch))
   1642         (i 1) prev)
   1643     (while (if (> (- (float-time) t0) magit-get-previous-branch-timeout)
   1644                (setq prev nil) ;; Timed out.
   1645              (and (setq prev (magit-rev-verify (format "@{-%d}" i)))
   1646                   (or (not (setq prev (magit-rev-branch prev)))
   1647                       (equal prev current))))
   1648       (cl-incf i))
   1649     prev))
   1650 
   1651 (defun magit--set-default-branch (newname oldname)
   1652   (let ((remote (or (magit-primary-remote)
   1653                     (user-error "Cannot determine primary remote")))
   1654         (branches (mapcar (lambda (line) (split-string line "\t"))
   1655                           (magit-git-lines
   1656                            "for-each-ref" "refs/heads"
   1657                            "--format=%(refname:short)\t%(upstream:short)"))))
   1658     (when-let ((old (assoc oldname branches))
   1659                ((not (assoc newname branches))))
   1660       (magit-call-git "branch" "-m" oldname newname)
   1661       (setcar old newname))
   1662     (let ((new (if (magit-branch-p newname)
   1663                    newname
   1664                  (concat remote "/" newname))))
   1665       (pcase-dolist (`(,branch ,upstream) branches)
   1666         (cond
   1667          ((equal upstream oldname)
   1668           (magit-set-upstream-branch branch new))
   1669          ((equal upstream (concat remote "/" oldname))
   1670           (magit-set-upstream-branch branch (concat remote "/" newname))))))))
   1671 
   1672 (defun magit--get-default-branch (&optional update)
   1673   (let ((remote (magit-primary-remote)))
   1674     (when update
   1675       (if (not remote)
   1676           (user-error "Cannot determine primary remote")
   1677         (message "Determining default branch...")
   1678         (magit-git "fetch" "--prune")
   1679         (magit-git "remote" "set-head" "--auto" remote)
   1680         (message "Determining default branch...done")))
   1681     (let ((branch (magit-git-string "symbolic-ref" "--short"
   1682                                     (format "refs/remotes/%s/HEAD" remote))))
   1683       (when (and update (not branch))
   1684         (error "Cannot determine new default branch"))
   1685       (list remote (and branch (cdr (magit-split-branch-name branch)))))))
   1686 
   1687 (defun magit-set-upstream-branch (branch upstream)
   1688   "Set UPSTREAM as the upstream of BRANCH.
   1689 If UPSTREAM is nil, then unset BRANCH's upstream.
   1690 Otherwise UPSTREAM has to be an existing branch."
   1691   (if upstream
   1692       (magit-call-git "branch" "--set-upstream-to" upstream branch)
   1693     (magit-call-git "branch" "--unset-upstream" branch)))
   1694 
   1695 (defun magit-get-upstream-ref (&optional branch)
   1696   "Return the upstream branch of BRANCH as a fully qualified ref.
   1697 It BRANCH is nil, then return the upstream of the current branch,
   1698 if any, nil otherwise.  If the upstream is not configured, the
   1699 configured remote is an url, or the named branch does not exist,
   1700 then return nil.  I.e.,  return an existing local or
   1701 remote-tracking branch ref."
   1702   (and-let* ((branch (or branch (magit-get-current-branch))))
   1703     (magit-ref-fullname (concat branch "@{upstream}"))))
   1704 
   1705 (defun magit-get-upstream-branch (&optional branch)
   1706   "Return the name of the upstream branch of BRANCH.
   1707 It BRANCH is nil, then return the upstream of the current branch
   1708 if any, nil otherwise.  If the upstream is not configured, the
   1709 configured remote is an url, or the named branch does not exist,
   1710 then return nil.  I.e., return the name of an existing local or
   1711 remote-tracking branch.  The returned string is colorized
   1712 according to the branch type."
   1713   (magit--with-refresh-cache
   1714       (list default-directory 'magit-get-upstream-branch branch)
   1715     (and-let* ((branch (or branch (magit-get-current-branch)))
   1716                (upstream (magit-ref-abbrev (concat branch "@{upstream}"))))
   1717       (magit--propertize-face
   1718        upstream (if (equal (magit-get "branch" branch "remote") ".")
   1719                     'magit-branch-local
   1720                   'magit-branch-remote)))))
   1721 
   1722 (defun magit-get-indirect-upstream-branch (branch &optional force)
   1723   (let ((remote (magit-get "branch" branch "remote")))
   1724     (and remote (not (equal remote "."))
   1725          ;; The user has opted in...
   1726          (or force
   1727              (--some (if (magit-git-success "check-ref-format" "--branch" it)
   1728                          (equal it branch)
   1729                        (string-match-p it branch))
   1730                      magit-branch-prefer-remote-upstream))
   1731          ;; and local BRANCH tracks a remote branch...
   1732          (let ((upstream (magit-get-upstream-branch branch)))
   1733            ;; whose upstream...
   1734            (and upstream
   1735                 ;; has the same name as BRANCH...
   1736                 (equal (substring upstream (1+ (length remote))) branch)
   1737                 ;; and can be fast-forwarded to BRANCH.
   1738                 (magit-rev-ancestor-p upstream branch)
   1739                 upstream)))))
   1740 
   1741 (defun magit-get-upstream-remote (&optional branch allow-unnamed)
   1742   (and-let* ((branch (or branch (magit-get-current-branch)))
   1743              (remote (magit-get "branch" branch "remote")))
   1744     (and (not (equal remote "."))
   1745          (cond ((member remote (magit-list-remotes))
   1746                 (magit--propertize-face remote 'magit-branch-remote))
   1747                ((and allow-unnamed
   1748                      (string-match-p "\\(\\`.\\{0,2\\}/\\|[:@]\\)" remote))
   1749                 (magit--propertize-face remote 'bold))))))
   1750 
   1751 (defun magit-get-unnamed-upstream (&optional branch)
   1752   (and-let* ((branch (or branch (magit-get-current-branch)))
   1753              (remote (magit-get "branch" branch "remote"))
   1754              (merge  (magit-get "branch" branch "merge")))
   1755     (and (magit--unnamed-upstream-p remote merge)
   1756          (list (magit--propertize-face remote 'bold)
   1757                (magit--propertize-face merge 'magit-branch-remote)))))
   1758 
   1759 (defun magit--unnamed-upstream-p (remote merge)
   1760   (and remote (string-match-p "\\(\\`\\.\\{0,2\\}/\\|[:@]\\)" remote)
   1761        merge  (string-prefix-p "refs/" merge)))
   1762 
   1763 (defun magit--valid-upstream-p (remote merge)
   1764   (and (or (equal remote ".")
   1765            (member remote (magit-list-remotes)))
   1766        (string-prefix-p "refs/" merge)))
   1767 
   1768 (defun magit-get-current-remote (&optional allow-unnamed)
   1769   (or (magit-get-upstream-remote nil allow-unnamed)
   1770       (and-let* ((remotes (magit-list-remotes))
   1771                  (remote (if (length= remotes 1)
   1772                              (car remotes)
   1773                            (magit-primary-remote))))
   1774         (magit--propertize-face remote 'magit-branch-remote))))
   1775 
   1776 (defun magit-get-push-remote (&optional branch)
   1777   (and-let* ((remote
   1778               (or (and (or branch (setq branch (magit-get-current-branch)))
   1779                        (magit-get "branch" branch "pushRemote"))
   1780                   (magit-get "remote.pushDefault"))))
   1781     (magit--propertize-face remote 'magit-branch-remote)))
   1782 
   1783 (defun magit-get-push-branch (&optional branch verify)
   1784   (magit--with-refresh-cache
   1785       (list default-directory 'magit-get-push-branch branch verify)
   1786     (and-let* ((branch (or branch (setq branch (magit-get-current-branch))))
   1787                (remote (magit-get-push-remote branch))
   1788                (target (concat remote "/" branch)))
   1789       (and (or (not verify)
   1790                (magit-rev-verify target))
   1791            (magit--propertize-face target 'magit-branch-remote)))))
   1792 
   1793 (defun magit-get-@{push}-branch (&optional branch)
   1794   (let ((ref (magit-rev-parse "--symbolic-full-name"
   1795                               (concat branch "@{push}"))))
   1796     (and ref
   1797          (string-prefix-p "refs/remotes/" ref)
   1798          (substring ref 13))))
   1799 
   1800 (defun magit-get-remote (&optional branch)
   1801   (and (or branch (setq branch (magit-get-current-branch)))
   1802        (let ((remote (magit-get "branch" branch "remote")))
   1803          (and (not (equal remote "."))
   1804               remote))))
   1805 
   1806 (defun magit-get-some-remote (&optional branch)
   1807   (or (magit-get-remote branch)
   1808       (and-let* ((main (magit-main-branch)))
   1809         (magit-get-remote main))
   1810       (magit-primary-remote)
   1811       (car (magit-list-remotes))))
   1812 
   1813 (defvar magit-primary-remote-names
   1814   '("upstream" "origin"))
   1815 
   1816 (defun magit-primary-remote ()
   1817   "Return the primary remote.
   1818 
   1819 The primary remote is the remote that tracks the repository that
   1820 other repositories are forked from.  It often is called \"origin\"
   1821 but because many people name their own fork \"origin\", using that
   1822 term would be ambiguous.  Likewise we avoid the term \"upstream\"
   1823 because a branch's @{upstream} branch may be a local branch or a
   1824 branch from a remote other than the primary remote.
   1825 
   1826 If a remote exists whose name matches `magit.primaryRemote', then
   1827 that is considered the primary remote.  If no remote by that name
   1828 exists, then remotes in `magit-primary-remote-names' are tried in
   1829 order and the first remote from that list that actually exists in
   1830 the current repository is considered its primary remote."
   1831   (let ((remotes (magit-list-remotes)))
   1832     (seq-find (lambda (name)
   1833                 (member name remotes))
   1834               (delete-dups
   1835                (delq nil
   1836                      (cons (magit-get "magit.primaryRemote")
   1837                            magit-primary-remote-names))))))
   1838 
   1839 (defun magit-branch-merged-p (branch &optional target)
   1840   "Return non-nil if BRANCH is merged into its upstream and TARGET.
   1841 
   1842 TARGET defaults to the current branch.  If `HEAD' is detached and
   1843 TARGET is nil, then always return nil.  As a special case, if
   1844 TARGET is t, then return non-nil if BRANCH is merged into any one
   1845 of the other local branches.
   1846 
   1847 If, and only if, BRANCH has an upstream, then only return non-nil
   1848 if BRANCH is merged into both TARGET (as described above) as well
   1849 as into its upstream."
   1850   (and (if-let ((upstream (and (magit-branch-p branch)
   1851                                (magit-get-upstream-branch branch))))
   1852            (magit-rev-ancestor-p branch upstream)
   1853          t)
   1854        (if (eq target t)
   1855            (delete (magit-name-local-branch branch)
   1856                    (magit-list-containing-branches branch))
   1857          (and-let* ((target (or target (magit-get-current-branch))))
   1858            (magit-rev-ancestor-p branch target)))))
   1859 
   1860 (defun magit-get-tracked (refname)
   1861   "Return the remote branch tracked by the remote-tracking branch REFNAME.
   1862 The returned value has the form (REMOTE . REF), where REMOTE is
   1863 the name of a remote and REF is the ref local to the remote."
   1864   (and-let* ((ref (magit-ref-fullname refname)))
   1865     (save-match-data
   1866       (seq-some (lambda (line)
   1867                   (and (string-match "\
   1868 \\`remote\\.\\([^.]+\\)\\.fetch=\\+?\\([^:]+\\):\\(.+\\)" line)
   1869                        (let ((rmt (match-string 1 line))
   1870                              (src (match-string 2 line))
   1871                              (dst (match-string 3 line)))
   1872                          (and (string-match (format "\\`%s\\'"
   1873                                                     (string-replace
   1874                                                      "*" "\\(.+\\)" dst))
   1875                                             ref)
   1876                               (cons rmt (string-replace
   1877                                          "*" (match-string 1 ref) src))))))
   1878                 (magit-git-lines "config" "--local" "--list")))))
   1879 
   1880 (defun magit-split-branch-name (branch)
   1881   (cond ((member branch (magit-list-local-branch-names))
   1882          (cons "." branch))
   1883         ((string-match "/" branch)
   1884          (or (seq-some (lambda (remote)
   1885                          (and (string-match
   1886                                (format "\\`\\(%s\\)/\\(.+\\)\\'" remote)
   1887                                branch)
   1888                               (cons (match-string 1 branch)
   1889                                     (match-string 2 branch))))
   1890                        (magit-list-remotes))
   1891              (error "Invalid branch name %s" branch)))))
   1892 
   1893 (defun magit-get-current-tag (&optional rev with-distance)
   1894   "Return the closest tag reachable from REV.
   1895 
   1896 If optional REV is nil, then default to `HEAD'.
   1897 If optional WITH-DISTANCE is non-nil then return (TAG COMMITS),
   1898 if it is `dirty' return (TAG COMMIT DIRTY). COMMITS is the number
   1899 of commits in `HEAD' but not in TAG and DIRTY is t if there are
   1900 uncommitted changes, nil otherwise."
   1901   (and-let* ((str (magit-git-str "describe" "--long" "--tags"
   1902                                  (and (eq with-distance 'dirty) "--dirty")
   1903                                  rev)))
   1904     (save-match-data
   1905       (string-match
   1906        "\\(.+\\)-\\(?:0[0-9]*\\|\\([0-9]+\\)\\)-g[0-9a-z]+\\(-dirty\\)?$" str)
   1907       (if with-distance
   1908           `(,(match-string 1 str)
   1909             ,(string-to-number (or (match-string 2 str) "0"))
   1910             ,@(and (match-string 3 str) (list t)))
   1911         (match-string 1 str)))))
   1912 
   1913 (defun magit-get-next-tag (&optional rev with-distance)
   1914   "Return the closest tag from which REV is reachable.
   1915 
   1916 If optional REV is nil, then default to `HEAD'.
   1917 If no such tag can be found or if the distance is 0 (in which
   1918 case it is the current tag, not the next), return nil instead.
   1919 If optional WITH-DISTANCE is non-nil, then return (TAG COMMITS)
   1920 where COMMITS is the number of commits in TAG but not in REV."
   1921   (and-let* ((str (magit-git-str "describe" "--contains" (or rev "HEAD"))))
   1922     (save-match-data
   1923       (when (string-match "^[^^~]+" str)
   1924         (setq str (match-string 0 str))
   1925         (unless (equal str (magit-get-current-tag rev))
   1926           (if with-distance
   1927               (list str (car (magit-rev-diff-count str rev)))
   1928             str))))))
   1929 
   1930 (defun magit-list-refs (&optional namespaces format sortby)
   1931   "Return list of references, excluding symbolic references.
   1932 
   1933 When NAMESPACES is non-nil, list refs from these namespaces
   1934 rather than those from `magit-list-refs-namespaces'.
   1935 
   1936 FORMAT is passed to the `--format' flag of `git for-each-ref'
   1937 and defaults to \"%(refname)\".
   1938 
   1939 SORTBY is a key or list of keys to pass to the `--sort' flag of
   1940 `git for-each-ref'.  When nil, use `magit-list-refs-sortby'"
   1941   (unless format
   1942     (setq format "%(refname)"))
   1943   (seq-keep (lambda (line)
   1944               (pcase-let* ((`(,symrefp ,value)
   1945                             (split-string line ""))
   1946                            (symrefp (not (equal symrefp ""))))
   1947                 (and (not symrefp) value)))
   1948             (magit-git-lines "for-each-ref"
   1949                              (concat "--format=%(symref)" format)
   1950                              (--map (concat "--sort=" it)
   1951                                     (pcase (or sortby magit-list-refs-sortby)
   1952                                       ((and val (pred stringp)) (list val))
   1953                                       ((and val (pred listp)) val)))
   1954                              (or namespaces magit-list-refs-namespaces))))
   1955 
   1956 (defun magit-list-branches ()
   1957   (magit-list-refs (list "refs/heads" "refs/remotes")))
   1958 
   1959 (defun magit-list-local-branches ()
   1960   (magit-list-refs "refs/heads"))
   1961 
   1962 (defun magit-list-remote-branches (&optional remote)
   1963   (magit-list-refs (concat "refs/remotes/" remote)))
   1964 
   1965 (defun magit-list-related-branches (relation &optional commit &rest args)
   1966   (--remove (string-match-p "\\(\\`(HEAD\\|HEAD -> \\)" it)
   1967             (--map (substring it 2)
   1968                    (magit-git-lines "branch" args relation commit))))
   1969 
   1970 (defun magit-list-containing-branches (&optional commit &rest args)
   1971   (magit-list-related-branches "--contains" commit args))
   1972 
   1973 (defun magit-list-publishing-branches (&optional commit)
   1974   (--filter (magit-rev-ancestor-p (or commit "HEAD") it)
   1975             magit-published-branches))
   1976 
   1977 (defun magit-list-merged-branches (&optional commit &rest args)
   1978   (magit-list-related-branches "--merged" commit args))
   1979 
   1980 (defun magit-list-unmerged-branches (&optional commit &rest args)
   1981   (magit-list-related-branches "--no-merged" commit args))
   1982 
   1983 (defun magit-list-unmerged-to-upstream-branches ()
   1984   (--filter (and-let* ((upstream (magit-get-upstream-branch it)))
   1985               (member it (magit-list-unmerged-branches upstream)))
   1986             (magit-list-local-branch-names)))
   1987 
   1988 (defun magit-list-branches-pointing-at (commit)
   1989   (let ((re (format "\\`%s refs/\\(heads\\|remotes\\)/\\(.*\\)\\'"
   1990                     (magit-rev-verify commit))))
   1991     (--keep (and (string-match re it)
   1992                  (let ((name (match-string 2 it)))
   1993                    (and (not (string-suffix-p "HEAD" name))
   1994                         name)))
   1995             (magit-git-lines "show-ref"))))
   1996 
   1997 (defun magit-list-refnames (&optional namespaces include-special)
   1998   (nconc (magit-list-refs namespaces "%(refname:short)")
   1999          (and include-special
   2000               (magit-list-special-refnames))))
   2001 
   2002 (defvar magit-special-refnames
   2003   '("HEAD" "ORIG_HEAD" "FETCH_HEAD" "MERGE_HEAD" "CHERRY_PICK_HEAD"))
   2004 
   2005 (defun magit-list-special-refnames ()
   2006   (let ((gitdir (magit-gitdir)))
   2007     (cl-mapcan (lambda (name)
   2008                  (and (file-exists-p (expand-file-name name gitdir))
   2009                       (list name)))
   2010                magit-special-refnames)))
   2011 
   2012 (defun magit-list-branch-names ()
   2013   (magit-list-refnames (list "refs/heads" "refs/remotes")))
   2014 
   2015 (defun magit-list-local-branch-names ()
   2016   (magit-list-refnames "refs/heads"))
   2017 
   2018 (defun magit-list-remote-branch-names (&optional remote relative)
   2019   (if (and remote relative)
   2020       (let ((regexp (format "^refs/remotes/%s/\\(.+\\)" remote)))
   2021         (--mapcat (when (string-match regexp it)
   2022                     (list (match-string 1 it)))
   2023                   (magit-list-remote-branches remote)))
   2024     (magit-list-refnames (concat "refs/remotes/" remote))))
   2025 
   2026 (defun magit-format-refs (format &rest args)
   2027   (let ((lines (magit-git-lines
   2028                 "for-each-ref" (concat "--format=" format)
   2029                 (or args (list "refs/heads" "refs/remotes" "refs/tags")))))
   2030     (if (string-search "\f" format)
   2031         (--map (split-string it "\f") lines)
   2032       lines)))
   2033 
   2034 (defun magit-list-remotes ()
   2035   (magit-git-lines "remote"))
   2036 
   2037 (defun magit-list-tags ()
   2038   (magit-git-lines "tag"))
   2039 
   2040 (defun magit-list-stashes (&optional format)
   2041   (magit-git-lines "stash" "list" (concat "--format=" (or format "%gd"))))
   2042 
   2043 (defun magit-list-active-notes-refs ()
   2044   "Return notes refs according to `core.notesRef' and `notes.displayRef'."
   2045   (magit-git-lines "for-each-ref" "--format=%(refname)"
   2046                    (or (magit-get "core.notesRef") "refs/notes/commits")
   2047                    (magit-get-all "notes.displayRef")))
   2048 
   2049 (defun magit-list-notes-refnames ()
   2050   (--map (substring it 6) (magit-list-refnames "refs/notes")))
   2051 
   2052 (defun magit-remote-list-tags (remote)
   2053   (--keep (and (not (string-suffix-p "^{}" it))
   2054                (substring it 51))
   2055           (magit-git-lines "ls-remote" "--tags" remote)))
   2056 
   2057 (defun magit-remote-list-branches (remote)
   2058   (--keep (and (not (string-suffix-p "^{}" it))
   2059                (substring it 52))
   2060           (magit-git-lines "ls-remote" "--heads" remote)))
   2061 
   2062 (defun magit-remote-list-refs (remote)
   2063   (--keep (and (not (string-suffix-p "^{}" it))
   2064                (substring it 41))
   2065           (magit-git-lines "ls-remote" remote)))
   2066 
   2067 (defun magit-remote-head (remote)
   2068   (and-let* ((line (cl-find-if
   2069                     (lambda (line)
   2070                       (string-match
   2071                        "\\`ref: refs/heads/\\([^\s\t]+\\)[\s\t]HEAD\\'" line))
   2072                     (magit-git-lines "ls-remote" "--symref" remote "HEAD"))))
   2073     (match-string 1 line)))
   2074 
   2075 (defun magit-list-modified-modules ()
   2076   (--keep (and (string-match "\\`\\+\\([^ ]+\\) \\(.+\\) (.+)\\'" it)
   2077                (match-string 2 it))
   2078           (magit-git-lines "submodule" "status")))
   2079 
   2080 (defun magit-list-module-paths ()
   2081   (magit-with-toplevel
   2082     (--mapcat (and (string-match "^160000 [0-9a-z]\\{40,\\} 0\t\\(.+\\)$" it)
   2083                    (list (match-string 1 it)))
   2084               (magit-git-items "ls-files" "-z" "--stage"))))
   2085 
   2086 (defun magit-list-module-names ()
   2087   (mapcar #'magit-get-submodule-name (magit-list-module-paths)))
   2088 
   2089 (defun magit-get-submodule-name (path)
   2090   "Return the name of the submodule at PATH.
   2091 PATH has to be relative to the super-repository."
   2092   (if (magit-git-version>= "2.38.0")
   2093       ;; "git submodule--helper name" was removed,
   2094       ;; but might still come back in another form.
   2095       (substring
   2096        (car (split-string
   2097              (car (or (magit-git-items
   2098                        "config" "-z"
   2099                        "-f" (expand-file-name ".gitmodules" (magit-toplevel))
   2100                        "--get-regexp" "^submodule\\..*\\.path$"
   2101                        (concat "^" (regexp-quote (directory-file-name path)) "$"))
   2102                       (error "No such submodule `%s'" path)))
   2103              "\n"))
   2104        10 -5)
   2105     (magit-git-string "submodule--helper" "name" path)))
   2106 
   2107 (defun magit-list-worktrees ()
   2108   "Return list of the worktrees of this repository.
   2109 
   2110 The returned list has the form (PATH COMMIT BRANCH BARE DETACHED
   2111 LOCKED PRUNABLE).  The last four elements are booleans, with the
   2112 exception of LOCKED and PRUNABLE, which may also be strings.
   2113 See git-worktree(1) manpage for the meaning of the various parts.
   2114 
   2115 This function corrects a situation where \"git worktree list\"
   2116 would claim a worktree is bare, even though the working tree is
   2117 specified using `core.worktree'."
   2118   (let ((remote (file-remote-p default-directory))
   2119         worktrees worktree)
   2120     (dolist (line (let ((magit-git-global-arguments
   2121                          ;; KLUDGE At least in Git v2.8.3 this argument
   2122                          ;; would trigger a segfault.
   2123                          (remove "--no-pager" magit-git-global-arguments)))
   2124                     (if (magit-git-version>= "2.36")
   2125                         (magit-git-items "worktree" "list" "--porcelain" "-z")
   2126                       (magit-git-lines "worktree" "list" "--porcelain"))))
   2127       (cond ((string-prefix-p "worktree" line)
   2128              (let ((path (substring line 9)))
   2129                (when remote
   2130                  (setq path (concat remote path)))
   2131                ;; If the git directory is separate from the main
   2132                ;; worktree, then "git worktree" returns the git
   2133                ;; directory instead of the worktree, which isn't
   2134                ;; what it is supposed to do and not what we want.
   2135                ;; However, if the worktree has been removed, then
   2136                ;; we want to return it anyway; instead of nil.
   2137                (setq path (or (magit-toplevel path) path))
   2138                (setq worktree (list path nil nil nil nil nil nil))
   2139                (push worktree worktrees)))
   2140             ((string-prefix-p "HEAD" line)
   2141              (setf (nth 1 worktree) (substring line 5)))
   2142             ((string-prefix-p "branch" line)
   2143              (setf (nth 2 worktree) (substring line 18)))
   2144             ((string-equal line "bare")
   2145              (let* ((default-directory (car worktree))
   2146                     (wt (and (not (magit-get-boolean "core.bare"))
   2147                              (magit-get "core.worktree"))))
   2148                (if (and wt (file-exists-p (expand-file-name wt)))
   2149                    (progn (setf (nth 0 worktree) (expand-file-name wt))
   2150                           (setf (nth 2 worktree) (magit-rev-parse "HEAD"))
   2151                           (setf (nth 3 worktree) (magit-get-current-branch)))
   2152                  (setf (nth 3 worktree) t))))
   2153             ((string-equal line "detached")
   2154              (setf (nth 4 worktree) t))
   2155             ((string-prefix-p line "locked")
   2156              (setf (nth 5 worktree)
   2157                    (if (> (length line) 6) (substring line 7) t)))
   2158             ((string-prefix-p line "prunable")
   2159              (setf (nth 6 worktree)
   2160                    (if (> (length line) 8) (substring line 9) t)))))
   2161     (nreverse worktrees)))
   2162 
   2163 (defun magit-symbolic-ref-p (name)
   2164   (magit-git-success "symbolic-ref" "--quiet" name))
   2165 
   2166 (defun magit-ref-p (rev)
   2167   (or (car (member rev (magit-list-refs "refs/")))
   2168       (car (member rev (magit-list-refnames "refs/")))))
   2169 
   2170 (defun magit-branch-p (rev)
   2171   (or (car (member rev (magit-list-branches)))
   2172       (car (member rev (magit-list-branch-names)))))
   2173 
   2174 (defun magit-local-branch-p (rev)
   2175   (or (car (member rev (magit-list-local-branches)))
   2176       (car (member rev (magit-list-local-branch-names)))))
   2177 
   2178 (defun magit-remote-branch-p (rev)
   2179   (or (car (member rev (magit-list-remote-branches)))
   2180       (car (member rev (magit-list-remote-branch-names)))))
   2181 
   2182 (defun magit-branch-set-face (branch)
   2183   (magit--propertize-face branch (if (magit-local-branch-p branch)
   2184                                      'magit-branch-local
   2185                                    'magit-branch-remote)))
   2186 
   2187 (defun magit-tag-p (rev)
   2188   (car (member rev (magit-list-tags))))
   2189 
   2190 (defun magit-remote-p (string)
   2191   (car (member string (magit-list-remotes))))
   2192 
   2193 (defvar magit-main-branch-names
   2194   '("main" "master" "trunk" "development")
   2195   "Branch names reserved for use by the primary branch.
   2196 Use function `magit-main-branch' to get the name actually used in
   2197 the current repository.")
   2198 
   2199 (defvar magit-long-lived-branches
   2200   (append magit-main-branch-names (list "maint" "next"))
   2201   "Branch names reserved for use by long lived branches.")
   2202 
   2203 (defun magit-main-branch ()
   2204   "Return the main branch.
   2205 
   2206 If a branch exists whose name matches `init.defaultBranch', then
   2207 that is considered the main branch.  If no branch by that name
   2208 exists, then the branch names in `magit-main-branch-names' are
   2209 tried in order.  The first branch from that list that actually
   2210 exists in the current repository is considered its main branch."
   2211   (let ((branches (magit-list-local-branch-names)))
   2212     (seq-find (lambda (name)
   2213                 (member name branches))
   2214               (delete-dups
   2215                (delq nil
   2216                      (cons (magit-get "init.defaultBranch")
   2217                            magit-main-branch-names))))))
   2218 
   2219 (defun magit-rev-diff-count (a b &optional first-parent)
   2220   "Return the commits in A but not B and vice versa.
   2221 Return a list of two integers: (A>B B>A).
   2222 
   2223 If `first-parent' is set, traverse only first parents."
   2224   (mapcar #'string-to-number
   2225           (split-string (magit-git-string "rev-list"
   2226                                           "--count" "--left-right"
   2227                                           (and first-parent "--first-parent")
   2228                                           (concat a "..." b))
   2229                         "\t")))
   2230 
   2231 (defun magit-abbrev-length ()
   2232   (let ((abbrev (magit-get "core.abbrev")))
   2233     (if (and abbrev (not (equal abbrev "auto")))
   2234         (string-to-number abbrev)
   2235       ;; Guess the length git will be using based on an example
   2236       ;; abbreviation.  Actually HEAD's abbreviation might be an
   2237       ;; outlier, so use the shorter of the abbreviations for two
   2238       ;; commits.  See #3034.
   2239       (if-let ((head (magit-rev-parse "--short" "HEAD"))
   2240                (head-len (length head)))
   2241           (min head-len
   2242                (if-let ((rev (magit-rev-parse "--short" "HEAD~")))
   2243                    (length rev)
   2244                  head-len))
   2245         ;; We're on an unborn branch, but perhaps the repository has
   2246         ;; other commits.  See #4123.
   2247         (if-let ((commits (magit-git-lines "rev-list" "-n2" "--all"
   2248                                            "--abbrev-commit")))
   2249             (apply #'min (mapcar #'length commits))
   2250           ;; A commit does not exist.  Fall back to the default of 7.
   2251           7)))))
   2252 
   2253 (defun magit-abbrev-arg (&optional arg)
   2254   (format "--%s=%d" (or arg "abbrev") (magit-abbrev-length)))
   2255 
   2256 (defun magit-rev-abbrev (rev)
   2257   (magit-rev-parse (magit-abbrev-arg "short") rev))
   2258 
   2259 (defun magit-commit-children (commit &optional args)
   2260   (mapcar #'car
   2261           (--filter (member commit (cdr it))
   2262                     (--map (split-string it " ")
   2263                            (magit-git-lines
   2264                             "log" "--format=%H %P"
   2265                             (or args (list "--branches" "--tags" "--remotes"))
   2266                             "--not" commit)))))
   2267 
   2268 (defun magit-commit-parents (commit)
   2269   (and-let* ((str (magit-git-string "rev-list" "-1" "--parents" commit)))
   2270     (cdr (split-string str))))
   2271 
   2272 (defun magit-patch-id (rev)
   2273   (magit--with-connection-local-variables
   2274     (magit--with-temp-process-buffer
   2275       (magit-process-file
   2276        shell-file-name nil '(t nil) nil shell-command-switch
   2277        (let ((exec (shell-quote-argument (magit-git-executable))))
   2278          (format "%s diff-tree -u %s | %s patch-id" exec rev exec)))
   2279       (car (split-string (buffer-string))))))
   2280 
   2281 (defun magit-rev-format (format &optional rev args)
   2282   ;; Prefer `git log --no-walk' to `git show --no-patch' because it
   2283   ;; performs better in some scenarios.
   2284   (let ((str (magit-git-string "log" "--no-walk"
   2285                                (concat "--format=" format) args
   2286                                (if rev (magit--rev-dereference rev) "HEAD")
   2287                                "--")))
   2288     (and (not (string-equal str ""))
   2289          str)))
   2290 
   2291 (defun magit-rev-insert-format (format &optional rev args)
   2292   ;; Prefer `git log --no-walk' to `git show --no-patch' because it
   2293   ;; performs better in some scenarios.
   2294   (magit-git-insert "log" "--no-walk"
   2295                     (concat "--format=" format) args
   2296                     (if rev (magit--rev-dereference rev) "HEAD")
   2297                     "--"))
   2298 
   2299 (defun magit-format-rev-summary (rev)
   2300   (and-let* ((str (magit-rev-format "%h %s" rev)))
   2301     (progn
   2302       (magit--put-face 0 (string-match " " str) 'magit-hash str)
   2303       str)))
   2304 
   2305 (defvar magit-ref-namespaces
   2306   '(("\\`HEAD\\'"                  . magit-head)
   2307     ("\\`refs/tags/\\(.+\\)"       . magit-tag)
   2308     ("\\`refs/heads/\\(.+\\)"      . magit-branch-local)
   2309     ("\\`refs/remotes/\\(.+\\)"    . magit-branch-remote)
   2310     ("\\`refs/bisect/\\(bad\\)"    . magit-bisect-bad)
   2311     ("\\`refs/bisect/\\(skip.*\\)" . magit-bisect-skip)
   2312     ("\\`refs/bisect/\\(good.*\\)" . magit-bisect-good)
   2313     ("\\`refs/stash$"              . magit-refname-stash)
   2314     ("\\`refs/wip/\\(.+\\)"        . magit-refname-wip)
   2315     ("\\`refs/pullreqs/\\(.+\\)"   . magit-refname-pullreq)
   2316     ("\\`\\(bad\\):"               . magit-bisect-bad)
   2317     ("\\`\\(skip\\):"              . magit-bisect-skip)
   2318     ("\\`\\(good\\):"              . magit-bisect-good)
   2319     ("\\`\\(.+\\)"                 . magit-refname))
   2320   "How refs are formatted for display.
   2321 
   2322 Each entry controls how a certain type of ref is displayed, and
   2323 has the form (REGEXP . FACE).  REGEXP is a regular expression
   2324 used to match full refs.  The first entry whose REGEXP matches
   2325 the reference is used.
   2326 
   2327 In log and revision buffers the first regexp submatch becomes the
   2328 \"label\" that represents the ref and is propertized with FONT.
   2329 In refs buffers the displayed text is controlled by other means
   2330 and this option only controls what face is used.")
   2331 
   2332 (defun magit-format-ref-labels (string)
   2333   (save-match-data
   2334     (let ((regexp "\\(, \\|tag: \\|HEAD -> \\)")
   2335           names)
   2336       (if (and (derived-mode-p 'magit-log-mode)
   2337                (member "--simplify-by-decoration" magit-buffer-log-args))
   2338           (let ((branches (magit-list-local-branch-names))
   2339                 (re (format "^%s/.+" (regexp-opt (magit-list-remotes)))))
   2340             (setq names
   2341                   (--map (cond ((string-equal it "HEAD")     it)
   2342                                ((string-prefix-p "refs/" it) it)
   2343                                ((member it branches) (concat "refs/heads/" it))
   2344                                ((string-match re it) (concat "refs/remotes/" it))
   2345                                (t                    (concat "refs/" it)))
   2346                          (split-string
   2347                           (string-replace "tag: " "refs/tags/" string)
   2348                           regexp t))))
   2349         (setq names (split-string string regexp t)))
   2350       (let (state head upstream tags branches remotes other combined)
   2351         (dolist (ref names)
   2352           (let* ((face (cdr (--first (string-match (car it) ref)
   2353                                      magit-ref-namespaces)))
   2354                  (name (magit--propertize-face
   2355                         (or (match-string 1 ref) ref) face)))
   2356             (cl-case face
   2357               ((magit-bisect-bad magit-bisect-skip magit-bisect-good)
   2358                (setq state name))
   2359               (magit-head
   2360                (setq head (magit--propertize-face "@" 'magit-head)))
   2361               (magit-tag            (push name tags))
   2362               (magit-branch-local   (push name branches))
   2363               (magit-branch-remote  (push name remotes))
   2364               (t                    (push name other)))))
   2365         (setq remotes
   2366               (seq-keep
   2367                (lambda (name)
   2368                  (if (string-match "\\`\\([^/]*\\)/\\(.*\\)\\'" name)
   2369                      (let ((r (match-string 1 name))
   2370                            (b (match-string 2 name)))
   2371                        (and (not (equal b "HEAD"))
   2372                             (if (equal (concat "refs/remotes/" name)
   2373                                        (magit-git-string
   2374                                         "symbolic-ref"
   2375                                         (format "refs/remotes/%s/HEAD" r)))
   2376                                 (magit--propertize-face
   2377                                  name 'magit-branch-remote-head)
   2378                               name)))
   2379                    name))
   2380                remotes))
   2381         (let* ((current (magit-get-current-branch))
   2382                (target  (magit-get-upstream-branch current)))
   2383           (dolist (name branches)
   2384             (let ((push (car (member (magit-get-push-branch name) remotes))))
   2385               (when push
   2386                 (setq remotes (delete push remotes))
   2387                 (string-match "^[^/]*/" push)
   2388                 (setq push (substring push 0 (match-end 0))))
   2389               (cond
   2390                ((equal name current)
   2391                 (setq head
   2392                       (concat push
   2393                               (magit--propertize-face
   2394                                name 'magit-branch-current))))
   2395                ((equal name target)
   2396                 (setq upstream
   2397                       (concat push
   2398                               (magit--propertize-face
   2399                                name '(magit-branch-upstream
   2400                                       magit-branch-local)))))
   2401                (t
   2402                 (push (concat push name) combined)))))
   2403           (when (and target (not upstream))
   2404             (if (member target remotes)
   2405                 (progn
   2406                   (magit--add-face-text-property
   2407                    0 (length target) 'magit-branch-upstream nil target)
   2408                   (setq upstream target)
   2409                   (setq remotes  (delete target remotes)))
   2410               (when-let ((target (car (member target combined))))
   2411                 (magit--add-face-text-property
   2412                  0 (length target) 'magit-branch-upstream nil target)
   2413                 (setq upstream target)
   2414                 (setq combined (delete target combined))))))
   2415         (string-join (flatten-tree `(,state
   2416                                      ,head
   2417                                      ,upstream
   2418                                      ,@(nreverse tags)
   2419                                      ,@(nreverse combined)
   2420                                      ,@(nreverse remotes)
   2421                                      ,@other))
   2422                      " ")))))
   2423 
   2424 (defun magit-object-type (object)
   2425   (magit-git-string "cat-file" "-t" object))
   2426 
   2427 (defmacro magit-with-blob (commit file &rest body)
   2428   (declare (indent 2)
   2429            (debug (form form body)))
   2430   `(magit--with-temp-process-buffer
   2431      (let ((buffer-file-name ,file))
   2432        (save-excursion
   2433          (magit-git-insert "cat-file" "-p"
   2434                            (concat ,commit ":" buffer-file-name)))
   2435        (decode-coding-inserted-region
   2436         (point-min) (point-max) buffer-file-name t nil nil t)
   2437        ,@body)))
   2438 
   2439 (defmacro magit-with-temp-index (tree arg &rest body)
   2440   (declare (indent 2) (debug (form form body)))
   2441   (let ((file (cl-gensym "file")))
   2442     `(let ((magit--refresh-cache nil)
   2443            (,file (magit-convert-filename-for-git
   2444                    (make-temp-name
   2445                     (expand-file-name "index.magit." (magit-gitdir))))))
   2446        (unwind-protect
   2447            (magit-with-toplevel
   2448              (when-let* ((tree ,tree)
   2449                          ((not (magit-git-success
   2450                                 "read-tree" ,arg tree
   2451                                 (concat "--index-output=" ,file)))))
   2452                (error "Cannot read tree %s" tree))
   2453              (with-environment-variables (("GIT_INDEX_FILE" ,file))
   2454                ,@body))
   2455          (ignore-errors
   2456            (delete-file (concat (file-remote-p default-directory) ,file)))))))
   2457 
   2458 (defun magit-commit-tree (message &optional tree &rest parents)
   2459   (magit-git-string "commit-tree" "--no-gpg-sign" "-m" message
   2460                     (--mapcat (list "-p" it) (delq nil parents))
   2461                     (or tree
   2462                         (magit-git-string "write-tree")
   2463                         (error "Cannot write tree"))))
   2464 
   2465 (defun magit-commit-worktree (message &optional arg &rest other-parents)
   2466   (magit-with-temp-index "HEAD" arg
   2467     (and (magit-update-files (magit-unstaged-files))
   2468          (apply #'magit-commit-tree message nil "HEAD" other-parents))))
   2469 
   2470 (defun magit-update-files (files)
   2471   (magit-git-success "update-index" "--add" "--remove" "--" files))
   2472 
   2473 (defun magit-update-ref (ref message rev &optional stashish)
   2474   (let ((magit--refresh-cache nil))
   2475     (or (if (magit-git-version>= "2.6.0")
   2476             (zerop (magit-call-git "update-ref" "--create-reflog"
   2477                                    "-m" message ref rev
   2478                                    (or (magit-rev-verify ref) "")))
   2479           ;; `--create-reflog' didn't exist before v2.6.0
   2480           (let ((oldrev  (magit-rev-verify ref))
   2481                 (logfile (expand-file-name (concat "logs/" ref)
   2482                                            (magit-gitdir))))
   2483             (unless (file-exists-p logfile)
   2484               (when oldrev
   2485                 (magit-git-success "update-ref" "-d" ref oldrev))
   2486               (make-directory (file-name-directory logfile) t)
   2487               (with-temp-file logfile)
   2488               (when (and oldrev (not stashish))
   2489                 (magit-git-success "update-ref" "-m" "enable reflog"
   2490                                    ref oldrev ""))))
   2491           (magit-git-success "update-ref" "-m" message ref rev
   2492                              (or (magit-rev-verify ref) "")))
   2493         (error "Cannot update %s with %s" ref rev))))
   2494 
   2495 (defconst magit-range-re
   2496   (concat "\\`\\([^ \t]*[^.]\\)?"       ; revA
   2497           "\\(\\.\\.\\.?\\)"            ; range marker
   2498           "\\([^.][^ \t]*\\)?\\'"))     ; revB
   2499 
   2500 (defun magit-split-range (range)
   2501   (pcase-let ((`(,beg ,end ,sep) (magit--split-range-raw range)))
   2502     (and sep
   2503          (let ((beg (or beg "HEAD"))
   2504                (end (or end "HEAD")))
   2505            (if (string-equal (match-string 2 range) "...")
   2506                (and-let* ((base (magit-git-string "merge-base" beg end)))
   2507                  (cons base end))
   2508              (cons beg end))))))
   2509 
   2510 (defun magit--split-range-raw (range)
   2511   (and (string-match magit-range-re range)
   2512        (let ((beg (match-string 1 range))
   2513              (end (match-string 3 range)))
   2514          (and (or beg end)
   2515               (list beg end (match-string 2 range))))))
   2516 
   2517 (defun magit-hash-range (range)
   2518   (if (string-match magit-range-re range)
   2519       (let ((beg (match-string 1 range))
   2520             (end (match-string 3 range)))
   2521         (and (or beg end)
   2522              (let ((beg-hash (and beg (magit-rev-hash (match-string 1 range))))
   2523                    (end-hash (and end (magit-rev-hash (match-string 3 range)))))
   2524                (and (or (not beg) beg-hash)
   2525                     (or (not end) end-hash)
   2526                     (concat beg-hash (match-string 2 range) end-hash)))))
   2527     (magit-rev-hash range)))
   2528 
   2529 (defvar magit-revision-faces
   2530   '(magit-hash
   2531     magit-tag
   2532     magit-branch-remote
   2533     magit-branch-remote-head
   2534     magit-branch-local
   2535     magit-branch-current
   2536     magit-branch-upstream
   2537     magit-branch-warning
   2538     magit-head
   2539     magit-refname
   2540     magit-refname-stash
   2541     magit-refname-wip
   2542     magit-refname-pullreq))
   2543 
   2544 (put 'git-revision 'thing-at-point #'magit-thingatpt--git-revision)
   2545 (defun magit-thingatpt--git-revision (&optional disallow)
   2546   ;; Support hashes and references.
   2547   (and-let* ((bounds
   2548               (let ((c (concat "\s\n\t~^:?*[\\" disallow)))
   2549                 (cl-letf
   2550                     (((get 'git-revision 'beginning-op)
   2551                       (lambda ()
   2552                         (if (re-search-backward (format "[%s]" c) nil t)
   2553                             (forward-char)
   2554                           (goto-char (point-min)))))
   2555                      ((get 'git-revision 'end-op)
   2556                       (lambda ()
   2557                         (re-search-forward (format "\\=[^%s]*" c) nil t))))
   2558                   (bounds-of-thing-at-point 'git-revision))))
   2559              (string (buffer-substring-no-properties (car bounds) (cdr bounds)))
   2560              ;; References are allowed to contain most parentheses and
   2561              ;; most punctuation, but if those characters appear at the
   2562              ;; edges of a possible reference in arbitrary text, then
   2563              ;; they are much more likely to be intended as just that:
   2564              ;; punctuation and delimiters.
   2565              (string (thread-first string
   2566                        (string-trim-left  "[(</]")
   2567                        (string-trim-right "[])>/.,;!]"))))
   2568     (let (disallow)
   2569       (when (or (string-match-p "\\.\\." string)
   2570                 (string-match-p "/\\." string))
   2571         (setq disallow (concat disallow ".")))
   2572       (when (string-match-p "@{" string)
   2573         (setq disallow (concat disallow "@{")))
   2574       (if disallow
   2575           ;; These additional restrictions overcompensate,
   2576           ;; but that only matters in rare cases.
   2577           (magit-thingatpt--git-revision disallow)
   2578         (and (not (equal string "@"))
   2579              (or (and (>= (length string) 7)
   2580                       (string-match-p "[a-z]" string)
   2581                       (magit-commit-p string))
   2582                  (and (magit-ref-p string)
   2583                       (let ((face (get-text-property (point) 'face)))
   2584                         (or (not face)
   2585                             (member face magit-revision-faces)))))
   2586              string)))))
   2587 
   2588 (put 'git-revision-range 'thing-at-point #'magit-thingatpt--git-revision-range)
   2589 (defun magit-thingatpt--git-revision-range ()
   2590   ;; Support hashes but no references.
   2591   (and-let* ((bounds
   2592               (cl-letf (((get 'git-revision 'beginning-op)
   2593                          (lambda ()
   2594                            (if (re-search-backward "[^a-z0-9.]" nil t)
   2595                                (forward-char)
   2596                              (goto-char (point-min)))))
   2597                         ((get 'git-revision 'end-op)
   2598                          (lambda ()
   2599                            (and (re-search-forward "[^a-z0-9.]" nil t)
   2600                                 (backward-char)))))
   2601                 (bounds-of-thing-at-point 'git-revision)))
   2602              (range (buffer-substring-no-properties (car bounds) (cdr bounds))))
   2603     ;; Validate but return as-is.
   2604     (and (magit-hash-range range) range)))
   2605 
   2606 ;;; Completion
   2607 
   2608 (defvar magit-revision-history nil)
   2609 
   2610 (defun magit--minibuf-default-add-commit ()
   2611   (let ((fn minibuffer-default-add-function))
   2612     (setq-local
   2613      minibuffer-default-add-function
   2614      (lambda ()
   2615        (let ((rest (and (functionp fn) (funcall fn))))
   2616          (if-let ((commit (with-selected-window (minibuffer-selected-window)
   2617                             (or (magit-thing-at-point 'git-revision-range t)
   2618                                 (magit-commit-at-point)))))
   2619              (let ((rest (cons commit (delete commit rest)))
   2620                    (def minibuffer-default))
   2621                (if (listp def)
   2622                    (append def rest)
   2623                  (cons def (delete def rest))))
   2624            rest))))))
   2625 
   2626 (defun magit-read-branch (prompt &optional secondary-default)
   2627   (magit-completing-read prompt (magit-list-branch-names)
   2628                          nil t nil 'magit-revision-history
   2629                          (or (magit-branch-at-point)
   2630                              secondary-default
   2631                              (magit-get-current-branch))))
   2632 
   2633 (defun magit-read-branch-or-commit (prompt &optional secondary-default exclude)
   2634   (let ((current (magit-get-current-branch))
   2635         (branch-at-point (magit-branch-at-point))
   2636         (commit-at-point (magit-commit-at-point))
   2637         (choices (delete exclude (magit-list-refnames nil t))))
   2638     (when (equal current exclude)
   2639       (setq current nil))
   2640     (when (equal branch-at-point exclude)
   2641       (setq branch-at-point nil))
   2642     (when (and commit-at-point (not branch-at-point))
   2643       (setq choices (cons commit-at-point choices)))
   2644     (minibuffer-with-setup-hook #'magit--minibuf-default-add-commit
   2645       (or (magit-completing-read
   2646            prompt choices nil nil nil 'magit-revision-history
   2647            (or branch-at-point commit-at-point secondary-default current))
   2648           (user-error "Nothing selected")))))
   2649 
   2650 (defun magit-read-range-or-commit (prompt &optional secondary-default)
   2651   (magit-read-range
   2652    prompt
   2653    (or (and-let* ((revs (magit-region-values '(commit branch) t)))
   2654          (progn
   2655            (deactivate-mark)
   2656            (concat (car (last revs)) ".." (car revs))))
   2657        (magit-branch-or-commit-at-point)
   2658        secondary-default
   2659        (magit-get-current-branch))))
   2660 
   2661 (defun magit-read-range (prompt &optional default)
   2662   (minibuffer-with-setup-hook
   2663       (lambda ()
   2664         (magit--minibuf-default-add-commit)
   2665         (setq-local crm-separator "\\.\\.\\.?"))
   2666     (magit-completing-read-multiple
   2667      (concat prompt ": ")
   2668      (magit-list-refnames)
   2669      nil nil nil 'magit-revision-history default nil t)))
   2670 
   2671 (defun magit-read-remote-branch
   2672     (prompt &optional remote default local-branch require-match)
   2673   (let ((choice (magit-completing-read
   2674                  prompt
   2675                  (cl-union (and local-branch
   2676                                 (if remote
   2677                                     (list local-branch)
   2678                                   (--map (concat it "/" local-branch)
   2679                                          (magit-list-remotes))))
   2680                            (magit-list-remote-branch-names remote t)
   2681                            :test #'equal)
   2682                  nil require-match nil 'magit-revision-history default)))
   2683     (if (or remote (string-match "\\`\\([^/]+\\)/\\(.+\\)" choice))
   2684         choice
   2685       (user-error "`%s' doesn't have the form REMOTE/BRANCH" choice))))
   2686 
   2687 (defun magit-read-refspec (prompt remote)
   2688   (magit-completing-read prompt
   2689                          (prog2 (message "Determining available refs...")
   2690                              (magit-remote-list-refs remote)
   2691                            (message "Determining available refs...done"))))
   2692 
   2693 (defun magit-read-local-branch (prompt &optional secondary-default)
   2694   (magit-completing-read prompt (magit-list-local-branch-names)
   2695                          nil t nil 'magit-revision-history
   2696                          (or (magit-local-branch-at-point)
   2697                              secondary-default
   2698                              (magit-get-current-branch))))
   2699 
   2700 (defun magit-read-local-branch-or-commit (prompt)
   2701   (let ((choices (nconc (magit-list-local-branch-names)
   2702                         (magit-list-special-refnames)))
   2703         (commit (magit-commit-at-point)))
   2704     (when commit
   2705       (push commit choices))
   2706     (minibuffer-with-setup-hook #'magit--minibuf-default-add-commit
   2707       (or (magit-completing-read prompt choices
   2708                                  nil nil nil 'magit-revision-history
   2709                                  (or (magit-local-branch-at-point) commit))
   2710           (user-error "Nothing selected")))))
   2711 
   2712 (defun magit-read-local-branch-or-ref (prompt &optional secondary-default)
   2713   (magit-completing-read prompt (nconc (magit-list-local-branch-names)
   2714                                        (magit-list-refs "refs/"))
   2715                          nil t nil 'magit-revision-history
   2716                          (or (magit-local-branch-at-point)
   2717                              secondary-default
   2718                              (magit-get-current-branch))))
   2719 
   2720 (defun magit-read-other-branch
   2721     (prompt &optional exclude secondary-default no-require-match)
   2722   (let* ((current (magit-get-current-branch))
   2723          (atpoint (magit-branch-at-point))
   2724          (exclude (or exclude current))
   2725          (default (or (and (not (equal atpoint exclude)) atpoint)
   2726                       (and (not (equal current exclude)) current)
   2727                       secondary-default
   2728                       (magit-get-previous-branch))))
   2729     (magit-completing-read prompt (delete exclude (magit-list-branch-names))
   2730                            nil (not no-require-match)
   2731                            nil 'magit-revision-history default)))
   2732 
   2733 (defun magit-read-other-branch-or-commit
   2734     (prompt &optional exclude secondary-default)
   2735   (let* ((current (magit-get-current-branch))
   2736          (atpoint (magit-branch-or-commit-at-point))
   2737          (exclude (or exclude current))
   2738          (default (or (and (not (equal atpoint exclude))
   2739                            (not (and (not current)
   2740                                      (magit-rev-equal atpoint "HEAD")))
   2741                            atpoint)
   2742                       (and (not (equal current exclude)) current)
   2743                       secondary-default
   2744                       (magit-get-previous-branch))))
   2745     (minibuffer-with-setup-hook #'magit--minibuf-default-add-commit
   2746       (or (magit-completing-read prompt (delete exclude (magit-list-refnames))
   2747                                  nil nil nil 'magit-revision-history default)
   2748           (user-error "Nothing selected")))))
   2749 
   2750 (defun magit-read-other-local-branch
   2751     (prompt &optional exclude secondary-default no-require-match)
   2752   (let* ((current (magit-get-current-branch))
   2753          (atpoint (magit-local-branch-at-point))
   2754          (exclude (or exclude current))
   2755          (default (or (and (not (equal atpoint exclude)) atpoint)
   2756                       (and (not (equal current exclude)) current)
   2757                       secondary-default
   2758                       (magit-get-previous-branch))))
   2759     (magit-completing-read prompt
   2760                            (delete exclude (magit-list-local-branch-names))
   2761                            nil (not no-require-match)
   2762                            nil 'magit-revision-history default)))
   2763 
   2764 (defun magit-read-branch-prefer-other (prompt)
   2765   (let* ((current (magit-get-current-branch))
   2766          (commit  (magit-commit-at-point))
   2767          (atrev   (and commit (magit-list-branches-pointing-at commit)))
   2768          (atpoint (magit--painted-branch-at-point)))
   2769     (magit-completing-read prompt (magit-list-branch-names)
   2770                            nil t nil 'magit-revision-history
   2771                            (or (magit-section-value-if 'branch)
   2772                                atpoint
   2773                                (and (not (cdr atrev)) (car atrev))
   2774                                (--first (not (equal it current)) atrev)
   2775                                (magit-get-previous-branch)
   2776                                (car atrev)))))
   2777 
   2778 (defun magit-read-upstream-branch (&optional branch prompt)
   2779   "Read the upstream for BRANCH using PROMPT.
   2780 If optional BRANCH is nil, then read the upstream for the
   2781 current branch, or raise an error if no branch is checked
   2782 out.  Only existing branches can be selected."
   2783   (unless branch
   2784     (setq branch (or (magit-get-current-branch)
   2785                      (error "Need a branch to set its upstream"))))
   2786   (let ((branches (delete branch (magit-list-branch-names))))
   2787     (magit-completing-read
   2788      (or prompt (format "Change upstream of %s to" branch))
   2789      branches nil t nil 'magit-revision-history
   2790      (or (let ((r (car (member (magit-remote-branch-at-point) branches)))
   2791                (l (car (member (magit-local-branch-at-point) branches))))
   2792            (if magit-prefer-remote-upstream (or r l) (or l r)))
   2793          (and-let* ((main (magit-main-branch)))
   2794            (let ((r (car (member (concat "origin/" main) branches)))
   2795                  (l (car (member main branches))))
   2796              (if magit-prefer-remote-upstream (or r l) (or l r))))
   2797          (car (member (magit-get-previous-branch) branches))))))
   2798 
   2799 (defun magit-read-starting-point (prompt &optional branch default)
   2800   (or (magit-completing-read
   2801        (concat prompt
   2802                (and branch
   2803                     (if (bound-and-true-p ivy-mode)
   2804                         ;; Ivy-mode strips faces from prompt.
   2805                         (format  " `%s'" branch)
   2806                       (concat " " (magit--propertize-face
   2807                                    branch 'magit-branch-local))))
   2808                " starting at")
   2809        (nconc (list "HEAD")
   2810               (magit-list-refnames)
   2811               (directory-files (magit-gitdir) nil "_HEAD\\'"))
   2812        nil nil nil 'magit-revision-history
   2813        (or default (magit--default-starting-point)))
   2814       (user-error "Nothing selected")))
   2815 
   2816 (defun magit--default-starting-point ()
   2817   (or (let ((r (magit-remote-branch-at-point))
   2818             (l (magit-local-branch-at-point)))
   2819         (if magit-prefer-remote-upstream (or r l) (or l r)))
   2820       (magit-commit-at-point)
   2821       (magit-stash-at-point)
   2822       (magit-get-current-branch)))
   2823 
   2824 (defun magit-read-tag (prompt &optional require-match)
   2825   (magit-completing-read prompt (magit-list-tags) nil
   2826                          require-match nil 'magit-revision-history
   2827                          (magit-tag-at-point)))
   2828 
   2829 (defun magit-read-stash (prompt)
   2830   (let* ((atpoint (magit-stash-at-point))
   2831          (default (and atpoint
   2832                        (concat atpoint (magit-rev-format " %s" atpoint))))
   2833          (choices (mapcar (lambda (c)
   2834                             (pcase-let ((`(,rev ,msg) (split-string c "\0")))
   2835                               (concat (propertize rev 'face 'magit-hash)
   2836                                       " " msg)))
   2837                           (magit-list-stashes "%gd%x00%s")))
   2838          (choice  (magit-completing-read prompt choices
   2839                                          nil t nil nil
   2840                                          default
   2841                                          (car choices))))
   2842     (and choice
   2843          (string-match "^\\([^ ]+\\) \\(.+\\)" choice)
   2844          (substring-no-properties (match-string 1 choice)))))
   2845 
   2846 (defun magit-read-remote (prompt &optional default use-only)
   2847   (let ((remotes (magit-list-remotes)))
   2848     (if (and use-only (length= remotes 1))
   2849         (car remotes)
   2850       (magit-completing-read prompt remotes
   2851                              nil t nil nil
   2852                              (or default
   2853                                  (magit-remote-at-point)
   2854                                  (magit-get-remote))))))
   2855 
   2856 (defun magit-read-remote-or-url (prompt &optional default)
   2857   (magit-completing-read prompt
   2858                          (nconc (magit-list-remotes)
   2859                                 (list "https://" "git://" "git@"))
   2860                          nil nil nil nil
   2861                          (or default
   2862                              (magit-remote-at-point)
   2863                              (magit-get-remote))))
   2864 
   2865 (defun magit-read-module-path (prompt &optional predicate)
   2866   (magit-completing-read prompt (magit-list-module-paths)
   2867                          predicate t nil nil
   2868                          (magit-module-at-point predicate)))
   2869 
   2870 (defun magit-module-confirm (verb &optional predicate)
   2871   ;; Some predicates use the inefficient `magit-toplevel'
   2872   ;; and some repositories have thousands of submodules.
   2873   (let ((magit--refresh-cache (list (cons 0 0)))
   2874         (modules nil))
   2875     (if current-prefix-arg
   2876         (progn
   2877           (setq modules (magit-list-module-paths))
   2878           (when predicate
   2879             (setq modules (seq-filter predicate modules)))
   2880           (unless modules
   2881             (if predicate
   2882                 (user-error "No modules satisfying %s available" predicate)
   2883               (user-error "No modules available"))))
   2884       (setq modules (magit-region-values 'module))
   2885       (when modules
   2886         (when predicate
   2887           (setq modules (seq-filter predicate modules)))
   2888         (unless modules
   2889           (user-error "No modules satisfying %s selected" predicate))))
   2890     (if (or (length> modules 1) current-prefix-arg)
   2891         (magit-confirm t nil (format "%s %%d modules" verb) nil modules)
   2892       (list (magit-read-module-path (format "%s module" verb) predicate)))))
   2893 
   2894 ;;; _
   2895 (provide 'magit-git)
   2896 ;;; magit-git.el ends here