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