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