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