mirror of https://github.com/Chizi123/.emacs.d.git

Chizi123
2018-11-18 c655eea759be1db69c5e6b45c228139d8390122a
commit | author | age
5cb5f7 1 ;;; magit-push.el --- update remote objects and refs  -*- lexical-binding: t -*-
C 2
3 ;; Copyright (C) 2008-2018  The Magit Project Contributors
4 ;;
5 ;; You should have received a copy of the AUTHORS.md file which
6 ;; lists all contributors.  If not, see http://magit.vc/authors.
7
8 ;; Author: Jonas Bernoulli <jonas@bernoul.li>
9 ;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
10
11 ;; Magit is free software; you can redistribute it and/or modify it
12 ;; under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 3, or (at your option)
14 ;; any later version.
15 ;;
16 ;; Magit is distributed in the hope that it will be useful, but WITHOUT
17 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 ;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
19 ;; License for more details.
20 ;;
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with Magit.  If not, see http://www.gnu.org/licenses.
23
24 ;;; Commentary:
25
26 ;; This library implements push commands.
27
28 ;;; Code:
29
30 (eval-when-compile
31   (require 'subr-x))
32
33 (require 'magit)
34
35 ;;; Options
36
37 (defcustom magit-push-current-set-remote-if-missing t
38   "Whether to configure missing remotes before pushing.
39
40 When nil, then the command `magit-push-current-to-pushremote' and
41 `magit-push-current-to-upstream' do not appear in the push popup
42 if the push-remote resp. upstream is not configured.  If the user
43 invokes one of these commands anyway, then it raises an error.
44
45 When non-nil, then these commands always appear in the push
46 popup.  But if the required configuration is missing, then they
47 do appear in a way that indicates that this is the case.  If the
48 user invokes one of them, then it asks for the necessary
49 configuration, stores the configuration, and then uses it to push
50 a first time.
51
52 This option also affects whether the argument `--set-upstream' is
53 available in the popup.  If the value is t, then that argument is
54 redundant.  But note that changing the value of this option does
55 not take affect immediately, the argument will only be added or
56 removed after restarting Emacs."
57   :package-version '(magit . "2.6.0")
58   :group 'magit-commands
59   :type '(choice (const :tag "don't set" nil)
60                  (const :tag "set branch.<name>.pushRemote" t)
61                  (const :tag "set remote.pushDefault" default)))
62
63 ;;; Commands
64
65 ;;;###autoload (autoload 'magit-push-popup "magit-push" nil t)
66 (magit-define-popup magit-push-popup
67   "Popup console for push commands."
68   :man-page "git-push"
69   :switches `((?f "Force with lease" "--force-with-lease")
70               (?F "Force"            "--force")
71               (?h "Disable hooks"    "--no-verify")
72               (?d "Dry run"          "--dry-run")
73               ,@(and (not magit-push-current-set-remote-if-missing)
74                      '((?u "Set upstream"  "--set-upstream"))))
75   :actions '("Configure"
76              (?C "variables..."      magit-branch-config-popup)
77              (lambda ()
78                (--when-let (magit-get-current-branch)
79                  (concat (propertize "Push " 'face 'magit-popup-heading)
80                          (propertize it      'face 'magit-branch-local)
81                          (propertize " to"   'face 'magit-popup-heading))))
82              (?p magit--push-current-to-pushremote-desc
83                  magit-push-current-to-pushremote)
84              (?u magit--push-current-to-upstream-desc
85                  magit-push-current-to-upstream)
86              (?e "elsewhere\n"       magit-push-current)
87              "Push"
88              (?o "another branch"    magit-push-other)
89              (?T "a tag"             magit-push-tag)
90              (?r "explicit refspecs" magit-push-refspecs)
91              (?t "all tags"          magit-push-tags)
92              (?m "matching branches" magit-push-matching))
93   :max-action-columns 2)
94
95 (defun magit-git-push (branch target args)
96   (run-hooks 'magit-credential-hook)
97   (pcase-let ((`(,remote . ,target)
98                (magit-split-branch-name target)))
99     (magit-run-git-async "push" "-v" args remote
100                          (format "%s:refs/heads/%s" branch target))))
101
102 ;;;###autoload
103 (defun magit-push-current-to-pushremote (args &optional push-remote)
104   "Push the current branch to `branch.<name>.pushRemote'.
105 If that variable is unset, then push to `remote.pushDefault'.
106
107 When `magit-push-current-set-remote-if-missing' is non-nil and
108 the push-remote is not configured, then read the push-remote from
109 the user, set it, and then push to it.  With a prefix argument
110 the push-remote can be changed before pushed to it."
111   (interactive
112    (list (magit-push-arguments)
113          (and (magit--push-current-set-pushremote-p current-prefix-arg)
114               (magit-read-remote
115                (if (eq magit-push-current-set-remote-if-missing 'default)
116                    "Set `remote.pushDefault' and push there"
117                  (format "Set `branch.%s.pushRemote' and push there"
118                          (magit-get-current-branch)))))))
119   (--if-let (magit-get-current-branch)
120       (progn (when push-remote
121                (setf (magit-get
122                       (if (eq magit-push-current-set-remote-if-missing 'default)
123                           "remote.pushDefault"
124                         (format "branch.%s.pushRemote" it)))
125                      push-remote))
126              (if-let ((remote (magit-get-push-remote it)))
127                  (if (member remote (magit-list-remotes))
128                      (magit-git-push it (concat remote "/" it) args)
129                    (user-error "Remote `%s' doesn't exist" remote))
130                (user-error "No push-remote is configured for %s" it)))
131     (user-error "No branch is checked out")))
132
133 (defun magit--push-current-set-pushremote-p (&optional change)
134   (and (or change
135            (and magit-push-current-set-remote-if-missing
136                 (not (magit-get-push-remote))))
137        (magit-get-current-branch)))
138
139 (defun magit--push-current-to-pushremote-desc ()
140   (--if-let (magit-get-push-branch)
141       (concat (magit-branch-set-face it) "\n")
142     (and (magit--push-current-set-pushremote-p)
143          (concat
144           (propertize (if (eq magit-push-current-set-remote-if-missing 'default)
145                           "pushDefault"
146                         "pushRemote")
147                       'face 'bold)
148           ", after setting that\n"))))
149
150 ;;;###autoload
151 (defun magit-push-current-to-upstream (args &optional upstream)
152   "Push the current branch to its upstream branch.
153
154 When `magit-push-current-set-remote-if-missing' is non-nil and
155 the upstream is not configured, then read the upstream from the
156 user, set it, and then push to it.  With a prefix argument the
157 upstream can be changed before pushed to it."
158   (interactive
159    (list (magit-push-arguments)
160          (and (magit--push-current-set-upstream-p current-prefix-arg)
161               (magit-read-upstream-branch))))
162   (--if-let (magit-get-current-branch)
163       (progn
164         (when upstream
165           (magit-set-upstream-branch it upstream))
166         (if-let ((target (magit-get-upstream-branch it)))
167             (magit-git-push it target args)
168           (user-error "No upstream is configured for %s" it)))
169     (user-error "No branch is checked out")))
170
171 (defun magit--push-current-set-upstream-p (&optional change)
172   (and (or change
173            (and magit-push-current-set-remote-if-missing
174                 (not (magit-get-upstream-branch))))
175        (magit-get-current-branch)))
176
177 (defun magit--push-current-to-upstream-desc ()
178   (--if-let (magit-get-upstream-branch)
179       (concat (magit-branch-set-face it) "\n")
180     (and (magit--push-current-set-upstream-p)
181          (concat (propertize "@{upstream}" 'face 'bold)
182                  ", after setting that\n"))))
183
184 ;;;###autoload
185 (defun magit-push-current (target args)
186   "Push the current branch to a branch read in the minibuffer."
187   (interactive
188    (--if-let (magit-get-current-branch)
189        (list (magit-read-remote-branch (format "Push %s to" it)
190                                        nil nil it 'confirm)
191              (magit-push-arguments))
192      (user-error "No branch is checked out")))
193   (magit-git-push (magit-get-current-branch) target args))
194
195 ;;;###autoload
196 (defun magit-push-other (source target args)
197   "Push an arbitrary branch or commit somewhere.
198 Both the source and the target are read in the minibuffer."
199   (interactive
200    (let ((source (magit-read-local-branch-or-commit "Push")))
201      (list source
202            (magit-read-remote-branch
203             (format "Push %s to" source) nil
204             (if (magit-local-branch-p source)
205                 (or (magit-get-push-branch source)
206                     (magit-get-upstream-branch source))
207               (and (magit-rev-ancestor-p source "HEAD")
208                    (or (magit-get-push-branch)
209                        (magit-get-upstream-branch))))
210             source 'confirm)
211            (magit-push-arguments))))
212   (magit-git-push source target args))
213
214 (defvar magit-push-refspecs-history nil)
215
216 ;;;###autoload
217 (defun magit-push-refspecs (remote refspecs args)
218   "Push one or multiple REFSPECS to a REMOTE.
219 Both the REMOTE and the REFSPECS are read in the minibuffer.  To
220 use multiple REFSPECS, separate them with commas.  Completion is
221 only available for the part before the colon, or when no colon
222 is used."
223   (interactive
224    (list (magit-read-remote "Push to remote")
225          (split-string (magit-completing-read-multiple
226                         "Push refspec,s"
227                         (cons "HEAD" (magit-list-local-branch-names))
228                         nil nil 'magit-push-refspecs-history)
229                        crm-default-separator t)
230          (magit-push-arguments)))
231   (run-hooks 'magit-credential-hook)
232   (magit-run-git-async "push" "-v" args remote refspecs))
233
234 ;;;###autoload
235 (defun magit-push-matching (remote &optional args)
236   "Push all matching branches to another repository.
237 If multiple remotes exist, then read one from the user.
238 If just one exists, use that without requiring confirmation."
239   (interactive (list (magit-read-remote "Push matching branches to" nil t)
240                      (magit-push-arguments)))
241   (run-hooks 'magit-credential-hook)
242   (magit-run-git-async "push" "-v" args remote ":"))
243
244 ;;;###autoload
245 (defun magit-push-tags (remote &optional args)
246   "Push all tags to another repository.
247 If only one remote exists, then push to that.  Otherwise prompt
248 for a remote, offering the remote configured for the current
249 branch as default."
250   (interactive (list (magit-read-remote "Push tags to remote" nil t)
251                      (magit-push-arguments)))
252   (run-hooks 'magit-credential-hook)
253   (magit-run-git-async "push" remote "--tags" args))
254
255 ;;;###autoload
256 (defun magit-push-tag (tag remote &optional args)
257   "Push a tag to another repository."
258   (interactive
259    (let  ((tag (magit-read-tag "Push tag")))
260      (list tag (magit-read-remote (format "Push %s to remote" tag) nil t)
261            (magit-push-arguments))))
262   (run-hooks 'magit-credential-hook)
263   (magit-run-git-async "push" remote tag args))
264
265 ;;;###autoload
266 (defun magit-push-implicitly (args)
267   "Push somewhere without using an explicit refspec.
268
269 This command simply runs \"git push -v [ARGS]\".  ARGS are the
270 arguments specified in the popup buffer.  No explicit refspec
271 arguments are used.  Instead the behavior depends on at least
272 these Git variables: `push.default', `remote.pushDefault',
273 `branch.<branch>.pushRemote', `branch.<branch>.remote',
274 `branch.<branch>.merge', and `remote.<remote>.push'.
275
276 To add this command to the push popup add this to your init file:
277
278   (with-eval-after-load \\='magit-remote
279     (magit-define-popup-action \\='magit-push-popup ?P
280       \\='magit-push-implicitly--desc
281       \\='magit-push-implicitly ?p t))
282
283 The function `magit-push-implicitly--desc' attempts to predict
284 what this command will do.  The value it returns is displayed in
285 the popup buffer."
286   (interactive (list (magit-push-arguments)))
287   (run-hooks 'magit-credential-hook)
288   (magit-run-git-async "push" "-v" args))
289
290 (defun magit-push-implicitly--desc ()
291   (let ((default (magit-get "push.default")))
292     (unless (equal default "nothing")
293       (or (when-let ((remote (or (magit-get-remote)
294                                  (magit-remote-p "origin")))
295                      (refspec (magit-get "remote" remote "push")))
296             (format "%s using %s"
297                     (propertize remote  'face 'magit-branch-remote)
298                     (propertize refspec 'face 'bold)))
299           (--when-let (and (not (magit-get-push-branch))
300                            (magit-get-upstream-branch))
301             (format "%s aka %s\n"
302                     (magit-branch-set-face it)
303                     (propertize "@{upstream}" 'face 'bold)))
304           (--when-let (magit-get-push-branch)
305             (format "%s aka %s\n"
306                     (magit-branch-set-face it)
307                     (propertize "pushRemote" 'face 'bold)))
308           (--when-let (magit-get-@{push}-branch)
309             (format "%s aka %s\n"
310                     (magit-branch-set-face it)
311                     (propertize "@{push}" 'face 'bold)))
312           (format "using %s (%s is %s)\n"
313                   (propertize "git push"     'face 'bold)
314                   (propertize "push.default" 'face 'bold)
315                   (propertize default        'face 'bold))))))
316
317 ;;;###autoload
318 (defun magit-push-to-remote (remote args)
319   "Push to REMOTE without using an explicit refspec.
320 The REMOTE is read in the minibuffer.
321
322 This command simply runs \"git push -v [ARGS] REMOTE\".  ARGS
323 are the arguments specified in the popup buffer.  No refspec
324 arguments are used.  Instead the behavior depends on at least
325 these Git variables: `push.default', `remote.pushDefault',
326 `branch.<branch>.pushRemote', `branch.<branch>.remote',
327 `branch.<branch>.merge', and `remote.<remote>.push'.
328
329 To add this command to the push popup add this to your init file:
330
331   (with-eval-after-load \\='magit-remote
332     (magit-define-popup-action \\='magit-push-popup ?r
333       \\='magit-push-to-remote--desc
334       \\='magit-push-to-remote ?p t))"
335   (interactive (list (magit-read-remote "Push to remote")
336                      (magit-push-arguments)))
337   (run-hooks 'magit-credential-hook)
338   (magit-run-git-async "push" "-v" args remote))
339
340 (defun magit-push-to-remote--desc ()
341   (format "using %s\n" (propertize "git push <remote>" 'face 'bold)))
342
343 ;;; _
344 (provide 'magit-push)
345 ;;; magit-push.el ends here