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

magit-remote-prune-refspecs: new command

Re #3134.
parent 00552fd1
......@@ -273,6 +273,10 @@ Changes since v2.11.0
By default that is now also done for `untracked, `unstaged' and
`staged' sections. #2780
* Added command `magit-remote-prune-refspec', which is necessary
because Git does not ignore invalid refspecs and instead refuses
to fetch using only the refspecs that are still valid. #3134
Fixes since v2.11.0
-------------------
......
......@@ -7,7 +7,7 @@
#+TEXINFO_DIR_CATEGORY: Emacs
#+TEXINFO_DIR_TITLE: Magit: (magit).
#+TEXINFO_DIR_DESC: Using Git from Emacs with Magit.
#+SUBTITLE: for version 2.11.0 (2.11.0-381-g1c3529a54+1)
#+SUBTITLE: for version 2.11.0 (2.11.0-400-g00552fd10+1)
#+BIND: ox-texinfo+-before-export-hook ox-texinfo+-update-version-strings
#+TEXINFO_DEFFN: t
......@@ -22,7 +22,7 @@ directly from within Emacs. While many fine Git clients exist, only
Magit and Git itself deserve to be called porcelains.
#+TEXINFO: @noindent
This manual is for Magit version 2.11.0 (2.11.0-381-g1c3529a54+1).
This manual is for Magit version 2.11.0 (2.11.0-400-g00552fd10+1).
#+BEGIN_QUOTE
Copyright (C) 2015-2018 Jonas Bernoulli <jonas@bernoul.li>
......@@ -5348,6 +5348,12 @@ Also see [[man:git-remote]]
Delete a remote, read from the minibuffer.
- Key: M p, magit-remote-prune-refspecs
Remove stale refspecs and tracking branches for REMOTE. If there
are only stale refspecs, then offer to either delete the remote or
replace the refspecs with the default refspec instead.
- User Option: magit-remote-add-set-remote.pushDefault
Whether to set the value of ~remote.pushDefault~ after adding a
......
......@@ -30,7 +30,7 @@ General Public License for more details.
@finalout
@titlepage
@title Magit User Manual
@subtitle for version 2.11.0 (2.11.0-381-g1c3529a54+1)
@subtitle for version 2.11.0 (2.11.0-400-g00552fd10+1)
@author Jonas Bernoulli
@page
@vskip 0pt plus 1filll
......@@ -52,7 +52,7 @@ directly from within Emacs. While many fine Git clients exist, only
Magit and Git itself deserve to be called porcelains.
@noindent
This manual is for Magit version 2.11.0 (2.11.0-381-g1c3529a54+1).
This manual is for Magit version 2.11.0 (2.11.0-400-g00552fd10+1).
@quotation
Copyright (C) 2015-2018 Jonas Bernoulli <jonas@@bernoul.li>
......@@ -1511,6 +1511,16 @@ then the previous visibility is preserved. The initial visibility of
certain sections can also be overwritten using the hook
@code{magit-section-set-visibility-hook}.
@defopt magit-section-cache-visibility-types
This option controls for which sections the previous visibility
state should be restored if a section disappears and later appears
again. The value is a list of section types.
This requires that @code{magit-section-cached-visibility} is a member of
@code{magit-section-set-visibility-hook}.
@end defopt
@defvar magit-section-set-visibility-hook
This hook is run when first creating a buffer and also when
......@@ -7290,6 +7300,14 @@ read in the minibuffer.
Delete a remote, read from the minibuffer.
@kindex M p
@cindex magit-remote-prune-refspecs
@item @kbd{M p} @tie{}@tie{}@tie{}@tie{}(@code{magit-remote-prune-refspecs})
Remove stale refspecs and tracking branches for REMOTE. If there
are only stale refspecs, then offer to either delete the remote or
replace the refspecs with the default refspec instead.
@end table
@defopt magit-remote-add-set-remote.pushDefault
......
......@@ -124,10 +124,12 @@ to be used to view and change remote related variables."
magit-remote-config-variables))
:switches '("Switches for add"
(?f "Fetch after add" "-f"))
:actions '((?a "Add" magit-remote-add)
(?r "Rename" magit-remote-rename)
(?k "Remove" magit-remote-remove)
(?C "Configure..." magit-remote-config-popup)))
:actions '((?a "Add" magit-remote-add)
(?C "Configure..." magit-remote-config-popup)
(?r "Rename" magit-remote-rename)
(?p "Prune refspecs" magit-remote-prune-refspecs)
(?k "Remove" magit-remote-remove))
:max-action-columns 2)
;;;; Commands
......@@ -181,6 +183,76 @@ to be used to view and change remote related variables."
(format "^%s$" remote)))
(magit-call-git "config" (and (not new-name) "--unset") var new-name))))
(defconst magit--refspec-re "\\`\\(\\+\\)?\\([^:]+\\):\\(.*\\)\\'")
;;;###autoload
(defun magit-remote-prune-refspecs (remote)
"Remove stale refspecs and tracking branches for REMOTE.
If there are only stale refspecs, then offer to either delete the
remote or replace the refspecs with the default refspec instead."
(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)
refs))
(magit-confirm 'prune-stale-refspecs nil
(format "Prune %%i stale refspecs and %i branches"
(length (mapcan (lambda (s) (copy-sequence (cdr s))) stale)))
(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.
......
......@@ -903,5 +903,25 @@ FORMAT-STRING to be displayed, then don't."
(unless (--first (string-prefix-p it format-string) magit-no-message)
(apply #'message format-string args)))
(defun magit--log-action (summary line list)
(let (heading lines)
(if (cdr list)
(progn (setq heading (funcall summary list))
(setq lines (mapcar line list)))
(setq heading (funcall line (car list))))
(with-current-buffer (magit-process-buffer t)
(goto-char (1- (point-max)))
(let ((inhibit-read-only t))
(magit-insert-section (message)
(magit-insert-heading (concat " * " heading))
(when lines
(dolist (line lines)
(insert line "\n"))
(insert "\n"))))
(let ((inhibit-message t))
(when heading
(setq lines (cons heading lines)))
(message (mapconcat #'identity lines "\n"))))))
(provide 'magit-utils)
;;; magit-utils.el ends here
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