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.

267 lines
11 KiB

пре 4 година
  1. ;;; magit-clone.el --- clone a repository -*- 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 clone commands.
  22. ;;; Code:
  23. (require 'magit)
  24. ;;; Options
  25. (defcustom magit-clone-set-remote-head nil
  26. "Whether cloning creates the symbolic-ref `<remote>/HEAD'."
  27. :package-version '(magit . "2.4.2")
  28. :group 'magit-commands
  29. :type 'boolean)
  30. (defcustom magit-clone-set-remote.pushDefault 'ask
  31. "Whether to set the value of `remote.pushDefault' after cloning.
  32. If t, then set without asking. If nil, then don't set. If
  33. `ask', then ask."
  34. :package-version '(magit . "2.4.0")
  35. :group 'magit-commands
  36. :type '(choice (const :tag "set" t)
  37. (const :tag "ask" ask)
  38. (const :tag "don't set" nil)))
  39. (defcustom magit-clone-default-directory nil
  40. "Default directory to use when `magit-clone' reads destination.
  41. If nil (the default), then use the value of `default-directory'.
  42. If a directory, then use that. If a function, then call that
  43. with the remote url as only argument and use the returned value."
  44. :package-version '(magit . "2.90.0")
  45. :group 'magit-commands
  46. :type '(choice (const :tag "value of default-directory")
  47. (directory :tag "constant directory")
  48. (function :tag "function's value")))
  49. (defcustom magit-clone-always-transient nil
  50. "Whether `magit-clone' always acts as a transient prefix command.
  51. If nil, then a prefix argument has to be used to show the transient
  52. popup instead of invoking the default suffix `magit-clone-regular'
  53. directly."
  54. :package-version '(magit . "2.91.0")
  55. :group 'magit-commands
  56. :type 'boolean)
  57. (defcustom magit-clone-name-alist
  58. '(("\\`\\(?:github:\\|gh:\\)?\\([^:]+\\)\\'" "github.com" "github.user")
  59. ("\\`\\(?:gitlab:\\|gl:\\)\\([^:]+\\)\\'" "gitlab.com" "gitlab.user"))
  60. "Alist mapping repository names to repository urls.
  61. Each element has the form (REGEXP HOSTNAME USER). When the user
  62. enters a name when a cloning command asks for a name or url, then
  63. that is looked up in this list. The first element whose REGEXP
  64. matches is used.
  65. The format specified by option `magit-clone-url-format' is used
  66. to turn the name into an url, using HOSTNAME and the repository
  67. name. If the provided name contains a slash, then that is used.
  68. Otherwise if the name omits the owner of the repository, then the
  69. default user specified in the matched entry is used.
  70. If USER contains a dot, then it is treated as a Git variable and
  71. the value of that is used as the username. Otherwise it is used
  72. as the username itself."
  73. :package-version '(magit . "2.91.0")
  74. :group 'magit-commands
  75. :type '(repeat (list regexp
  76. (string :tag "hostname")
  77. (string :tag "user name or git variable"))))
  78. (defcustom magit-clone-url-format "git@%h:%n.git"
  79. "Format used when turning repository names into urls.
  80. %h is the hostname and %n is the repository name, including
  81. the name of the owner. Also see `magit-clone-name-alist'."
  82. :package-version '(magit . "2.91.0")
  83. :group 'magit-commands
  84. :type 'regexp)
  85. ;;; Commands
  86. ;;;###autoload (autoload 'magit-clone "magit-clone" nil t)
  87. (define-transient-command magit-clone (&optional transient)
  88. "Clone a repository."
  89. :man-page "git-clone"
  90. ["Fetch arguments"
  91. ("-B" "Clone a single branch" "--single-branch")
  92. ("-n" "Do not clone tags" "--no-tags")
  93. ("-S" "Clones submodules" "--recurse-submodules" :level 6)
  94. ("-l" "Do not optimize" "--no-local" :level 7)]
  95. ["Setup arguments"
  96. ("-o" "Set name of remote" ("-o" "--origin="))
  97. ("-b" "Set HEAD branch" ("-b" "--branch="))
  98. ("-g" "Separate git directory" "--separate-git-dir="
  99. transient-read-directory :level 7)
  100. ("-t" "Use template directory" "--template="
  101. transient-read-existing-directory :level 6)]
  102. ["Local sharing arguments"
  103. ("-s" "Share objects" ("-s" "--shared" :level 7))
  104. ("-h" "Do not use hardlinks" "--no-hardlinks")]
  105. ["Clone"
  106. ("C" "regular" magit-clone-regular)
  107. ("s" "shallow" magit-clone-shallow)
  108. ("d" "shallow since date" magit-clone-shallow-since :level 7)
  109. ("e" "shallow excluding" magit-clone-shallow-exclude :level 7)
  110. ("b" "bare" magit-clone-bare)
  111. ("m" "mirror" magit-clone-mirror)]
  112. (interactive (list (or magit-clone-always-transient current-prefix-arg)))
  113. (if transient
  114. (transient-setup #'magit-clone)
  115. (call-interactively #'magit-clone-regular)))
  116. ;;;###autoload
  117. (defun magit-clone-regular (repository directory args)
  118. "Create a clone of REPOSITORY in DIRECTORY.
  119. Then show the status buffer for the new repository."
  120. (interactive (magit-clone-read-args))
  121. (magit-clone-internal repository directory args))
  122. ;;;###autoload
  123. (defun magit-clone-shallow (repository directory args depth)
  124. "Create a shallow clone of REPOSITORY in DIRECTORY.
  125. Then show the status buffer for the new repository.
  126. With a prefix argument read the DEPTH of the clone;
  127. otherwise use 1."
  128. (interactive (append (magit-clone-read-args)
  129. (list (if current-prefix-arg
  130. (read-number "Depth: " 1)
  131. 1))))
  132. (magit-clone-internal repository directory
  133. (cons (format "--depth=%s" depth) args)))
  134. ;;;###autoload
  135. (defun magit-clone-shallow-since (repository directory args date)
  136. "Create a shallow clone of REPOSITORY in DIRECTORY.
  137. Then show the status buffer for the new repository.
  138. Exclude commits before DATE, which is read from the
  139. user."
  140. (interactive (append (magit-clone-read-args)
  141. (list (transient-read-date "Exclude commits before: "
  142. nil nil))))
  143. (magit-clone-internal repository directory
  144. (cons (format "--shallow-since=%s" date) args)))
  145. ;;;###autoload
  146. (defun magit-clone-shallow-exclude (repository directory args exclude)
  147. "Create a shallow clone of REPOSITORY in DIRECTORY.
  148. Then show the status buffer for the new repository.
  149. Exclude commits reachable from EXCLUDE, which is a
  150. branch or tag read from the user."
  151. (interactive (append (magit-clone-read-args)
  152. (list (read-string "Exclude commits reachable from: "))))
  153. (magit-clone-internal repository directory
  154. (cons (format "--shallow-exclude=%s" exclude) args)))
  155. ;;;###autoload
  156. (defun magit-clone-bare (repository directory args)
  157. "Create a bare clone of REPOSITORY in DIRECTORY.
  158. Then show the status buffer for the new repository."
  159. (interactive (magit-clone-read-args))
  160. (magit-clone-internal repository directory (cons "--bare" args)))
  161. ;;;###autoload
  162. (defun magit-clone-mirror (repository directory args)
  163. "Create a mirror of REPOSITORY in DIRECTORY.
  164. Then show the status buffer for the new repository."
  165. (interactive (magit-clone-read-args))
  166. (magit-clone-internal repository directory (cons "--mirror" args)))
  167. (defun magit-clone-internal (repository directory args)
  168. (run-hooks 'magit-credential-hook)
  169. (setq directory (file-name-as-directory (expand-file-name directory)))
  170. (magit-run-git-async "clone" args "--" repository
  171. (magit-convert-filename-for-git directory))
  172. ;; Don't refresh the buffer we're calling from.
  173. (process-put magit-this-process 'inhibit-refresh t)
  174. (set-process-sentinel
  175. magit-this-process
  176. (lambda (process event)
  177. (when (memq (process-status process) '(exit signal))
  178. (let ((magit-process-raise-error t))
  179. (magit-process-sentinel process event)))
  180. (when (and (eq (process-status process) 'exit)
  181. (= (process-exit-status process) 0))
  182. (unless (memq (car args) '("--bare" "--mirror"))
  183. (let ((default-directory directory))
  184. (when (or (eq magit-clone-set-remote.pushDefault t)
  185. (and magit-clone-set-remote.pushDefault
  186. (y-or-n-p "Set `remote.pushDefault' to \"origin\"? ")))
  187. (setf (magit-get "remote.pushDefault") "origin"))
  188. (unless magit-clone-set-remote-head
  189. (magit-remote-unset-head "origin"))))
  190. (with-current-buffer (process-get process 'command-buf)
  191. (magit-status-setup-buffer directory))))))
  192. (defun magit-clone-read-args ()
  193. (let ((repo (magit-clone-read-repository)))
  194. (list repo
  195. (read-directory-name
  196. "Clone to: "
  197. (if (functionp magit-clone-default-directory)
  198. (funcall magit-clone-default-directory repo)
  199. magit-clone-default-directory)
  200. nil nil
  201. (and (string-match "\\([^/:]+?\\)\\(/?\\.git\\)?$" repo)
  202. (match-string 1 repo)))
  203. (transient-args 'magit-clone))))
  204. (defun magit-clone-read-repository ()
  205. (magit-read-char-case "Clone from " nil
  206. (?u "[u]rl or name"
  207. (let ((str (magit-read-string-ns "Clone from url or name")))
  208. (if (string-match-p "\\(://\\|@\\)" str)
  209. str
  210. (magit-clone--name-to-url str))))
  211. (?p "[p]ath"
  212. (read-directory-name "Clone repository: "))
  213. (?l "or [l]ocal url"
  214. (concat "file://" (read-directory-name "Clone repository: file://")))))
  215. (defun magit-clone--name-to-url (name)
  216. (or (-some
  217. (pcase-lambda (`(,re ,host ,user))
  218. (and (string-match re name)
  219. (let ((repo (match-string 1 name)))
  220. (format-spec
  221. magit-clone-url-format
  222. `((?h . ,host)
  223. (?n . ,(if (string-match-p "/" repo)
  224. repo
  225. (if (string-match-p "\\." user)
  226. (if-let ((user (magit-get user)))
  227. (concat user "/" repo)
  228. (user-error
  229. "Set %S or specify owner explicitly" user))
  230. (concat user "/" repo)))))))))
  231. magit-clone-name-alist)
  232. (user-error "Not an url and no matching entry in `%s'"
  233. 'magit-clone-name-alist)))
  234. ;;; _
  235. (provide 'magit-clone)
  236. ;;; magit-clone.el ends here