diff options
Diffstat (limited to 'configs/shared/emacs/.emacs.d/elpa/magit-20180719.1904/magit-remote.el')
-rw-r--r-- | configs/shared/emacs/.emacs.d/elpa/magit-20180719.1904/magit-remote.el | 1052 |
1 files changed, 1052 insertions, 0 deletions
diff --git a/configs/shared/emacs/.emacs.d/elpa/magit-20180719.1904/magit-remote.el b/configs/shared/emacs/.emacs.d/elpa/magit-20180719.1904/magit-remote.el new file mode 100644 index 000000000000..7541f6e2705d --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/magit-20180719.1904/magit-remote.el @@ -0,0 +1,1052 @@ +;;; magit-remote.el --- transfer Git commits -*- lexical-binding: t -*- + +;; Copyright (C) 2008-2018 The Magit Project Contributors +;; +;; You should have received a copy of the AUTHORS.md file which +;; lists all contributors. If not, see http://magit.vc/authors. + +;; Author: Jonas Bernoulli <jonas@bernoul.li> +;; Maintainer: Jonas Bernoulli <jonas@bernoul.li> + +;; Magit is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; Magit is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +;; License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with Magit. If not, see http://www.gnu.org/licenses. + +;;; Commentary: + +;; This library implements support for interacting with remote +;; repositories. Commands for cloning, fetching, pulling, and +;; pushing are defined here. + +;;; Code: + +(require 'magit) + +;;; Options + +(defcustom magit-fetch-modules-jobs 4 + "Number of submodules to fetch in parallel. +Ignored for Git versions before v2.8.0." + :package-version '(magit . "2.12.0") + :group 'magit-commands + :type '(choice (const :tag "one at a time" nil) number)) + +;;; Clone + +(defcustom magit-clone-set-remote-head nil + "Whether cloning creates the symbolic-ref `<remote>/HEAD'." + :package-version '(magit . "2.4.2") + :group 'magit-commands + :type 'boolean) + +(defcustom magit-clone-set-remote.pushDefault 'ask + "Whether to set the value of `remote.pushDefault' after cloning. + +If t, then set without asking. If nil, then don't set. If +`ask', then ask." + :package-version '(magit . "2.4.0") + :group 'magit-commands + :type '(choice (const :tag "set" t) + (const :tag "ask" ask) + (const :tag "don't set" nil))) + +;;;###autoload +(defun magit-clone (repository directory) + "Clone the REPOSITORY to DIRECTORY. +Then show the status buffer for the new repository." + (interactive + (let ((url (magit-read-string-ns "Clone repository"))) + (list url (read-directory-name + "Clone to: " nil nil nil + (and (string-match "\\([^/:]+?\\)\\(/?\\.git\\)?$" url) + (match-string 1 url)))))) + (setq directory (file-name-as-directory (expand-file-name directory))) + (magit-run-git-async "clone" repository + (magit-convert-filename-for-git directory)) + ;; Don't refresh the buffer we're calling from. + (process-put magit-this-process 'inhibit-refresh t) + (set-process-sentinel + magit-this-process + (lambda (process event) + (when (memq (process-status process) '(exit signal)) + (let ((magit-process-raise-error t)) + (magit-process-sentinel process event))) + (when (and (eq (process-status process) 'exit) + (= (process-exit-status process) 0)) + (let ((default-directory directory)) + (when (or (eq magit-clone-set-remote.pushDefault t) + (and magit-clone-set-remote.pushDefault + (y-or-n-p "Set `remote.pushDefault' to \"origin\"? "))) + (setf (magit-get "remote.pushDefault") "origin")) + (unless magit-clone-set-remote-head + (magit-remote-unset-head "origin"))) + (with-current-buffer (process-get process 'command-buf) + (magit-status-internal directory)))))) + +;;; Remote +;;;; Options + +(defcustom magit-remote-add-set-remote.pushDefault 'ask-if-unset + "Whether to set the value of `remote.pushDefault' after adding a remote. + +If `ask', then always ask. If `ask-if-unset', then ask, but only +if the variable isn't set already. If nil, then don't ever set. +If the value is a string, then set without asking, provided that +the name of the added remote is equal to that string and the +variable isn't already set." + :package-version '(magit . "2.4.0") + :group 'magit-commands + :type '(choice (const :tag "ask if unset" ask-if-unset) + (const :tag "always ask" ask) + (string :tag "set if named") + (const :tag "don't set"))) + +(defcustom magit-remote-popup-show-variables t + "Whether the `magit-remote-popup' shows Git variables. +When set to nil, no variables are displayed directly in this +popup, instead the sub-popup `magit-remote-config-popup' has +to be used to view and change remote related variables." + :package-version '(magit . "2.12.0") + :group 'magit-commands + :type 'boolean) + +;;;; Popup + +(defvar magit-remote-config-variables) + +;;;###autoload (autoload 'magit-remote-popup "magit-remote" nil t) +(magit-define-popup magit-remote-popup + "Popup console for remote commands." + :man-page "git-remote" + :default-arguments '("-f") + :variables (lambda () + (and magit-remote-popup-show-variables + magit-remote-config-variables)) + :switches '("Switches for add" + (?f "Fetch after add" "-f")) + :actions '((?a "Add" magit-remote-add) + (?C "Configure..." magit-remote-config-popup) + (?r "Rename" magit-remote-rename) + (?p "Prune stale branches" magit-remote-prune) + (?k "Remove" magit-remote-remove) + (?P "Prune stale refspecs" magit-remote-prune-refspecs)) + :max-action-columns 2) + +;;;; Commands + +(defun magit-read-url (prompt &optional initial-input) + (let ((url (magit-read-string-ns prompt initial-input))) + (if (string-prefix-p "~" url) + (expand-file-name url) + url))) + +;;;###autoload +(defun magit-remote-add (remote url &optional args) + "Add a remote named REMOTE and fetch it." + (interactive (list (magit-read-string-ns "Remote name") + (magit-read-url "Remote url") + (magit-remote-arguments))) + (if (pcase (list magit-remote-add-set-remote.pushDefault + (magit-get "remote.pushDefault")) + (`(,(pred stringp) ,_) t) + ((or `(ask ,_) `(ask-if-unset nil)) + (y-or-n-p (format "Set `remote.pushDefault' to \"%s\"? " remote)))) + (progn (magit-call-git "remote" "add" args remote url) + (setf (magit-get "remote.pushDefault") remote) + (magit-refresh)) + (magit-run-git-async "remote" "add" args remote url))) + +;;;###autoload +(defun magit-remote-rename (old new) + "Rename the remote named OLD to NEW." + (interactive + (let ((remote (magit-read-remote "Rename remote"))) + (list remote (magit-read-string-ns (format "Rename %s to" remote))))) + (unless (string= old new) + (magit-call-git "remote" "rename" old new) + (magit-remote--cleanup-push-variables old new) + (magit-refresh))) + +;;;###autoload +(defun magit-remote-remove (remote) + "Delete the remote named REMOTE." + (interactive (list (magit-read-remote "Delete remote"))) + (magit-call-git "remote" "rm" remote) + (magit-remote--cleanup-push-variables remote) + (magit-refresh)) + +(defun magit-remote--cleanup-push-variables (remote &optional new-name) + (magit-with-toplevel + (when (equal (magit-get "remote.pushDefault") remote) + (magit-set new-name "remote.pushDefault")) + (dolist (var (magit-git-lines "config" "--name-only" + "--get-regexp" "^branch\.[^.]*\.pushRemote" + (format "^%s$" remote))) + (magit-call-git "config" (and (not new-name) "--unset") var new-name)))) + +(defconst magit--refspec-re "\\`\\(\\+\\)?\\([^:]+\\):\\(.*\\)\\'") + +;;;###autoload +(defun magit-remote-prune (remote) + "Remove stale remote-tracking branches for REMOTE." + (interactive (list (magit-read-remote "Prune stale branches of remote"))) + (magit-run-git-async "remote" "prune" remote)) + +;;;###autoload +(defun magit-remote-prune-refspecs (remote) + "Remove stale refspecs for REMOTE. + +A refspec is stale if there no longer exists at least one branch +on the remote that would be fetched due to that refspec. A stale +refspec is problematic because its existence causes Git to refuse +to fetch according to the remaining non-stale refspecs. + +If only stale refspecs remain, then offer to either delete the +remote or to replace the stale refspecs with the default refspec. + +Also remove the remote-tracking branches that were created due to +the now stale refspecs. Other stale branches are not removed." + (interactive (list (magit-read-remote "Prune refspecs of remote"))) + (let* ((tracking-refs (magit-list-remote-branches remote)) + (remote-refs (magit-remote-list-refs remote)) + (variable (format "remote.%s.fetch" remote)) + (refspecs (magit-get-all variable)) + stale) + (dolist (refspec refspecs) + (when (string-match magit--refspec-re refspec) + (let ((theirs (match-string 2 refspec)) + (ours (match-string 3 refspec))) + (unless (if (string-match "\\*" theirs) + (let ((re (replace-match ".*" t t theirs))) + (--some (string-match-p re it) remote-refs)) + (member theirs remote-refs)) + (push (cons refspec + (if (string-match "\\*" ours) + (let ((re (replace-match ".*" t t ours))) + (--filter (string-match-p re it) tracking-refs)) + (list (car (member ours tracking-refs))))) + stale))))) + (if (not stale) + (message "No stale refspecs for remote %S" remote) + (if (= (length stale) + (length refspecs)) + (magit-read-char-case + (format "All of %s's refspecs are stale. " remote) nil + (?s "replace with [d]efault refspec" + (magit-set-all + (list (format "+refs/heads/*:refs/remotes/%s/*" remote)) + variable)) + (?r "[r]emove remote" + (magit-call-git "remote" "rm" remote)) + (?a "or [a]abort" + (user-error "Abort"))) + (if (if (= (length stale) 1) + (pcase-let ((`(,refspec . ,refs) (car stale))) + (magit-confirm 'prune-stale-refspecs + (format "Prune stale refspec %s and branch %%s" refspec) + (format "Prune stale refspec %s and %%i branches" refspec) + nil refs)) + (magit-confirm 'prune-stale-refspecs nil + (format "Prune %%i stale refspecs and %i branches" + (length (cl-mapcan (lambda (s) (copy-sequence (cdr s))) + stale))) + nil + (mapcar (pcase-lambda (`(,refspec . ,refs)) + (concat refspec "\n" + (mapconcat (lambda (b) (concat " " b)) + refs "\n"))) + stale))) + (pcase-dolist (`(,refspec . ,refs) stale) + (magit-call-git "config" "--unset" variable + (regexp-quote refspec)) + (magit--log-action + (lambda (refs) + (format "Deleting %i branches" (length refs))) + (lambda (ref) + (format "Deleting branch %s (was %s)" ref + (magit-rev-parse "--short" ref))) + refs) + (dolist (ref refs) + (magit-call-git "update-ref" "-d" ref))) + (user-error "Abort"))) + (magit-refresh)))) + +;;;###autoload +(defun magit-remote-set-head (remote &optional branch) + "Set the local representation of REMOTE's default branch. +Query REMOTE and set the symbolic-ref refs/remotes/<remote>/HEAD +accordingly. With a prefix argument query for the branch to be +used, which allows you to select an incorrect value if you fancy +doing that." + (interactive + (let ((remote (magit-read-remote "Set HEAD for remote"))) + (list remote + (and current-prefix-arg + (magit-read-remote-branch (format "Set %s/HEAD to" remote) + remote nil nil t))))) + (magit-run-git "remote" "set-head" remote (or branch "--auto"))) + +;;;###autoload +(defun magit-remote-unset-head (remote) + "Unset the local representation of REMOTE's default branch. +Delete the symbolic-ref \"refs/remotes/<remote>/HEAD\"." + (interactive (list (magit-read-remote "Unset HEAD for remote"))) + (magit-run-git "remote" "set-head" remote "--delete")) + +;;;; Config Popup + +(defvar magit-remote-config--remote nil) + +;;;###autoload +(defun magit-remote-config-popup (remote) + "Popup console for setting remote variables." + (interactive + (list (if (or current-prefix-arg + (and (eq magit-current-popup 'magit-remote-popup) + magit-remote-popup-show-variables)) + (magit-read-remote "Configure remote") + (magit-remote-config--remote-1)))) + (let ((magit-remote-config--remote remote)) + (magit-invoke-popup 'magit-remote-config-popup nil nil))) + +(defvar magit-remote-config-variables + '((lambda () + (concat + (propertize "Configure " 'face 'magit-popup-heading) + (propertize (magit-remote-config--remote) 'face 'magit-branch-remote))) + (?u "remote.%s.url" + magit-set-remote*url + magit-format-remote*url) + (?U "remote.%s.fetch" + magit-set-remote*fetch + magit-format-remote*fetch) + (?s "remote.%s.pushurl" + magit-set-remote*pushurl + magit-format-remote*pushurl) + (?S "remote.%s.push" + magit-set-remote*push + magit-format-remote*push) + (?O "remote.%s.tagOpt" + magit-cycle-remote*tagOpt + magit-format-remote*tagOpt))) + +(defvar magit-remote-config-popup + `(:man-page "git-remote" + :variables ,magit-remote-config-variables + :setup-function magit-remote-config-popup-setup)) + +(defun magit-remote-config-popup-setup (val def) + (magit-popup-default-setup val def) + (setq-local magit-remote-config--remote magit-remote-config--remote)) + +(defun magit-remote-config--remote (&optional prompt) + (if prompt + (or (and (not current-prefix-arg) + (or magit-remote-config--remote + (magit-remote-config--remote-1))) + (magit-read-remote prompt)) + (or magit-remote-config--remote + (magit-remote-config--remote-1) + "<name>"))) + +(defun magit-remote-config--remote-1 () + (let ((remote (magit-get-upstream-remote))) + (if (or (not remote) + (equal remote ".")) + (and (magit-remote-p "origin") "origin") + remote))) + +;;;; Config Commands and Inserters + +(defun magit-set-remote*url (remote urls) + "Set the variable `url' for the remote named REMOTE to URLS." + (interactive (magit-remote-config--read-args "url" "Urls: ")) + (magit-remote-config--set-url remote "url" urls)) + +(defun magit-set-remote*fetch (remote values) + "Set the variable `fetch' for the remote named REMOTE to VALUES." + (interactive (magit-remote-config--read-args "fetch" "Fetch specs: ")) + (magit-set-all values "remote" remote "fetch") + (magit-refresh)) + +(defun magit-set-remote*pushurl (remote urls) + "Set the variable `pushurl' for the remote named REMOTE to URLS." + (interactive (magit-remote-config--read-args "pushurl" "Urls: ")) + (magit-remote-config--set-url remote "pushurl" urls "--push")) + +(defun magit-set-remote*push (remote values) + "Set the variable `push' for the remote named REMOTE to VALUES." + (interactive (magit-remote-config--read-args "push" "Push specs: ")) + (magit-set-all values "remote" remote "push") + (magit-refresh)) + +(defun magit-cycle-remote*tagOpt (remote) + (interactive (list (magit-remote-config--remote))) + (magit--set-popup-variable (format "remote.%s.tagOpt" remote) + '("--no-tags" "--tags") nil)) + +(defun magit-format-remote*url () + (magit-remote-config--format-variable "url")) + +(defun magit-format-remote*fetch () + (magit-remote-config--format-variable "fetch")) + +(defun magit-format-remote*pushurl () + (magit-remote-config--format-variable "pushurl")) + +(defun magit-format-remote*push () + (magit-remote-config--format-variable "push")) + +(defun magit-format-remote*tagOpt () + (let ((remote (magit-remote-config--remote))) + (magit--format-popup-variable:choices + (format "remote.%s.tagOpts" remote) + '("--no-tags" "--tags") nil nil + (+ (length remote) 16)))) + +(defun magit-remote-config--read-args (var prompt) + (let* ((remote (magit-remote-config--remote (format "Set `%s' of remote" var))) + (value (magit-get-all "remote" remote var))) + (list remote + (mapcar (lambda (url) + (if (string-prefix-p "~" url) + (expand-file-name url) + url)) + (completing-read-multiple + prompt nil nil nil + (and value (mapconcat #'identity value ","))))))) + +(defun magit-remote-config--set-url (remote var values &optional arg) + (let ((old (magit-get-all "remote" remote var))) + (dolist (v (-difference values old)) + (magit-call-git "remote" "set-url" arg "--add" remote v)) + (dolist (v (-difference old values)) + (magit-call-git "remote" "set-url" arg "--delete" remote + (concat "^" (regexp-quote v) "$")))) + (magit-refresh)) + +(defun magit-remote-config--format-variable (variable) + (magit--format-popup-variable:values + (format "remote.%s.%s" (magit-remote-config--remote) variable) + 25)) + +;;; Fetch + +;;;###autoload (autoload 'magit-fetch-popup "magit-remote" nil t) +(magit-define-popup magit-fetch-popup + "Popup console for fetch commands." + :man-page "git-fetch" + :switches '((?p "Prune deleted branches" "--prune")) + :actions '("Configure" + (?C "variables..." magit-branch-config-popup) + "Fetch from" + (?p magit-get-push-remote magit-fetch-from-pushremote) + (?u magit-get-remote magit-fetch-from-upstream) + (?e "elsewhere" magit-fetch) + (?a "all remotes" magit-fetch-all) + "Fetch" + (?o "another branch" magit-fetch-branch) + (?r "explicit refspec" magit-fetch-refspec) + (?m "submodules" magit-fetch-modules)) + :default-action 'magit-fetch + :max-action-columns 1) + +(defun magit-git-fetch (remote args) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "fetch" remote args)) + +;;;###autoload +(defun magit-fetch-from-pushremote (args) + "Fetch from the push-remote of the current branch." + (interactive (list (magit-fetch-arguments))) + (--if-let (magit-get-push-remote) + (magit-git-fetch it args) + (--if-let (magit-get-current-branch) + (user-error "No push-remote is configured for %s" it) + (user-error "No branch is checked out")))) + +;;;###autoload +(defun magit-fetch-from-upstream (args) + "Fetch from the upstream repository of the current branch." + (interactive (list (magit-fetch-arguments))) + (--if-let (magit-get-remote) + (magit-git-fetch it args) + (--if-let (magit-get-current-branch) + (user-error "No upstream is configured for %s" it) + (user-error "No branch is checked out")))) + +;;;###autoload +(defun magit-fetch (remote args) + "Fetch from another repository." + (interactive (list (magit-read-remote "Fetch remote") + (magit-fetch-arguments))) + (magit-git-fetch remote args)) + +;;;###autoload +(defun magit-fetch-branch (remote branch args) + "Fetch a BRANCH from a REMOTE." + (interactive + (let ((remote (magit-read-remote-or-url "Fetch from remote or url"))) + (list remote + (magit-read-remote-branch "Fetch branch" remote) + (magit-fetch-arguments)))) + (magit-git-fetch remote (cons branch args))) + +;;;###autoload +(defun magit-fetch-refspec (remote refspec args) + "Fetch a REFSPEC from a REMOTE." + (interactive + (let ((remote (magit-read-remote-or-url "Fetch from remote or url"))) + (list remote + (magit-read-refspec "Fetch using refspec" remote) + (magit-fetch-arguments)))) + (magit-git-fetch remote (cons refspec args))) + +;;;###autoload +(defun magit-fetch-all (args) + "Fetch from all remotes." + (interactive (list (cl-intersection (magit-fetch-arguments) + (list "--verbose" "--prune") + :test #'equal))) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "remote" "update" args)) + +;;;###autoload +(defun magit-fetch-all-prune () + "Fetch from all remotes, and prune. +Prune remote tracking branches for branches that have been +removed on the respective remote." + (interactive) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "remote" "update" "--prune")) + +;;;###autoload +(defun magit-fetch-all-no-prune () + "Fetch from all remotes." + (interactive) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "remote" "update")) + +;;;###autoload +(defun magit-fetch-modules (&optional all) + "Fetch all submodules. + +Option `magit-fetch-modules-jobs' controls how many submodules +are being fetched in parallel. Also fetch the super-repository, +because `git-fetch' does not support not doing that. With a +prefix argument fetch all remotes." + (interactive "P") + (magit-with-toplevel + (magit-run-git-async + "fetch" "--verbose" "--recurse-submodules" + (and magit-fetch-modules-jobs + (version<= "2.8.0" (magit-git-version)) + (list "-j" (number-to-string magit-fetch-modules-jobs))) + (and all "--all")))) + +;;; Pull + +;;;###autoload (autoload 'magit-pull-popup "magit-remote" nil t) +(magit-define-popup magit-pull-popup + "Popup console for pull commands." + :man-page "git-pull" + :variables '("Configure" + (?r "branch.%s.rebase" + magit-cycle-branch*rebase + magit-pull-format-branch*rebase) + (?C "variables..." magit-branch-config-popup)) + :actions '((lambda () + (--if-let (magit-get-current-branch) + (concat + (propertize "Pull into " 'face 'magit-popup-heading) + (propertize it 'face 'magit-branch-local) + (propertize " from" 'face 'magit-popup-heading)) + (propertize "Pull from" 'face 'magit-popup-heading))) + (?p magit-get-push-branch magit-pull-from-pushremote) + (?u magit-get-upstream-branch magit-pull-from-upstream) + (?e "elsewhere" magit-pull)) + :default-action 'magit-pull + :max-action-columns 1) + +;;;###autoload (autoload 'magit-pull-and-fetch-popup "magit-remote" nil t) +(magit-define-popup magit-pull-and-fetch-popup + "Popup console for pull and fetch commands. + +This popup is intended as a replacement for the separate popups +`magit-pull-popup' and `magit-fetch-popup'. To use it, add this +to your init file: + + (with-eval-after-load \\='magit-remote + (define-key magit-mode-map \"f\" \\='magit-pull-and-fetch-popup) + (define-key magit-mode-map \"F\" nil)) + +The combined popup does not offer all commands and arguments +available from the individual popups. Instead of the argument +`--prune' and the command `magit-fetch-all' it uses two commands +`magit-fetch-prune' and `magit-fetch-no-prune'. And the commands +`magit-fetch-from-pushremote' and `magit-fetch-from-upstream' are +missing. To add them use something like: + + (with-eval-after-load \\='magit-remote + (magit-define-popup-action \\='magit-pull-and-fetch-popup ?U + \\='magit-get-upstream-branch + \\='magit-fetch-from-upstream-remote ?F) + (magit-define-popup-action \\='magit-pull-and-fetch-popup ?P + \\='magit-get-push-branch + \\='magit-fetch-from-push-remote ?F))" + :man-page "git-pull" + :variables '("Configure" + (?r "branch.%s.rebase" + magit-cycle-branch*rebase + magit-pull-format-branch*rebase) + (?C "variables..." magit-branch-config-popup)) + :actions '((lambda () + (--if-let (magit-get-current-branch) + (concat + (propertize "Pull into " 'face 'magit-popup-heading) + (propertize it 'face 'magit-branch-local) + (propertize " from" 'face 'magit-popup-heading)) + (propertize "Pull from" 'face 'magit-popup-heading))) + (?p magit-get-push-branch magit-pull-from-pushremote) + (?u magit-get-upstream-branch magit-pull-from-upstream) + (?e "elsewhere" magit-pull) + "Fetch from" + (?f "remotes" magit-fetch-all-no-prune) + (?F "remotes and prune" magit-fetch-all-prune) + "Fetch" + (?o "another branch" magit-fetch-branch) + (?s "explicit refspec" magit-fetch-refspec) + (?m "submodules" magit-fetch-modules)) + :default-action 'magit-fetch + :max-action-columns 1) + +(defun magit-pull-format-branch*rebase () + (magit--format-popup-variable:choices + (format "branch.%s.rebase" (or (magit-get-current-branch) "<name>")) + '("true" "false") + "false" "pull.rebase")) + +(defun magit-git-pull (source args) + (run-hooks 'magit-credential-hook) + (pcase-let ((`(,remote . ,branch) + (magit-split-branch-name source))) + (magit-run-git-with-editor "pull" args remote branch))) + +;;;###autoload +(defun magit-pull-from-pushremote (args) + "Pull from the push-remote of the current branch." + (interactive (list (magit-pull-arguments))) + (--if-let (magit-get-push-branch) + (magit-git-pull it args) + (--if-let (magit-get-current-branch) + (user-error "No push-remote is configured for %s" it) + (user-error "No branch is checked out")))) + +;;;###autoload +(defun magit-pull-from-upstream (args) + "Pull from the upstream of the current branch." + (interactive (list (magit-pull-arguments))) + (--if-let (magit-get-upstream-branch) + (progn (run-hooks 'magit-credential-hook) + (magit-run-git-with-editor + "pull" args (car (magit-split-branch-name it)))) + (--if-let (magit-get-current-branch) + (user-error "No upstream is configured for %s" it) + (user-error "No branch is checked out")))) + +;;;###autoload +(defun magit-pull (source args) + "Pull from a branch read in the minibuffer." + (interactive (list (magit-read-remote-branch "Pull" nil nil nil t) + (magit-pull-arguments))) + (magit-git-pull source args)) + +;;; Push + +(defcustom magit-push-current-set-remote-if-missing t + "Whether to configure missing remotes before pushing. + +When nil, then the command `magit-push-current-to-pushremote' and +`magit-push-current-to-upstream' do not appear in the push popup +if the push-remote resp. upstream is not configured. If the user +invokes one of these commands anyway, then it raises an error. + +When non-nil, then these commands always appear in the push +popup. But if the required configuration is missing, then they +do appear in a way that indicates that this is the case. If the +user invokes one of them, then it asks for the necessary +configuration, stores the configuration, and then uses it to push +a first time. + +This option also affects whether the argument `--set-upstream' is +available in the popup. If the value is t, then that argument is +redundant. But note that changing the value of this option does +not take affect immediately, the argument will only be added or +removed after restarting Emacs." + :package-version '(magit . "2.6.0") + :group 'magit-commands + :type '(choice (const :tag "don't set" nil) + (const :tag "set branch.<name>.pushRemote" t) + (const :tag "set remote.pushDefault" default))) + +;;;###autoload (autoload 'magit-push-popup "magit-remote" nil t) +(magit-define-popup magit-push-popup + "Popup console for push commands." + :man-page "git-push" + :switches `((?f "Force with lease" "--force-with-lease") + (?F "Force" "--force") + (?h "Disable hooks" "--no-verify") + (?d "Dry run" "--dry-run") + ,@(and (not magit-push-current-set-remote-if-missing) + '((?u "Set upstream" "--set-upstream")))) + :actions '("Configure" + (?C "variables..." magit-branch-config-popup) + (lambda () + (--when-let (magit-get-current-branch) + (concat (propertize "Push " 'face 'magit-popup-heading) + (propertize it 'face 'magit-branch-local) + (propertize " to" 'face 'magit-popup-heading)))) + (?p magit--push-current-to-pushremote-desc + magit-push-current-to-pushremote) + (?u magit--push-current-to-upstream-desc + magit-push-current-to-upstream) + (?e "elsewhere\n" magit-push-current) + "Push" + (?o "another branch" magit-push) + (?T "a tag" magit-push-tag) + (?r "explicit refspecs" magit-push-refspecs) + (?t "all tags" magit-push-tags) + (?m "matching branches" magit-push-matching)) + :max-action-columns 2) + +(defun magit-git-push (branch target args) + (run-hooks 'magit-credential-hook) + (pcase-let ((`(,remote . ,target) + (magit-split-branch-name target))) + (magit-run-git-async "push" "-v" args remote + (format "%s:refs/heads/%s" branch target)))) + +;;;###autoload +(defun magit-push-current-to-pushremote (args &optional push-remote) + "Push the current branch to `branch.<name>.pushRemote'. +If that variable is unset, then push to `remote.pushDefault'. + +When `magit-push-current-set-remote-if-missing' is non-nil and +the push-remote is not configured, then read the push-remote from +the user, set it, and then push to it. With a prefix argument +the push-remote can be changed before pushed to it." + (interactive + (list (magit-push-arguments) + (and (magit--push-current-set-pushremote-p current-prefix-arg) + (magit-read-remote + (if (eq magit-push-current-set-remote-if-missing 'default) + "Set `remote.pushDefault' and push there" + (format "Set `branch.%s.pushRemote' and push there" + (magit-get-current-branch))))))) + (--if-let (magit-get-current-branch) + (progn (when push-remote + (setf (magit-get + (if (eq magit-push-current-set-remote-if-missing 'default) + "remote.pushDefault" + (format "branch.%s.pushRemote" it))) + push-remote)) + (if-let ((remote (magit-get-push-remote it))) + (if (member remote (magit-list-remotes)) + (magit-git-push it (concat remote "/" it) args) + (user-error "Remote `%s' doesn't exist" remote)) + (user-error "No push-remote is configured for %s" it))) + (user-error "No branch is checked out"))) + +(defun magit--push-current-set-pushremote-p (&optional change) + (and (or change + (and magit-push-current-set-remote-if-missing + (not (magit-get-push-remote)))) + (magit-get-current-branch))) + +(defun magit--push-current-to-pushremote-desc () + (--if-let (magit-get-push-branch) + (concat (magit-branch-set-face it) "\n") + (and (magit--push-current-set-pushremote-p) + (concat + (propertize (if (eq magit-push-current-set-remote-if-missing 'default) + "pushDefault" + "pushRemote") + 'face 'bold) + ", after setting that\n")))) + +;;;###autoload +(defun magit-push-current-to-upstream (args &optional upstream) + "Push the current branch to its upstream branch. + +When `magit-push-current-set-remote-if-missing' is non-nil and +the upstream is not configured, then read the upstream from the +user, set it, and then push to it. With a prefix argument the +upstream can be changed before pushed to it." + (interactive + (list (magit-push-arguments) + (and (magit--push-current-set-upstream-p current-prefix-arg) + (magit-read-upstream-branch)))) + (--if-let (magit-get-current-branch) + (progn + (when upstream + (magit-set-branch*merge/remote it upstream)) + (if-let ((target (magit-get-upstream-branch it))) + (magit-git-push it target args) + (user-error "No upstream is configured for %s" it))) + (user-error "No branch is checked out"))) + +(defun magit--push-current-set-upstream-p (&optional change) + (and (or change + (and magit-push-current-set-remote-if-missing + (not (magit-get-upstream-branch)))) + (magit-get-current-branch))) + +(defun magit--push-current-to-upstream-desc () + (--if-let (magit-get-upstream-branch) + (concat (magit-branch-set-face it) "\n") + (and (magit--push-current-set-upstream-p) + (concat (propertize "@{upstream}" 'face 'bold) + ", after setting that\n")))) + +;;;###autoload +(defun magit-push-current (target args) + "Push the current branch to a branch read in the minibuffer." + (interactive + (--if-let (magit-get-current-branch) + (list (magit-read-remote-branch (format "Push %s to" it) + nil nil it 'confirm) + (magit-push-arguments)) + (user-error "No branch is checked out"))) + (magit-git-push (magit-get-current-branch) target args)) + +;;;###autoload +(defun magit-push (source target args) + "Push an arbitrary branch or commit somewhere. +Both the source and the target are read in the minibuffer." + (interactive + (let ((source (magit-read-local-branch-or-commit "Push"))) + (list source + (magit-read-remote-branch + (format "Push %s to" source) nil + (if (magit-local-branch-p source) + (or (magit-get-push-branch source) + (magit-get-upstream-branch source)) + (and (magit-rev-ancestor-p source "HEAD") + (or (magit-get-push-branch) + (magit-get-upstream-branch)))) + source 'confirm) + (magit-push-arguments)))) + (magit-git-push source target args)) + +(defvar magit-push-refspecs-history nil) + +;;;###autoload +(defun magit-push-refspecs (remote refspecs args) + "Push one or multiple REFSPECS to a REMOTE. +Both the REMOTE and the REFSPECS are read in the minibuffer. To +use multiple REFSPECS, separate them with commas. Completion is +only available for the part before the colon, or when no colon +is used." + (interactive + (list (magit-read-remote "Push to remote") + (split-string (magit-completing-read-multiple + "Push refspec,s" + (cons "HEAD" (magit-list-local-branch-names)) + nil nil 'magit-push-refspecs-history) + crm-default-separator t) + (magit-push-arguments))) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "push" "-v" args remote refspecs)) + +;;;###autoload +(defun magit-push-matching (remote &optional args) + "Push all matching branches to another repository. +If multiple remotes exist, then read one from the user. +If just one exists, use that without requiring confirmation." + (interactive (list (magit-read-remote "Push matching branches to" nil t) + (magit-push-arguments))) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "push" "-v" args remote ":")) + +;;;###autoload +(defun magit-push-tags (remote &optional args) + "Push all tags to another repository. +If only one remote exists, then push to that. Otherwise prompt +for a remote, offering the remote configured for the current +branch as default." + (interactive (list (magit-read-remote "Push tags to remote" nil t) + (magit-push-arguments))) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "push" remote "--tags" args)) + +;;;###autoload +(defun magit-push-tag (tag remote &optional args) + "Push a tag to another repository." + (interactive + (let ((tag (magit-read-tag "Push tag"))) + (list tag (magit-read-remote (format "Push %s to remote" tag) nil t) + (magit-push-arguments)))) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "push" remote tag args)) + +;;;###autoload +(defun magit-push-implicitly (args) + "Push somewhere without using an explicit refspec. + +This command simply runs \"git push -v [ARGS]\". ARGS are the +arguments specified in the popup buffer. No explicit refspec +arguments are used. Instead the behavior depends on at least +these Git variables: `push.default', `remote.pushDefault', +`branch.<branch>.pushRemote', `branch.<branch>.remote', +`branch.<branch>.merge', and `remote.<remote>.push'. + +To add this command to the push popup add this to your init file: + + (with-eval-after-load \\='magit-remote + (magit-define-popup-action \\='magit-push-popup ?P + \\='magit-push-implicitly--desc + \\='magit-push-implicitly ?p t)) + +The function `magit-push-implicitly--desc' attempts to predict +what this command will do. The value it returns is displayed in +the popup buffer." + (interactive (list (magit-push-arguments))) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "push" "-v" args)) + +(defun magit-push-implicitly--desc () + (let ((default (magit-get "push.default"))) + (unless (equal default "nothing") + (or (when-let ((remote (or (magit-get-remote) + (magit-remote-p "origin"))) + (refspec (magit-get "remote" remote "push"))) + (format "%s using %s" + (propertize remote 'face 'magit-branch-remote) + (propertize refspec 'face 'bold))) + (--when-let (and (not (magit-get-push-branch)) + (magit-get-upstream-branch)) + (format "%s aka %s\n" + (magit-branch-set-face it) + (propertize "@{upstream}" 'face 'bold))) + (--when-let (magit-get-push-branch) + (format "%s aka %s\n" + (magit-branch-set-face it) + (propertize "pushRemote" 'face 'bold))) + (--when-let (magit-get-@{push}-branch) + (format "%s aka %s\n" + (magit-branch-set-face it) + (propertize "@{push}" 'face 'bold))) + (format "using %s (%s is %s)\n" + (propertize "git push" 'face 'bold) + (propertize "push.default" 'face 'bold) + (propertize default 'face 'bold)))))) + +;;;###autoload +(defun magit-push-to-remote (remote args) + "Push to REMOTE without using an explicit refspec. +The REMOTE is read in the minibuffer. + +This command simply runs \"git push -v [ARGS] REMOTE\". ARGS +are the arguments specified in the popup buffer. No refspec +arguments are used. Instead the behavior depends on at least +these Git variables: `push.default', `remote.pushDefault', +`branch.<branch>.pushRemote', `branch.<branch>.remote', +`branch.<branch>.merge', and `remote.<remote>.push'. + +To add this command to the push popup add this to your init file: + + (with-eval-after-load \\='magit-remote + (magit-define-popup-action \\='magit-push-popup ?r + \\='magit-push-to-remote--desc + \\='magit-push-to-remote ?p t))" + (interactive (list (magit-read-remote "Push to remote") + (magit-push-arguments))) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "push" "-v" args remote)) + +(defun magit-push-to-remote--desc () + (format "using %s\n" (propertize "git push <remote>" 'face 'bold))) + +;;; Email + +;;;###autoload (autoload 'magit-patch-popup "magit-remote" nil t) +(magit-define-popup magit-patch-popup + "Popup console for patch commands." + :man-page "git-format-patch" + :switches '("Switches for formatting patches" + (?l "Add cover letter" "--cover-letter")) + :options '("Options for formatting patches" + (?f "From" "--from=") + (?t "To" "--to=") + (?c "CC" "--cc=") + (?r "In reply to" "--in-reply-to=") + (?P "Subject Prefix" "--subject-prefix=") + (?v "Reroll count" "--reroll-count=") + (?s "Thread style" "--thread=") + (?U "Context lines" "-U") + (?M "Detect renames" "-M") + (?C "Detect copies" "-C") + (?A "Diff algorithm" "--diff-algorithm=" + magit-diff-select-algorithm) + (?o "Output directory" "--output-directory=")) + :actions '((?p "Format patches" magit-format-patch) + (?r "Request pull" magit-request-pull)) + :default-action 'magit-format-patch) + +;;;###autoload +(defun magit-format-patch (range args) + "Create patches for the commits in RANGE. +When a single commit is given for RANGE, create a patch for the +changes introduced by that commit (unlike 'git format-patch' +which creates patches for all commits that are reachable from +`HEAD' but not from the specified commit)." + (interactive + (list (if-let ((revs (magit-region-values 'commit t))) + (concat (car (last revs)) "^.." (car revs)) + (let ((range (magit-read-range-or-commit "Format range or commit"))) + (if (string-match-p "\\.\\." range) + range + (format "%s~..%s" range range)))) + (magit-patch-arguments))) + (magit-call-git "format-patch" range args) + (when (member "--cover-letter" args) + (find-file + (expand-file-name + "0000-cover-letter.patch" + (let ((topdir (magit-toplevel))) + (or (--some (and (string-match "--output-directory=\\(.+\\)" it) + (expand-file-name (match-string 1 it) topdir)) + args) + topdir)))))) + +;;;###autoload +(defun magit-request-pull (url start end) + "Request upstream to pull from you public repository. + +URL is the url of your publically accessible repository. +START is a commit that already is in the upstream repository. +END is the last commit, usually a branch name, which upstream +is asked to pull. START has to be reachable from that commit." + (interactive + (list (magit-get "remote" (magit-read-remote "Remote") "url") + (magit-read-branch-or-commit "Start" (magit-get-upstream-branch)) + (magit-read-branch-or-commit "End"))) + (let ((dir default-directory)) + ;; mu4e changes default-directory + (compose-mail) + (setq default-directory dir)) + (message-goto-body) + (magit-git-insert "request-pull" start url end) + (set-buffer-modified-p nil)) + +(provide 'magit-remote) +;;; magit-remote.el ends here |