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.

341 rivejä
13 KiB

4 vuotta sitten
  1. ;;; magit-remote.el --- transfer Git commits -*- lexical-binding: t -*-
  2. ;; Copyright (C) 2008-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 remote commands.
  22. ;;; Code:
  23. (require 'magit)
  24. ;;; Options
  25. (defcustom magit-remote-add-set-remote.pushDefault 'ask-if-unset
  26. "Whether to set the value of `remote.pushDefault' after adding a remote.
  27. If `ask', then always ask. If `ask-if-unset', then ask, but only
  28. if the variable isn't set already. If nil, then don't ever set.
  29. If the value is a string, then set without asking, provided that
  30. the name of the added remote is equal to that string and the
  31. variable isn't already set."
  32. :package-version '(magit . "2.4.0")
  33. :group 'magit-commands
  34. :type '(choice (const :tag "ask if unset" ask-if-unset)
  35. (const :tag "always ask" ask)
  36. (string :tag "set if named")
  37. (const :tag "don't set")))
  38. (defcustom magit-remote-direct-configure t
  39. "Whether the command `magit-remote' shows Git variables.
  40. When set to nil, no variables are displayed by this transient
  41. command, instead the sub-transient `magit-remote-configure'
  42. has to be used to view and change remote related variables."
  43. :package-version '(magit . "2.12.0")
  44. :group 'magit-commands
  45. :type 'boolean)
  46. (defcustom magit-prefer-push-default nil
  47. "Whether to prefer `remote.pushDefault' over per-branch variables."
  48. :package-version '(magit . "2.91.0")
  49. :group 'magit-commands
  50. :type 'boolean)
  51. ;;; Commands
  52. ;;;###autoload (autoload 'magit-remote "magit-remote" nil t)
  53. (define-transient-command magit-remote (remote)
  54. "Add, configure or remove a remote."
  55. :man-page "git-remote"
  56. :value '("-f")
  57. ["Variables"
  58. :if (lambda ()
  59. (and magit-remote-direct-configure
  60. (oref transient--prefix scope)))
  61. ("u" magit-remote.<remote>.url)
  62. ("U" magit-remote.<remote>.fetch)
  63. ("s" magit-remote.<remote>.pushurl)
  64. ("S" magit-remote.<remote>.push)
  65. ("O" magit-remote.<remote>.tagopt)]
  66. ["Arguments for add"
  67. ("-f" "Fetch after add" "-f")]
  68. ["Actions"
  69. [("a" "Add" magit-remote-add)
  70. ("r" "Rename" magit-remote-rename)
  71. ("k" "Remove" magit-remote-remove)]
  72. [("C" "Configure..." magit-remote-configure)
  73. ("p" "Prune stale branches" magit-remote-prune)
  74. ("P" "Prune stale refspecs" magit-remote-prune-refspecs)]]
  75. (interactive (list (magit-get-current-remote)))
  76. (transient-setup 'magit-remote nil nil :scope remote))
  77. (defun magit-read-url (prompt &optional initial-input)
  78. (let ((url (magit-read-string-ns prompt initial-input)))
  79. (if (string-prefix-p "~" url)
  80. (expand-file-name url)
  81. url)))
  82. ;;;###autoload
  83. (defun magit-remote-add (remote url &optional args)
  84. "Add a remote named REMOTE and fetch it."
  85. (interactive (list (magit-read-string-ns "Remote name")
  86. (magit-read-url "Remote url")
  87. (transient-args 'magit-remote)))
  88. (if (pcase (list magit-remote-add-set-remote.pushDefault
  89. (magit-get "remote.pushDefault"))
  90. (`(,(pred stringp) ,_) t)
  91. ((or `(ask ,_) `(ask-if-unset nil))
  92. (y-or-n-p (format "Set `remote.pushDefault' to \"%s\"? " remote))))
  93. (progn (magit-call-git "remote" "add" args remote url)
  94. (setf (magit-get "remote.pushDefault") remote)
  95. (magit-refresh))
  96. (magit-run-git-async "remote" "add" args remote url)))
  97. ;;;###autoload
  98. (defun magit-remote-rename (old new)
  99. "Rename the remote named OLD to NEW."
  100. (interactive
  101. (let ((remote (magit-read-remote "Rename remote")))
  102. (list remote (magit-read-string-ns (format "Rename %s to" remote)))))
  103. (unless (string= old new)
  104. (magit-call-git "remote" "rename" old new)
  105. (magit-remote--cleanup-push-variables old new)
  106. (magit-refresh)))
  107. ;;;###autoload
  108. (defun magit-remote-remove (remote)
  109. "Delete the remote named REMOTE."
  110. (interactive (list (magit-read-remote "Delete remote")))
  111. (magit-call-git "remote" "rm" remote)
  112. (magit-remote--cleanup-push-variables remote)
  113. (magit-refresh))
  114. (defun magit-remote--cleanup-push-variables (remote &optional new-name)
  115. (magit-with-toplevel
  116. (when (equal (magit-get "remote.pushDefault") remote)
  117. (magit-set new-name "remote.pushDefault"))
  118. (dolist (var (magit-git-lines "config" "--name-only"
  119. "--get-regexp" "^branch\.[^.]*\.pushRemote"
  120. (format "^%s$" remote)))
  121. (magit-call-git "config" (and (not new-name) "--unset") var new-name))))
  122. (defconst magit--refspec-re "\\`\\(\\+\\)?\\([^:]+\\):\\(.*\\)\\'")
  123. ;;;###autoload
  124. (defun magit-remote-prune (remote)
  125. "Remove stale remote-tracking branches for REMOTE."
  126. (interactive (list (magit-read-remote "Prune stale branches of remote")))
  127. (magit-run-git-async "remote" "prune" remote))
  128. ;;;###autoload
  129. (defun magit-remote-prune-refspecs (remote)
  130. "Remove stale refspecs for REMOTE.
  131. A refspec is stale if there no longer exists at least one branch
  132. on the remote that would be fetched due to that refspec. A stale
  133. refspec is problematic because its existence causes Git to refuse
  134. to fetch according to the remaining non-stale refspecs.
  135. If only stale refspecs remain, then offer to either delete the
  136. remote or to replace the stale refspecs with the default refspec.
  137. Also remove the remote-tracking branches that were created due to
  138. the now stale refspecs. Other stale branches are not removed."
  139. (interactive (list (magit-read-remote "Prune refspecs of remote")))
  140. (let* ((tracking-refs (magit-list-remote-branches remote))
  141. (remote-refs (magit-remote-list-refs remote))
  142. (variable (format "remote.%s.fetch" remote))
  143. (refspecs (magit-get-all variable))
  144. stale)
  145. (dolist (refspec refspecs)
  146. (when (string-match magit--refspec-re refspec)
  147. (let ((theirs (match-string 2 refspec))
  148. (ours (match-string 3 refspec)))
  149. (unless (if (string-match "\\*" theirs)
  150. (let ((re (replace-match ".*" t t theirs)))
  151. (--some (string-match-p re it) remote-refs))
  152. (member theirs remote-refs))
  153. (push (cons refspec
  154. (if (string-match "\\*" ours)
  155. (let ((re (replace-match ".*" t t ours)))
  156. (--filter (string-match-p re it) tracking-refs))
  157. (list (car (member ours tracking-refs)))))
  158. stale)))))
  159. (if (not stale)
  160. (message "No stale refspecs for remote %S" remote)
  161. (if (= (length stale)
  162. (length refspecs))
  163. (magit-read-char-case
  164. (format "All of %s's refspecs are stale. " remote) nil
  165. (?s "replace with [d]efault refspec"
  166. (magit-set-all
  167. (list (format "+refs/heads/*:refs/remotes/%s/*" remote))
  168. variable))
  169. (?r "[r]emove remote"
  170. (magit-call-git "remote" "rm" remote))
  171. (?a "or [a]abort"
  172. (user-error "Abort")))
  173. (if (if (= (length stale) 1)
  174. (pcase-let ((`(,refspec . ,refs) (car stale)))
  175. (magit-confirm 'prune-stale-refspecs
  176. (format "Prune stale refspec %s and branch %%s" refspec)
  177. (format "Prune stale refspec %s and %%i branches" refspec)
  178. nil refs))
  179. (magit-confirm 'prune-stale-refspecs nil
  180. (format "Prune %%i stale refspecs and %i branches"
  181. (length (cl-mapcan (lambda (s) (copy-sequence (cdr s)))
  182. stale)))
  183. nil
  184. (mapcar (pcase-lambda (`(,refspec . ,refs))
  185. (concat refspec "\n"
  186. (mapconcat (lambda (b) (concat " " b))
  187. refs "\n")))
  188. stale)))
  189. (pcase-dolist (`(,refspec . ,refs) stale)
  190. (magit-call-git "config" "--unset" variable
  191. (regexp-quote refspec))
  192. (magit--log-action
  193. (lambda (refs)
  194. (format "Deleting %i branches" (length refs)))
  195. (lambda (ref)
  196. (format "Deleting branch %s (was %s)" ref
  197. (magit-rev-parse "--short" ref)))
  198. refs)
  199. (dolist (ref refs)
  200. (magit-call-git "update-ref" "-d" ref)))
  201. (user-error "Abort")))
  202. (magit-refresh))))
  203. ;;;###autoload
  204. (defun magit-remote-set-head (remote &optional branch)
  205. "Set the local representation of REMOTE's default branch.
  206. Query REMOTE and set the symbolic-ref refs/remotes/<remote>/HEAD
  207. accordingly. With a prefix argument query for the branch to be
  208. used, which allows you to select an incorrect value if you fancy
  209. doing that."
  210. (interactive
  211. (let ((remote (magit-read-remote "Set HEAD for remote")))
  212. (list remote
  213. (and current-prefix-arg
  214. (magit-read-remote-branch (format "Set %s/HEAD to" remote)
  215. remote nil nil t)))))
  216. (magit-run-git "remote" "set-head" remote (or branch "--auto")))
  217. ;;;###autoload
  218. (defun magit-remote-unset-head (remote)
  219. "Unset the local representation of REMOTE's default branch.
  220. Delete the symbolic-ref \"refs/remotes/<remote>/HEAD\"."
  221. (interactive (list (magit-read-remote "Unset HEAD for remote")))
  222. (magit-run-git "remote" "set-head" remote "--delete"))
  223. ;;; Configure
  224. ;;;###autoload (autoload 'magit-remote-configure "magit-remote" nil t)
  225. (define-transient-command magit-remote-configure (remote)
  226. "Configure a remote."
  227. :man-page "git-remote"
  228. [:description
  229. (lambda ()
  230. (concat
  231. (propertize "Configure " 'face 'transient-heading)
  232. (propertize (oref transient--prefix scope) 'face 'magit-branch-remote)))
  233. ("u" magit-remote.<remote>.url)
  234. ("U" magit-remote.<remote>.fetch)
  235. ("s" magit-remote.<remote>.pushurl)
  236. ("S" magit-remote.<remote>.push)
  237. ("O" magit-remote.<remote>.tagopt)]
  238. (interactive
  239. (list (or (and (not current-prefix-arg)
  240. (not (and magit-remote-direct-configure
  241. (eq current-transient-command 'magit-remote)))
  242. (magit-get-current-remote))
  243. (magit--read-remote-scope))))
  244. (transient-setup 'magit-remote-configure nil nil :scope remote))
  245. (defun magit--read-remote-scope (&optional obj)
  246. (magit-read-remote
  247. (if obj
  248. (format "Set %s for remote"
  249. (format (oref obj variable) "<name>"))
  250. "Configure remote")))
  251. (define-infix-command magit-remote.<remote>.url ()
  252. :class 'magit--git-variable:urls
  253. :scope 'magit--read-remote-scope
  254. :variable "remote.%s.url"
  255. :multi-value t
  256. :history-key 'magit-remote.<remote>.*url)
  257. (define-infix-command magit-remote.<remote>.fetch ()
  258. :class 'magit--git-variable
  259. :scope 'magit--read-remote-scope
  260. :variable "remote.%s.fetch"
  261. :multi-value t)
  262. (define-infix-command magit-remote.<remote>.pushurl ()
  263. :class 'magit--git-variable:urls
  264. :scope 'magit--read-remote-scope
  265. :variable "remote.%s.pushurl"
  266. :multi-value t
  267. :history-key 'magit-remote.<remote>.*url
  268. :seturl-arg "--push")
  269. (define-infix-command magit-remote.<remote>.push ()
  270. :class 'magit--git-variable
  271. :scope 'magit--read-remote-scope
  272. :variable "remote.%s.push")
  273. (define-infix-command magit-remote.<remote>.tagopt ()
  274. :class 'magit--git-variable:choices
  275. :scope 'magit--read-remote-scope
  276. :variable "remote.%s.tagOpt"
  277. :choices '("--no-tags" "--tags"))
  278. ;;; Transfer Utilities
  279. (defun magit--push-remote-variable (&optional branch short)
  280. (unless branch
  281. (setq branch (magit-get-current-branch)))
  282. (magit--propertize-face
  283. (if (or (not branch) magit-prefer-push-default)
  284. (if short "pushDefault" "remote.pushDefault")
  285. (if short "pushRemote" (format "branch.%s.pushRemote" branch)))
  286. 'bold))
  287. (defun magit--select-push-remote (prompt-suffix)
  288. (let* ((branch (or (magit-get-current-branch)
  289. (user-error "No branch is checked out")))
  290. (remote (magit-get-push-remote branch)))
  291. (when (or current-prefix-arg
  292. (not remote)
  293. (not (member remote (magit-list-remotes))))
  294. (setq remote
  295. (magit-read-remote (format "Set %s and %s"
  296. (magit--push-remote-variable)
  297. prompt-suffix)))
  298. (setf (magit-get (magit--push-remote-variable branch)) remote))
  299. (list branch remote)))
  300. ;;; _
  301. (provide 'magit-remote)
  302. ;;; magit-remote.el ends here