config

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

magit-git.el (124586B)


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