dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

magit-git.el (105581B)


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