config

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

magit-git.el (125092B)


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