Commit 0b709443 authored by Jonas Bernoulli's avatar Jonas Bernoulli

add new push and pull commands

Previously only one command to push a branch and one command to pull a
branch existed.  Now there are several variants for pushing as well as
pulling.  They are all available from the respective popup which makes
it much easier to push to or pull from a branch which is not the already
configured upstream branch of the currently checked out branch.

Previously one had to remember exactly how many prefix arguments on had
to use to do something "unusual" and even then most "unusual" things
were not possible.  I for one did at least 2/3 of my pushes and pulls
in a terminal, but no more.

Add new commands `magit-pull-current', `magit-push-current',
`magit-push-elsewhere' and `magit-push-matching'.  Add the functions
`magit-pull-read-args' and `magit-push-read-args.  And adjust the
`magit-pull-popup' and `magit-push-popup popups, as well as the
function `magit-read-remote-branch' accordingly.
parent d1364010
......@@ -775,8 +775,14 @@ Return a list of two integers: (A>B B>A)."
(user-error "Nothing selected")))
(defun magit-read-remote-branch (prompt &optional remote default require-match)
(magit-completing-read prompt (magit-list-remote-branch-names remote t)
nil require-match nil 'magit-revision-history default))
(when (consp default)
(setq default (concat (car default) "/" (cdr default))))
(let ((branch (magit-completing-read
prompt (magit-list-remote-branch-names remote t)
nil require-match nil 'magit-revision-history default)))
(string-match "^\\([^/]+\\)/\\(.+\\)" branch)
(cons (match-string 1 branch)
(match-string 2 branch))))
(defun magit-read-local-branch (prompt &optional default)
(magit-completing-read prompt (magit-list-local-branch-names)
......@@ -113,62 +113,27 @@ If there is no default remote, ask for one."
:man-page "git-pull"
:switches '((?r "Rebase" "--rebase"))
:actions '((?F "Pull" magit-pull))
:default-action 'magit-pull)
:actions '((?F "Current" magit-pull-current)
(?o "Other" magit-pull))
:default-action 'magit-pull-current)
(defun magit-pull ()
"Pull changes from a remote repository.
If there is no default remote, the user is prompted for one and
the chosen values is saved. If there is no default merge branch,
the user is prompted for one and the chosen values is saved.
With a prefix argument, the default remote is not used and the
user is prompted for a remote. With two prefix arguments, the
default merge branch is not used and the user is prompted for
a merge branch. Values entered by the user because of prefix
arguments are not saved."
(let* ((branch (magit-get-current-branch))
(branch-remote (magit-get-current-remote))
(branch-merge (magit-get "branch" branch "merge"))
(branch-merge-name (and branch-merge
(string-match "^refs/heads/\\(.+\\)"
(match-string 1 branch-merge))))
(choose-remote (>= (prefix-numeric-value current-prefix-arg) 4))
(choose-branch (>= (prefix-numeric-value current-prefix-arg) 16))
(remote-needed (or choose-remote
(not branch-remote)))
(branch-needed (or choose-branch
(not branch-merge-name)))
(if remote-needed
(magit-read-remote "Pull from remote" branch-remote)
(if branch-needed
(magit-read-remote-branch (format "Pull branch from remote %s"
chosen-branch-remote nil t)
(when (and (not branch-remote)
(not choose-remote))
(magit-set chosen-branch-remote "branch" branch "remote"))
(when (and (not branch-merge-name)
(not choose-branch))
(magit-set (format "%s" chosen-branch-merge-name)
"branch" branch "merge"))
"pull" magit-current-popup-args
(and choose-remote chosen-branch-remote)
(and (or choose-remote choose-branch)
(list (format "refs/heads/%s:refs/remotes/%s/%s"
(defun magit-pull-current (remote branch &optional args)
"Fetch from another repository and merge into current branch."
(interactive (magit-pull-read-args t))
(magit-run-git-async "pull" args remote branch))
(defun magit-pull (remote branch &optional args)
"Fetch from another repository and merge a fetched branch."
(interactive (magit-pull-read-args))
(magit-run-git-async "pull" args remote branch))
(defun magit-pull-read-args (&optional use-upstream)
(let ((remote (magit-get-remote-branch)))
(unless (and use-upstream remote)
(setq remote (magit-read-remote-branch "Pull" nil remote t)))
(list (car remote) (cdr remote) magit-current-popup-args)))
;;; Push
......@@ -181,41 +146,60 @@ arguments are not saved."
(?h "Disable hooks" "--no-verify")
(?d "Dry run" "--dry-run")
(?u "Set upstream" "--set-upstream"))
:actions '((?P "Push" magit-push)
(?t "Push tags" magit-push-tags))
:default-action 'magit-push)
:actions '((?P "Current" magit-push-current)
(?o "Other" magit-push)
(?e "Elsewhere" magit-push-elsewhere)
(?m "Matching" magit-push-matching)
(?t "Tags" magit-push-tags))
:default-action 'magit-push-current)
(defun magit-push-current (branch remote &optional remote-branch args)
"Push the current branch to its upstream branch.
If the upstream isn't set, then read the remote branch."
(interactive (magit-push-read-args t t))
(magit-push branch remote remote-branch args))
(defun magit-push (branch remote &optional remote-branch args)
"Push a branch to its upstream branch.
If the upstream isn't set, then read the remote branch."
(interactive (magit-push-read-args t))
(magit-run-git-async "push" "-v" args remote
(if remote-branch
(format "%s:refs/heads/%s" branch remote-branch)
(defun magit-push-elsewhere (branch remote remote-branch &optional args)
"Push a branch or commit to some remote branch.
Read the local and remote branch."
(interactive (magit-push-read-args))
(magit-push branch remote remote-branch args))
(defun magit-push-read-args (&optional use-upstream use-current)
(let* ((local (or (and use-current (magit-get-current-branch))
"Push" (--if-let (magit-commit-at-point)
(cons it (magit-list-local-branch-names))
nil nil nil 'magit-revision-history
(user-error "Nothing selected")))
(remote (and (magit-branch-p local)
(magit-get-remote-branch local))))
(unless (and use-upstream remote)
(setq remote (magit-read-remote-branch (format "Push %s to" local)
nil remote 'confirm)))
(list local (car remote) (cdr remote) magit-current-popup-args)))
(defun magit-push (arg)
"Push the current branch to a remote repository.
With a single prefix argument ask the user what remote to push
to. With two or more prefix arguments also ask the user the
name of the remote branch to push to.
Otherwise use the remote and branch as configured using the
Git variables `branch.<name>.remote' and `branch.<name>.merge'.
If the former is undefined ask the user. If the latter is
undefined push without specifing the remote branch explicitly."
(interactive "P")
(let* ((branch (or (magit-get-current-branch)
(user-error "Don't push a detached head. That's gross")))
(auto-remote (magit-get-current-remote))
(used-remote (if (or arg (not auto-remote))
(format "Push %s to remote" branch) auto-remote)
(auto-branch (and (equal used-remote auto-remote)
(magit-get "branch" branch "merge")))
(used-branch (if (>= (prefix-numeric-value arg) 16)
(format "Push %s as branch" branch)
used-remote auto-branch)
"push" "-v" used-remote
(if used-branch (format "%s:%s" branch used-branch) branch)
(defun magit-push-matching (remote &optional args)
"Push all matching branches to another repository.
If multiple remotes exit, 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-run-git-async "push" "-v" args remote ":"))
(defun magit-push-tags (remote &optional args)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment