Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2302 line
96 KiB

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