Merge branch 'master' into empty-commit

This commit is contained in:
Nathan Weizenbaum 2010-08-01 15:48:55 -07:00
commit 6f2100c72c
7 changed files with 674 additions and 319 deletions

View file

@ -1,17 +1,18 @@
lispdir = $(datadir)/emacs/site-lisp lispdir = $(datadir)/emacs/site-lisp
sitestartdir = @SITESTART@ sitestartdir = @SITESTART@
lisp_DATA = magit.el magit.elc lisp_DATA = magit.el magit.elc magit-svn.el magit-svn.elc magit-topgit.el magit-topgit.elc
sitestart_DATA = 50magit.el sitestart_DATA = 50magit.el
info_TEXINFOS = magit.texi info_TEXINFOS = magit.texi
CLEANFILES = magit.elc CLEANFILES = magit-*.elc
EXTRA_DIST = magit.el 50magit.el magit.spec EXTRA_DIST = magit.el 50magit.el magit.spec magit-svn.el magit-topgit.el
%.elc: %.el %.elc: %.el
@if [ $(builddir) != $(srcdir) ]; then ln $(srcdir)/$*.el .; fi @if [ $(builddir) != $(srcdir) ]; then ln $(srcdir)/$*.el .; fi
emacs --batch --eval '(byte-compile-file "$*.el")' emacs --batch --eval "(add-to-list 'load-path \"$(srcdir)\")" \
--eval '(byte-compile-file "$*.el")'
@if [ $(builddir) != $(srcdir) ]; then rm -f $*.el; fi @if [ $(builddir) != $(srcdir) ]; then rm -f $*.el; fi

View file

@ -2,6 +2,14 @@
set -e set -e
function configure_ac_ver_ok {
cat configure.ac | grep "${1}" || return 1
}
function magit_el_ver_ok {
grep -e ";; Version: *$1" magit.el || return 1
}
USAGE="usage: ${0##*/} <tag>" USAGE="usage: ${0##*/} <tag>"
tag="${1}" tag="${1}"
@ -20,6 +28,20 @@ fi
# grab that tag # grab that tag
git co "${tag}" git co "${tag}"
# correct version in magit?
if ! magit_el_ver_ok "$tag"; then
echo "Please set version in magit.el to $tag"
git co master
exit 1
fi
# correct version in configure.ac?
if ! configure_ac_ver_ok "$tag"; then
echo "Please set AC_INIT to $tag in configure.ac"
git co master
exit 1
fi
# clean up if we need to # clean up if we need to
[ -f Makefile ] && make distclean [ -f Makefile ] && make distclean

View file

@ -1,4 +1,4 @@
AC_INIT(magit, 0.8.1) AC_INIT(magit, 0.8.2)
AC_CONFIG_SRCDIR([magit.el]) AC_CONFIG_SRCDIR([magit.el])
AM_INIT_AUTOMAKE([1.10]) AM_INIT_AUTOMAKE([1.10])

185
magit-svn.el Normal file
View file

@ -0,0 +1,185 @@
;;; magit-svn.el --- git-svn plug-in for Magit
;; Copyright (C) 2008, 2009 Marius Vollmer
;; Copyright (C) 2008 Linh Dang
;; Copyright (C) 2008 Alex Ott
;; Copyright (C) 2008 Marcin Bachry
;; Copyright (C) 2009 Alexey Voinov
;; Copyright (C) 2009 John Wiegley
;; Copyright (C) 2010 Yann Hodique
;;
;; 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 plug-in provides git-svn functionality as a separate component of Magit
;;; Code:
(require 'magit)
;; git svn commands
(defun magit-svn-find-rev (rev &optional branch)
(interactive
(list (read-string "SVN revision: ")
(if current-prefix-arg
(read-string "In branch: "))))
(let* ((sha (apply 'magit-git-string
`("svn"
"find-rev"
,(concat "r" rev)
,@(when branch (list branch))))))
(if sha
(magit-show-commit
(magit-with-section sha 'commit
(magit-set-section-info sha)
sha))
(error "Revision %s could not be mapped to a commit" rev))))
(defun magit-svn-rebase ()
(interactive)
(magit-run-git-async "svn" "rebase"))
(defun magit-svn-dcommit ()
(interactive)
(magit-run-git-async "svn" "dcommit"))
(defun magit-svn-enabled ()
(not (null (magit-svn-get-ref-info))))
(defun magit-svn-get-local-ref (url)
(let ((branches (cons (magit-get "svn-remote" "svn" "fetch")
(magit-get-all "svn-remote" "svn" "branches")))
(base-url (magit-get "svn-remote" "svn" "url"))
(result nil))
(while branches
(let* ((pats (split-string (pop branches) ":"))
(src (replace-regexp-in-string "\\*" "\\\\(.*\\\\)" (car pats)))
(dst (replace-regexp-in-string "\\*" "\\\\1" (cadr pats)))
(base-url (replace-regexp-in-string "\\+" "\\\\+" base-url))
(pat1 (concat "^" src "$"))
(pat2 (cond ((equal src "") (concat "^" base-url "$"))
(t (concat "^" base-url "/" src "$")))))
(cond ((string-match pat1 url)
(setq result (replace-match dst nil nil url))
(setq branches nil))
((string-match pat2 url)
(setq result (replace-match dst nil nil url))
(setq branches nil)))))
result))
(defvar magit-svn-get-ref-info-cache nil
"A cache for svn-ref-info.
As `magit-get-svn-ref-info' might be considered a quite
expensive operation a cache is taken so that `magit-status'
doesn't repeatedly call it.")
(defun magit-svn-get-ref-info (&optional use-cache)
"Gather details about the current git-svn repository.
Return nil if there isn't one. Keys of the alist are ref-path,
trunk-ref-name and local-ref-name.
If USE-CACHE is non-nil then return the value of `magit-get-svn-ref-info-cache'."
(if use-cache
magit-svn-get-ref-info-cache
(let* ((fetch (magit-get "svn-remote" "svn" "fetch"))
(url)
(revision))
(when fetch
(let* ((ref (cadr (split-string fetch ":")))
(ref-path (file-name-directory ref))
(trunk-ref-name (file-name-nondirectory ref)))
(setq magit-svn-get-ref-info-cache
(list
(cons 'ref-path ref-path)
(cons 'trunk-ref-name trunk-ref-name)
;; get the local ref from the log. This is actually
;; the way that git-svn does it.
(cons 'local-ref
(with-temp-buffer
(insert (or (magit-git-string "log" "--first-parent")
""))
(goto-char (point-min))
(cond ((re-search-forward "git-svn-id: \\(.+/.+?\\)@\\([0-9]+\\)" nil t)
(setq url (match-string 1)
revision (match-string 2))
(magit-svn-get-local-ref url))
(t
(setq url (magit-get "svn-remote" "svn" "url"))
nil))))
(cons 'revision revision)
(cons 'url url))))))))
(defun magit-svn-get-ref (&optional use-cache)
"Get the best guess remote ref for the current git-svn based branch.
If USE-CACHE is non nil, use the cached information."
(let ((info (magit-svn-get-ref-info use-cache)))
(cdr (assoc 'local-ref info))))
(magit-define-inserter svn-unpulled (&optional use-cache)
(when (magit-svn-get-ref-info)
(magit-git-section 'svn-unpulled
"Unpulled commits (SVN):" 'magit-wash-log
"log" "--pretty=format:* %H %s"
(format "HEAD..%s" (magit-svn-get-ref use-cache)))))
(magit-define-inserter svn-unpushed (&optional use-cache)
(when (magit-svn-get-ref-info)
(magit-git-section 'svn-unpushed
"Unpushed commits (SVN):" 'magit-wash-log
"log" "--pretty=format:* %H %s"
(format "%s..HEAD" (magit-svn-get-ref use-cache)))))
(magit-define-section-jumper svn-unpushed "Unpushed commits (SVN)")
(defun magit-svn-remote-string ()
(let ((svn-info (magit-svn-get-ref-info)))
(when svn-info
(concat (cdr (assoc 'url svn-info))
" @ "
(cdr (assoc 'revision svn-info))))))
(defun magit-svn-remote-update ()
(interactive)
(when (magit-svn-enabled)
(magit-run-git-async "svn" "fetch")))
(defvar magit-svn-extension-keys
`((,(kbd "N r") . magit-svn-rebase)
(,(kbd "N c") . magit-svn-dcommit)
(,(kbd "N f") . magit-svn-remote-update)
(,(kbd "N s") . magit-svn-find-rev)))
(easy-menu-define magit-svn-extension-menu
nil
"Git SVN extension menu"
'("Git SVN"
["Rebase" magit-svn-rebase (magit-svn-enabled)]
["Fetch" magit-svn-remote-update (magit-svn-enabled)]
["Commit" magit-svn-dcommit (magit-svn-enabled)]))
(defvar magit-svn-extension-inserters
'((:after unpulled-commits (lambda () (magit-insert-svn-unpulled t)))
(:after unpushed-commits (lambda () (magit-insert-svn-unpushed t)))))
(defvar magit-svn-extension
(make-magit-extension :keys magit-svn-extension-keys
:menu magit-svn-extension-menu
:insert magit-svn-extension-inserters
:remote-string 'magit-svn-remote-string))
(magit-install-extension magit-svn-extension)
(provide 'magit-svn)
;;; magit-svn.el ends here

99
magit-topgit.el Normal file
View file

@ -0,0 +1,99 @@
;;; magit-topgit.el --- topgit plug-in for Magit
;; Copyright (C) 2008, 2009 Marius Vollmer
;; Copyright (C) 2008 Linh Dang
;; Copyright (C) 2008 Alex Ott
;; Copyright (C) 2008 Marcin Bachry
;; Copyright (C) 2009 Alexey Voinov
;; Copyright (C) 2009 John Wiegley
;; Copyright (C) 2010 Yann Hodique
;;
;; 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 plug-in provides topgit functionality as a separate component of Magit
;;; Code:
(require 'magit)
(defcustom magit-topgit-executable "tg"
"The name of the TopGit executable."
:group 'magit
:type 'string)
;;; Topic branches (using topgit)
(defun magit-topgit-create-branch (branch parent)
(when (zerop (or (string-match "t/" branch) -1))
(magit-run* (list magit-topgit-executable "create"
branch (magit-rev-to-git parent))
nil nil nil t)
t))
(defun magit-topgit-pull ()
(when (file-exists-p ".topdeps")
(magit-run* (list magit-topgit-executable "update")
nil nil nil t)
t))
(defun magit-topgit-wash-topic ()
(if (search-forward-regexp "^..\\(t/\\S-+\\)\\s-+\\(\\S-+\\)\\s-+\\(\\S-+\\)"
(line-end-position) t)
(let ((topic (match-string 1)))
(delete-region (match-beginning 2) (match-end 2))
(goto-char (line-beginning-position))
(delete-char 4)
(insert "\t")
(goto-char (line-beginning-position))
(magit-with-section topic 'topic
(magit-set-section-info topic)
(forward-line)))
(delete-region (line-beginning-position) (1+ (line-end-position))))
t)
(defun magit-topgit-wash-topics ()
(let ((magit-old-top-section nil))
(magit-wash-sequence #'magit-topgit-wash-topic)))
(magit-define-inserter topics ()
(magit-git-section 'topics
"Topics:" 'magit-topgit-wash-topics
"branch" "-v"))
(defvar magit-topgit-extension-inserters
'((:after stashes magit-insert-topics)))
(defvar magit-topgit-extension-actions
'(("discard" ((topic)
(when (yes-or-no-p "Discard topic? ")
(magit-run* (list magit-topgit-executable "delete" "-f" info)
nil nil nil t))))
("visit" ((topic)
(magit-checkout info)))))
(defvar magit-topgit-extension-commands
'((create-branch . magit-topgit-create-branch)
(pull . magit-topgit-pull)))
(defvar magit-topgit-extension
(make-magit-extension :actions magit-topgit-extension-actions
:insert magit-topgit-extension-inserters
:commands magit-topgit-extension-commands))
(magit-install-extension magit-topgit-extension)
(provide 'magit-topgit)
;;; magit-topgit.el ends here

489
magit.el
View file

@ -25,10 +25,11 @@
;; Copyright (C) 2009 Steve Purcell. ;; Copyright (C) 2009 Steve Purcell.
;; Copyright (C) 2010 Ævar Arnfjörð Bjarmason. ;; Copyright (C) 2010 Ævar Arnfjörð Bjarmason.
;; Copyright (C) 2010 Óscar Fuentes. ;; Copyright (C) 2010 Óscar Fuentes.
;; Copyright (C) 2010 Yann Hodique
;; Author: Marius Vollmer <marius.vollmer@nokia.com> ;; Author: Marius Vollmer <marius.vollmer@nokia.com>
;; Maintainer: Phil Jackson <phil@shellarchive.co.uk> ;; Maintainer: Phil Jackson <phil@shellarchive.co.uk>
;; Version: 0.8.1 ;; Version: 0.8.2
;; Keywords: tools ;; Keywords: tools
;; ;;
@ -150,6 +151,22 @@ after a confirmation."
:group 'magit :group 'magit
:type 'boolean) :type 'boolean)
(defcustom magit-remote-ref-format 'branch-then-remote
"What format to use for autocompleting refs, in pariticular for remotes.
Autocompletion is used by functions like `magit-checkout',
`magit-interactive-rebase' and others which offer branch name
completion.
The value 'name-then-remote means remotes will be of the
form \"name (remote)\", while the value 'remote-slash-name
means that they'll be of the form \"remote/name\". I.e. something that's
listed as \"remotes/upstream/next\" by \"git branch -l -a\"
will be \"upstream/next\"."
:group 'magit
:type '(choice (const :tag "name (remote)" branch-then-remote)
(const :tag "remote/name" remote-slash-branch)))
(defcustom magit-process-connection-type (not (eq system-type 'cygwin)) (defcustom magit-process-connection-type (not (eq system-type 'cygwin))
"Connection type used for the git process. "Connection type used for the git process.
@ -342,6 +359,10 @@ Many Magit faces inherit from this one by default."
(make-variable-buffer-local 'magit-submode) (make-variable-buffer-local 'magit-submode)
(put 'magit-submode 'permanent-local t) (put 'magit-submode 'permanent-local t)
(eval-when-compile
(defun magit-dynamic-clauses-helper (clauses context)
`(((magit-dynamic-clauses ,clauses ,context) t))))
(defun magit-use-region-p () (defun magit-use-region-p ()
(if (fboundp 'use-region-p) (if (fboundp 'use-region-p)
(use-region-p) (use-region-p)
@ -511,12 +532,42 @@ return nil."
(or (magit-get-top-dir default-directory) (or (magit-get-top-dir default-directory)
default-directory))))) default-directory)))))
(defun magit-rev-parse (ref)
"Return the SHA hash for REF."
(magit-git-string "rev-parse" ref))
(defun magit-ref-ambiguous-p (ref)
"Return whether or not REF is ambiguous."
;; If REF is ambiguous, rev-parse just prints errors,
;; so magit-git-string returns nil.
(not (magit-git-string "rev-parse" "--abbrev-ref" ref)))
(defun magit-name-rev (rev) (defun magit-name-rev (rev)
(and rev "Return a human-readable name for REV.
(let ((name (magit-git-string "name-rev" "--name-only" rev))) Unlike git name-rev, this will remove tags/ and remotes/ prefixes
(if (or (not name) (string= name "undefined")) if that can be done unambiguously. In addition, it will filter
rev out revs involving HEAD."
name)))) (when rev
(let ((name (magit-git-string "name-rev" "--no-undefined" "--name-only" rev)))
;; There doesn't seem to be a way of filtering HEAD out from name-rev,
;; so we have to do it manually.
;; HEAD-based names are too transient to allow.
(when (string-match "^\\(.*\\<HEAD\\)\\([~^].*\\|$\\)" name)
(let ((head-ref (match-string 1 name))
(modifier (match-string 2 name)))
;; Sometimes when name-rev gives a HEAD-based name,
;; rev-parse will give an actual branch or remote name.
(setq name (concat (magit-git-string "rev-parse" "--abbrev-ref" head-ref)
modifier))
;; If rev-parse doesn't give us what we want, just use the SHA.
(when (or (null name) (string-match-p "\\<HEAD\\>" name))
(setq name (magit-rev-parse rev)))))
(setq rev (or name rev))
(when (string-match "^\\(?:tags\\|remotes\\)/\\(.*\\)" rev)
(let ((plain-name (match-string 1 rev)))
(unless (magit-ref-ambiguous-p plain-name)
(setq rev plain-name))))
rev)))
(defun magit-put-line-property (prop val) (defun magit-put-line-property (prop val)
(put-text-property (line-beginning-position) (line-beginning-position 2) (put-text-property (line-beginning-position) (line-beginning-position 2)
@ -574,12 +625,20 @@ return nil."
(let ((branch (match-string 1 ref))) (let ((branch (match-string 1 ref)))
(push (cons branch branch) refs))) (push (cons branch branch) refs)))
((string-match "refs/tags/\\(.*\\)" ref) ((string-match "refs/tags/\\(.*\\)" ref)
(push (cons (format "%s (tag)" (match-string 1 ref)) ref) (push (cons (format
(if (eq magit-remote-ref-format 'branch-then-remote)
"%s (tag)" "%s")
(match-string 1 ref))
ref)
refs)) refs))
((string-match "refs/remotes/\\([^/]+\\)/\\(.+\\)" ref) ((string-match "refs/remotes/\\([^/]+\\)/\\(.+\\)" ref)
(push (cons (format "%s (%s)" (push (cons (if (eq magit-remote-ref-format 'branch-then-remote)
(format "%s (%s)"
(match-string 2 ref) (match-string 2 ref)
(match-string 1 ref)) (match-string 1 ref))
(format "%s/%s"
(match-string 1 ref)
(match-string 2 ref)))
ref) ref)
refs)))))) refs))))))
refs)) refs))
@ -1157,6 +1216,18 @@ TITLE is the displayed title of the section."
(interactive) (interactive)
(magit-goto-section '(,sym))))) (magit-goto-section '(,sym)))))
(defmacro magit-define-inserter (sym arglist &rest body)
(declare (indent defun))
(let ((fun (intern (format "magit-insert-%s" sym)))
(before (intern (format "magit-insert-%s:before-hook" sym)))
(after (intern (format "magit-insert-%s:after-hook" sym)))
(doc (format "Insert items for `%s'." sym)))
`(defun ,fun ,arglist
,doc
(run-hooks ',before)
,@body
(run-hooks ',after))))
(defvar magit-highlight-overlay nil) (defvar magit-highlight-overlay nil)
(defvar magit-highlighted-section nil) (defvar magit-highlighted-section nil)
@ -1199,6 +1270,23 @@ TITLE is the displayed title of the section."
(equal (car prefix) (car list)) (equal (car prefix) (car list))
(magit-prefix-p (cdr prefix) (cdr list)))))) (magit-prefix-p (cdr prefix) (cdr list))))))
(defun magit-inline-clause (clause context)
(if (eq (car clause) t)
clause
(let ((prefix (reverse (car clause)))
(body (cdr clause)))
`((magit-prefix-p ',prefix ,context)
,@body))))
(defun magit-dynamic-clauses (clauses context)
(let* ((c (car clauses))
(prefix (reverse (car c)))
(body (cadr c)))
(cond ((magit-prefix-p prefix context)
(eval body))
(t
(magit-dynamic-clauses (cdr clauses) context)))))
(defmacro magit-section-case (head &rest clauses) (defmacro magit-section-case (head &rest clauses)
"Make different action depending of current section. "Make different action depending of current section.
@ -1214,11 +1302,13 @@ where SECTION-TYPE describe section where BODY will be run."
(info (cadr head)) (info (cadr head))
(type (make-symbol "*type*")) (type (make-symbol "*type*"))
(context (make-symbol "*context*")) (context (make-symbol "*context*"))
(extra (make-symbol "*extra*"))
(opname (caddr head))) (opname (caddr head)))
`(let* ((,section (magit-current-section)) `(let* ((,section (magit-current-section))
(,info (magit-section-info ,section)) (,info (magit-section-info ,section))
(,type (magit-section-type ,section)) (,type (magit-section-type ,section))
(,context (magit-section-context-type ,section))) (,context (magit-section-context-type ,section))
(,extra (magit-get-extensions-actions ,opname)))
(cond ,@(mapcar (lambda (clause) (cond ,@(mapcar (lambda (clause)
(if (eq (car clause) t) (if (eq (car clause) t)
clause clause
@ -1227,6 +1317,7 @@ where SECTION-TYPE describe section where BODY will be run."
`((magit-prefix-p ',prefix ,context) `((magit-prefix-p ',prefix ,context)
,@body)))) ,@body))))
clauses) clauses)
,@(magit-dynamic-clauses-helper extra context)
,@(if opname ,@(if opname
`(((not ,type) `(((not ,type)
(error "Nothing to %s here" ,opname)) (error "Nothing to %s here" ,opname))
@ -1248,6 +1339,27 @@ FUNC should leave point at the end of the modified region"
(while (and (not (eobp)) (while (and (not (eobp))
(funcall func)))) (funcall func))))
(defmacro magit-define-command (sym arglist &rest body)
(declare (indent defun))
(let ((fun (intern (format "magit-%s" sym)))
(hook (intern (format "magit-%s:functions" sym)))
(doc (format "Command for `%s'." sym))
(inter nil)
(instr body))
(when (stringp (car body))
(setq doc (car body)
instr (cdr body)))
(let ((form (car instr)))
(when (eq (car form) 'interactive)
(setq inter form
instr (cdr instr))))
`(defun ,fun ,arglist
,doc
,inter
(or (run-hook-with-args-until-success
',hook ,@(remq '&optional (remq '&rest arglist)))
,@instr))))
;;; Running commands ;;; Running commands
(defun magit-set-mode-line-process (str) (defun magit-set-mode-line-process (str)
@ -1438,7 +1550,6 @@ FUNC should leave point at the end of the modified region"
(magit-define-section-jumper unstaged "Unstaged changes") (magit-define-section-jumper unstaged "Unstaged changes")
(magit-define-section-jumper staged "Staged changes") (magit-define-section-jumper staged "Staged changes")
(magit-define-section-jumper unpushed "Unpushed commits") (magit-define-section-jumper unpushed "Unpushed commits")
(magit-define-section-jumper svn-unpushed "Unpushed commits (SVN)")
(magit-define-level-shower 1) (magit-define-level-shower 1)
(magit-define-level-shower 2) (magit-define-level-shower 2)
@ -1474,9 +1585,6 @@ FUNC should leave point at the end of the modified region"
(define-key map (kbd "SPC") 'magit-show-item-or-scroll-up) (define-key map (kbd "SPC") 'magit-show-item-or-scroll-up)
(define-key map (kbd "DEL") 'magit-show-item-or-scroll-down) (define-key map (kbd "DEL") 'magit-show-item-or-scroll-down)
(define-key map (kbd "C-w") 'magit-copy-item-as-kill) (define-key map (kbd "C-w") 'magit-copy-item-as-kill)
(define-key map (kbd "N r") 'magit-svn-rebase)
(define-key map (kbd "N c") 'magit-svn-dcommit)
(define-key map (kbd "N f") 'magit-svn-find-rev)
(define-key map (kbd "R") 'magit-rebase-step) (define-key map (kbd "R") 'magit-rebase-step)
(define-key map (kbd "r s") 'magit-rewrite-start) (define-key map (kbd "r s") 'magit-rewrite-start)
(define-key map (kbd "r t") 'magit-rewrite-stop) (define-key map (kbd "r t") 'magit-rewrite-stop)
@ -1650,10 +1758,6 @@ FUNC should leave point at the end of the modified region"
["Merge (no commit)" magit-manual-merge t] ["Merge (no commit)" magit-manual-merge t]
["Interactive resolve" magit-interactive-resolve-item t] ["Interactive resolve" magit-interactive-resolve-item t]
["Rebase" magit-rebase-step t] ["Rebase" magit-rebase-step t]
("Git SVN"
["Rebase" magit-svn-rebase (magit-svn-enabled)]
["Commit" magit-svn-dcommit (magit-svn-enabled)]
)
("Rewrite" ("Rewrite"
["Start" magit-rewrite-start t] ["Start" magit-rewrite-start t]
["Stop" magit-rewrite-stop t] ["Stop" magit-rewrite-stop t]
@ -1666,6 +1770,8 @@ FUNC should leave point at the end of the modified region"
["Pull" magit-pull t] ["Pull" magit-pull t]
["Remote update" magit-remote-update t] ["Remote update" magit-remote-update t]
"---" "---"
("Extensions")
"---"
["Display Git output" magit-display-process t] ["Display Git output" magit-display-process t]
["Quit Magit" quit-window t])) ["Quit Magit" quit-window t]))
@ -1805,6 +1911,16 @@ Please see the manual for a complete description of Magit.
(ignore-errors (ignore-errors
(revert-buffer t t nil)))))) (revert-buffer t t nil))))))
(defun magit-update-vc-modeline (dir)
"Update the modeline for buffers representable by magit."
(dolist (buffer (buffer-list))
(when (and buffer
(buffer-file-name buffer)
(magit-string-has-prefix-p (buffer-file-name buffer) dir))
(with-current-buffer buffer
(ignore-errors
(vc-find-file-hook))))))
(defvar magit-refresh-needing-buffers nil) (defvar magit-refresh-needing-buffers nil)
(defvar magit-refresh-pending nil) (defvar magit-refresh-pending nil)
@ -2194,13 +2310,14 @@ in the corresponding directories."
(defun magit-apply-hunk-item-reverse (hunk &rest args) (defun magit-apply-hunk-item-reverse (hunk &rest args)
(apply #'magit-apply-hunk-item* hunk t (cons "--reverse" args))) (apply #'magit-apply-hunk-item* hunk t (cons "--reverse" args)))
(defun magit-insert-unstaged-changes (title) (magit-define-inserter unstaged-changes (title)
(let ((magit-hide-diffs t)) (let ((magit-hide-diffs t))
(let ((magit-diff-options '())) (let ((magit-diff-options '()))
(magit-git-section 'unstaged title 'magit-wash-raw-diffs (magit-git-section 'unstaged title 'magit-wash-raw-diffs
"diff-files")))) "diff-files"))))
(defun magit-insert-staged-changes (no-commit) (magit-define-inserter staged-changes (staged no-commit)
(when staged
(let ((magit-hide-diffs t) (let ((magit-hide-diffs t)
(base (if no-commit (base (if no-commit
(magit-git-string "mktree") (magit-git-string "mktree")
@ -2209,7 +2326,7 @@ in the corresponding directories."
(magit-ignore-unmerged-raw-diffs t)) (magit-ignore-unmerged-raw-diffs t))
(magit-git-section 'staged "Staged changes:" 'magit-wash-raw-diffs (magit-git-section 'staged "Staged changes:" 'magit-wash-raw-diffs
"diff-index" "--cached" "diff-index" "--cached"
base)))) base)))))
;;; Logs and Commits ;;; Logs and Commits
@ -2401,29 +2518,27 @@ insert a line to tell how to insert more of them"
(or magit-marked-commit (or magit-marked-commit
(error "No commit marked"))) (error "No commit marked")))
(defun magit-insert-unpulled-commits (remote branch) (defun magit-remote-branch-name (remote branch)
"Get the name of the branch BRANCH on remote REMOTE"
(if (string= remote ".")
branch
(concat remote "/" branch)))
(magit-define-inserter unpulled-commits (remote branch)
(when remote
(magit-git-section 'unpulled (magit-git-section 'unpulled
"Unpulled commits:" 'magit-wash-log "Unpulled commits:" 'magit-wash-log
"log" "--pretty=format:* %H %s" "log" "--pretty=format:* %H %s"
(format "HEAD..%s/%s" remote branch))) (format "HEAD..%s"
(magit-remote-branch-name remote branch)))))
(defun magit-insert-unpushed-commits (remote branch) (magit-define-inserter unpushed-commits (remote branch)
(when remote
(magit-git-section 'unpushed (magit-git-section 'unpushed
"Unpushed commits:" 'magit-wash-log "Unpushed commits:" 'magit-wash-log
"log" "--pretty=format:* %H %s" "log" "--pretty=format:* %H %s"
(format "%s/%s..HEAD" remote branch))) (format "%s..HEAD"
(magit-remote-branch-name remote branch)))))
(defun magit-insert-unpulled-svn-commits (&optional use-cache)
(magit-git-section 'svn-unpulled
"Unpulled commits (SVN):" 'magit-wash-log
"log" "--pretty=format:* %H %s"
(format "HEAD..%s" (magit-get-svn-ref use-cache))))
(defun magit-insert-unpushed-svn-commits (&optional use-cache)
(magit-git-section 'svn-unpushed
"Unpushed commits (SVN):" 'magit-wash-log
"log" "--pretty=format:* %H %s"
(format "%s..HEAD" (magit-get-svn-ref use-cache))))
(defun magit-remote-branch-for (local-branch) (defun magit-remote-branch-for (local-branch)
"Guess the remote branch name that LOCAL-BRANCH is tracking." "Guess the remote branch name that LOCAL-BRANCH is tracking."
@ -2434,13 +2549,23 @@ insert a line to tell how to insert more of them"
;;; Status ;;; Status
(defun magit-remote-string (remote svn-info) (defvar magit-remote-string-hook nil)
(if remote
(concat remote " " (magit-get "remote" remote "url")) (defun magit-remote-string (remote remote-branch)
(when svn-info (cond
(concat (cdr (assoc 'url svn-info)) ((string= "." remote)
(format "branch %s"
(propertize remote-branch 'face 'magit-branch)))
(remote
(concat
(propertize remote-branch 'face 'magit-branch)
" @ " " @ "
(cdr (assoc 'revision svn-info)))))) remote
" ("
(magit-get "remote" remote "url")
")"))
(t
(run-hook-with-args-until-success 'magit-remote-string-hook))))
(defun magit-refresh-status () (defun magit-refresh-status ()
(magit-create-buffer-sections (magit-create-buffer-sections
@ -2448,8 +2573,7 @@ insert a line to tell how to insert more of them"
(let* ((branch (magit-get-current-branch)) (let* ((branch (magit-get-current-branch))
(remote (and branch (magit-get "branch" branch "remote"))) (remote (and branch (magit-get "branch" branch "remote")))
(remote-branch (or (and branch (magit-remote-branch-for branch)) branch)) (remote-branch (or (and branch (magit-remote-branch-for branch)) branch))
(svn-info (magit-get-svn-ref-info)) (remote-string (magit-remote-string remote remote-branch))
(remote-string (magit-remote-string remote svn-info))
(head (magit-git-string (head (magit-git-string
"log" "--max-count=1" "--abbrev-commit" "--pretty=oneline")) "log" "--max-count=1" "--abbrev-commit" "--pretty=oneline"))
(no-commit (not head))) (no-commit (not head)))
@ -2474,22 +2598,15 @@ insert a line to tell how to insert more of them"
(magit-git-exit-code "update-index" "--refresh") (magit-git-exit-code "update-index" "--refresh")
(magit-insert-untracked-files) (magit-insert-untracked-files)
(magit-insert-stashes) (magit-insert-stashes)
(magit-insert-topics)
(magit-insert-pending-changes) (magit-insert-pending-changes)
(magit-insert-pending-commits) (magit-insert-pending-commits)
(when remote (magit-insert-unpulled-commits remote remote-branch)
(magit-insert-unpulled-commits remote remote-branch))
(when svn-info
(magit-insert-unpulled-svn-commits t))
(let ((staged (or no-commit (magit-anything-staged-p)))) (let ((staged (or no-commit (magit-anything-staged-p))))
(magit-insert-unstaged-changes (magit-insert-unstaged-changes
(if staged "Unstaged changes:" "Changes:")) (if staged "Unstaged changes:" "Changes:"))
(if staged (magit-insert-staged-changes staged no-commit))
(magit-insert-staged-changes no-commit))) (magit-insert-unpushed-commits remote remote-branch)
(when remote (run-hooks 'magit-refresh-status-hook)))))
(magit-insert-unpushed-commits remote remote-branch))
(when svn-info
(magit-insert-unpushed-svn-commits t))))))
(defun magit-init (dir) (defun magit-init (dir)
"Initialize git repository in the DIR directory." "Initialize git repository in the DIR directory."
@ -2603,7 +2720,9 @@ With prefix argument, add remaining untracked files as well.
tracking brach name suggesting a sensible default." tracking brach name suggesting a sensible default."
(when (yes-or-no-p (when (yes-or-no-p
(format "Create local tracking branch for %s? " branch)) (format "Create local tracking branch for %s? " branch))
(let* ((default-name (concat remote "-" branch)) (let* ((default-name (concat remote
"-"
(replace-regexp-in-string "[/]" "-" branch)))
(chosen-name (read-string (format "Call local branch (%s): " default-name) (chosen-name (read-string (format "Call local branch (%s): " default-name)
nil nil
nil nil
@ -2624,7 +2743,7 @@ rev... maybe."
t)) t))
nil)) nil))
(defun magit-checkout (revision) (magit-define-command checkout (revision)
"Switch 'HEAD' to REVISION and update working tree. "Switch 'HEAD' to REVISION and update working tree.
Fails if working tree or staging area contain uncommitted changes. Fails if working tree or staging area contain uncommitted changes.
If REVISION is a remote branch, offer to create a local tracking branch. If REVISION is a remote branch, offer to create a local tracking branch.
@ -2640,7 +2759,7 @@ If REVISION is a remote branch, offer to create a local tracking branch.
(parent (magit-read-rev "Parent" cur-branch))) (parent (magit-read-rev "Parent" cur-branch)))
(list branch parent))) (list branch parent)))
(defun magit-create-branch (branch parent) (magit-define-command create-branch (branch parent)
"Switch 'HEAD' to new BRANCH at revision PARENT and update working tree. "Switch 'HEAD' to new BRANCH at revision PARENT and update working tree.
Fails if working tree or staging area contain uncommitted changes. Fails if working tree or staging area contain uncommitted changes.
\('git checkout -b BRANCH REVISION')." \('git checkout -b BRANCH REVISION')."
@ -2675,7 +2794,7 @@ With a prefix-arg, the merge will be squashed.
"--no-ff") "--no-ff")
(magit-rev-to-git revision)))) (magit-rev-to-git revision))))
(defun magit-automatic-merge (revision) (magit-define-command automatic-merge (revision)
"Merge REVISION into the current 'HEAD'; commit unless merge fails. "Merge REVISION into the current 'HEAD'; commit unless merge fails.
\('git merge REVISION')." \('git merge REVISION')."
(interactive (list (magit-read-rev "Merge" (magit-guess-branch)))) (interactive (list (magit-read-rev "Merge" (magit-guess-branch))))
@ -2720,107 +2839,9 @@ With a prefix-arg, the merge will be squashed.
((?C ?c) ((?C ?c)
(magit-run-git "rebase" "--continue")))))))) (magit-run-git "rebase" "--continue"))))))))
;; git svn commands
(defun magit-svn-find-rev (rev &optional branch)
(interactive
(list (read-string "SVN revision: ")
(if current-prefix-arg
(read-string "In branch: "))))
(let* ((sha (apply 'magit-git-string
`("svn"
"find-rev"
,(concat "r" rev)
,@(when branch (list branch))))))
(if sha
(magit-show-commit
(magit-with-section sha 'commit
(magit-set-section-info sha)
sha))
(error "Revision %s could not be mapped to a commit" rev))))
(defun magit-svn-rebase ()
(interactive)
(magit-run-git-async "svn" "rebase"))
(defun magit-svn-dcommit ()
(interactive)
(magit-run-git-async "svn" "dcommit"))
(defun magit-svn-enabled ()
(not (null (magit-get-svn-ref-info))))
(defun magit-get-svn-local-ref (url)
(let ((branches (cons (magit-get "svn-remote" "svn" "fetch")
(magit-get-all "svn-remote" "svn" "branches")))
(base-url (magit-get "svn-remote" "svn" "url"))
(result nil))
(while branches
(let* ((pats (split-string (pop branches) ":"))
(src (replace-regexp-in-string "\\*" "\\\\(.*\\\\)" (car pats)))
(dst (replace-regexp-in-string "\\*" "\\\\1" (cadr pats)))
(base-url (replace-regexp-in-string "\\+" "\\\\+" base-url))
(pat1 (concat "^" src "$"))
(pat2 (cond ((equal src "") (concat "^" base-url "$"))
(t (concat "^" base-url "/" src "$")))))
(cond ((string-match pat1 url)
(setq result (replace-match dst nil nil url))
(setq branches nil))
((string-match pat2 url)
(setq result (replace-match dst nil nil url))
(setq branches nil)))))
result))
(defvar magit-get-svn-ref-info-cache nil
"A cache for svn-ref-info.
As `magit-get-svn-ref-info' might be considered a quite
expensive operation a cache is taken so that `magit-status'
doesn't repeatedly call it.")
(defun magit-get-svn-ref-info (&optional use-cache)
"Gather details about the current git-svn repository.
Return nil if there isn't one. Keys of the alist are ref-path,
trunk-ref-name and local-ref-name.
If USE-CACHE is non-nil then return the value of `magit-get-svn-ref-info-cache'."
(if use-cache
magit-get-svn-ref-info-cache
(let* ((fetch (magit-get "svn-remote" "svn" "fetch"))
(url)
(revision))
(when fetch
(let* ((ref (cadr (split-string fetch ":")))
(ref-path (file-name-directory ref))
(trunk-ref-name (file-name-nondirectory ref)))
(setq magit-get-svn-ref-info-cache
(list
(cons 'ref-path ref-path)
(cons 'trunk-ref-name trunk-ref-name)
;; get the local ref from the log. This is actually
;; the way that git-svn does it.
(cons 'local-ref
(with-temp-buffer
(insert (or (magit-git-string "log" "--first-parent")
""))
(goto-char (point-min))
(cond ((re-search-forward "git-svn-id: \\(.+/.+?\\)@\\([0-9]+\\)" nil t)
(setq url (match-string 1)
revision (match-string 2))
(magit-get-svn-local-ref url))
(t
(setq url (magit-get "svn-remote" "svn" "url"))
nil))))
(cons 'revision revision)
(cons 'url url))))))))
(defun magit-get-svn-ref (&optional use-cache)
"Get the best guess remote ref for the current git-svn based branch.
If USE-CACHE is non nil, use the cached information."
(let ((info (magit-get-svn-ref-info use-cache)))
(cdr (assoc 'local-ref info))))
;;; Resetting ;;; Resetting
(defun magit-reset-head (revision &optional hard) (magit-define-command reset-head (revision &optional hard)
"Switch 'HEAD' to REVISION, keeping prior working tree and staging area. "Switch 'HEAD' to REVISION, keeping prior working tree and staging area.
Any differences from REVISION become new changes to be committed. Any differences from REVISION become new changes to be committed.
With prefix argument, all uncommitted changes in working tree With prefix argument, all uncommitted changes in working tree
@ -2833,11 +2854,12 @@ and staging area are lost.
(or (magit-default-rev) (or (magit-default-rev)
"HEAD^")) "HEAD^"))
current-prefix-arg)) current-prefix-arg))
(if revision (when revision
(magit-run-git "reset" (if hard "--hard" "--soft") (magit-run-git "reset" (if hard "--hard" "--soft")
(magit-rev-to-git revision)))) (magit-rev-to-git revision))
(magit-update-vc-modeline default-directory)))
(defun magit-reset-head-hard (revision) (magit-define-command reset-head-hard (revision)
"Switch 'HEAD' to REVISION, losing all changes. "Switch 'HEAD' to REVISION, losing all changes.
Uncomitted changes in both working tree and staging area are lost. Uncomitted changes in both working tree and staging area are lost.
\('git reset --hard REVISION')." \('git reset --hard REVISION')."
@ -2846,7 +2868,7 @@ Uncomitted changes in both working tree and staging area are lost.
"HEAD")))) "HEAD"))))
(magit-reset-head revision t)) (magit-reset-head revision t))
(defun magit-reset-working-tree () (magit-define-command reset-working-tree ()
"Revert working tree and clear changes from staging area. "Revert working tree and clear changes from staging area.
\('git reset --hard HEAD')." \('git reset --hard HEAD')."
(interactive) (interactive)
@ -2867,7 +2889,7 @@ Uncomitted changes in both working tree and staging area are lost.
(prin1 info (current-buffer)) (prin1 info (current-buffer))
(princ "\n" (current-buffer)))) (princ "\n" (current-buffer))))
(defun magit-insert-pending-commits () (magit-define-inserter pending-commits ()
(let* ((info (magit-read-rewrite-info)) (let* ((info (magit-read-rewrite-info))
(pending (cdr (assq 'pending info)))) (pending (cdr (assq 'pending info))))
(when pending (when pending
@ -2910,7 +2932,7 @@ Uncomitted changes in both working tree and staging area are lost.
((pending commit) ((pending commit)
(magit-rewrite-set-commit-property info 'used nil)))) (magit-rewrite-set-commit-property info 'used nil))))
(defun magit-insert-pending-changes () (magit-define-inserter pending-changes ()
(let* ((info (magit-read-rewrite-info)) (let* ((info (magit-read-rewrite-info))
(orig (cadr (assq 'orig info)))) (orig (cadr (assq 'orig info))))
(when orig (when orig
@ -2926,7 +2948,7 @@ Uncomitted changes in both working tree and staging area are lost.
(error "You have uncommitted changes")) (error "You have uncommitted changes"))
(or (not (magit-read-rewrite-info)) (or (not (magit-read-rewrite-info))
(error "Rewrite in progress")) (error "Rewrite in progress"))
(let* ((orig (magit-git-string "rev-parse" "HEAD")) (let* ((orig (magit-rev-parse "HEAD"))
(base (or (car (magit-commit-parents from)) (base (or (car (magit-commit-parents from))
(error "Can't rewrite a commit without a parent, sorry"))) (error "Can't rewrite a commit without a parent, sorry")))
(pending (magit-git-lines "rev-list" (concat base "..")))) (pending (magit-git-lines "rev-list" (concat base ".."))))
@ -2942,7 +2964,7 @@ Uncomitted changes in both working tree and staging area are lost.
(when (or noconfirm (when (or noconfirm
(yes-or-no-p "Stop rewrite? ")) (yes-or-no-p "Stop rewrite? "))
(magit-write-rewrite-info nil) (magit-write-rewrite-info nil)
(magit-need-refresh)))) (magit-refresh))))
(defun magit-rewrite-abort () (defun magit-rewrite-abort ()
(interactive) (interactive)
@ -2980,7 +3002,7 @@ Uncomitted changes in both working tree and staging area are lost.
;;; Updating, pull, and push ;;; Updating, pull, and push
(defun magit-remote-update (&optional remote) (magit-define-command remote-update (&optional remote)
"Update REMOTE. If nil, update all remotes. "Update REMOTE. If nil, update all remotes.
When called interactively, update the current remote unless a When called interactively, update the current remote unless a
@ -2988,11 +3010,10 @@ prefix arg is given. With prefix arg, prompt for a remote and
update it." update it."
(interactive (list (when current-prefix-arg (magit-read-remote)))) (interactive (list (when current-prefix-arg (magit-read-remote))))
(cond (cond
((magit-svn-enabled) (magit-run-git-async "svn" "fetch"))
(remote (magit-run-git-async "fetch" remote)) (remote (magit-run-git-async "fetch" remote))
(t (magit-run-git-async "remote" "update")))) (t (magit-run-git-async "remote" "update"))))
(defun magit-pull () (magit-define-command pull ()
(interactive) (interactive)
(let* ((branch (magit-get-current-branch)) (let* ((branch (magit-get-current-branch))
(config-branch (and branch (magit-get "branch" branch "merge"))) (config-branch (and branch (magit-get "branch" branch "merge")))
@ -3031,7 +3052,7 @@ typing and automatically refreshes the status buffer."
args) args)
nil nil nil t)))) nil nil nil t))))
(defun magit-push () (magit-define-command push ()
(interactive) (interactive)
(let* ((branch (or (magit-get-current-branch) (let* ((branch (or (magit-get-current-branch)
(error "Don't push a detached head. That's gross"))) (error "Don't push a detached head. That's gross")))
@ -3045,7 +3066,15 @@ typing and automatically refreshes the status buffer."
(if (and (not branch-remote) (if (and (not branch-remote)
(not current-prefix-arg)) (not current-prefix-arg))
(magit-set push-remote "branch" branch "remote")) (magit-set push-remote "branch" branch "remote"))
(magit-run-git-async "push" "-v" push-remote (format "%s:%s" branch ref-branch)))) (magit-run-git-async "push" "-v" push-remote
(if ref-branch
(format "%s:%s" branch ref-branch)
branch))
;; Although git will automatically set up the remote,
;; it doesn't set up the branch to merge (at least as of Git 1.6.6.1),
;; so we have to do that manually.
(unless ref-branch
(magit-set (concat "refs/heads/" branch) "branch" branch "merge"))))
;;; Log edit mode ;;; Log edit mode
@ -3082,8 +3111,7 @@ Prefix arg means justify as well."
(define-derived-mode magit-log-edit-mode text-mode "Magit Log Edit" (define-derived-mode magit-log-edit-mode text-mode "Magit Log Edit"
(set (make-local-variable 'fill-paragraph-function) (set (make-local-variable 'fill-paragraph-function)
'magit-log-fill-paragraph) 'magit-log-fill-paragraph))
(run-mode-hooks 'magit-log-edit-mode-hook))
(defun magit-log-edit-cleanup () (defun magit-log-edit-cleanup ()
(save-excursion (save-excursion
@ -3223,7 +3251,7 @@ toggled on. When it's toggled on for the first time, return
(bury-buffer) (bury-buffer)
(when (file-exists-p ".git/MERGE_MSG") (when (file-exists-p ".git/MERGE_MSG")
(delete-file ".git/MERGE_MSG")) (delete-file ".git/MERGE_MSG"))
(magit-revert-buffers default-directory t) (magit-update-vc-modeline default-directory)
(when magit-pre-log-edit-window-configuration (when magit-pre-log-edit-window-configuration
(set-window-configuration magit-pre-log-edit-window-configuration) (set-window-configuration magit-pre-log-edit-window-configuration)
(setq magit-pre-log-edit-window-configuration nil)))) (setq magit-pre-log-edit-window-configuration nil))))
@ -3348,7 +3376,7 @@ This means that the eventual commit does 'git commit --allow-empty'."
;;; Tags ;;; Tags
(defun magit-tag (name rev) (magit-define-command tag (name rev)
"Create a new lightweight tag with the given NAME at REV. "Create a new lightweight tag with the given NAME at REV.
\('git tag NAME')." \('git tag NAME')."
(interactive (interactive
@ -3357,7 +3385,7 @@ This means that the eventual commit does 'git commit --allow-empty'."
(magit-read-rev "Place tag on: " (or (magit-default-rev) "HEAD")))) (magit-read-rev "Place tag on: " (or (magit-default-rev) "HEAD"))))
(magit-run-git "tag" name rev)) (magit-run-git "tag" name rev))
(defun magit-annotated-tag (name) (magit-define-command annotated-tag (name)
"Start composing an annotated tag with the given NAME. "Start composing an annotated tag with the given NAME.
Tag will point to the current 'HEAD'." Tag will point to the current 'HEAD'."
(interactive "sNew annotated tag name: ") (interactive "sNew annotated tag name: ")
@ -3386,12 +3414,12 @@ Tag will point to the current 'HEAD'."
(let ((magit-old-top-section nil)) (let ((magit-old-top-section nil))
(magit-wash-sequence #'magit-wash-stash))) (magit-wash-sequence #'magit-wash-stash)))
(defun magit-insert-stashes () (magit-define-inserter stashes ()
(magit-git-section 'stashes (magit-git-section 'stashes
"Stashes:" 'magit-wash-stashes "Stashes:" 'magit-wash-stashes
"stash" "list")) "stash" "list"))
(defun magit-stash (description) (magit-define-command stash (description)
"Create new stash of working tree and staging area named DESCRIPTION. "Create new stash of working tree and staging area named DESCRIPTION.
Working tree and staging area revert to the current 'HEAD'. Working tree and staging area revert to the current 'HEAD'.
With prefix argument, changes in staging area are kept. With prefix argument, changes in staging area are kept.
@ -3400,9 +3428,10 @@ With prefix argument, changes in staging area are kept.
(apply 'magit-run-git `("stash" (apply 'magit-run-git `("stash"
"save" "save"
,@(when current-prefix-arg '("--keep-index")) ,@(when current-prefix-arg '("--keep-index"))
"--"
,description))) ,description)))
(defun magit-stash-snapshot () (magit-define-command stash-snapshot ()
"Create new stash of working tree and staging area; keep changes in place. "Create new stash of working tree and staging area; keep changes in place.
\('git stash save \"Snapshot...\"; git stash apply stash@{0}')" \('git stash save \"Snapshot...\"; git stash apply stash@{0}')"
(interactive) (interactive)
@ -3451,32 +3480,6 @@ With prefix argument, changes in staging area are kept.
range args) range args)
(magit-stash-mode t))))))) (magit-stash-mode t)))))))
;;; Topic branches (using topgit)
(defun magit-wash-topic ()
(if (search-forward-regexp "^..\\(t/\\S-+\\)\\s-+\\(\\S-+\\)\\s-+\\(\\S-+\\)"
(line-end-position) t)
(let ((topic (match-string 1)))
(delete-region (match-beginning 2) (match-end 2))
(goto-char (line-beginning-position))
(delete-char 4)
(insert "\t")
(goto-char (line-beginning-position))
(magit-with-section topic 'topic
(magit-set-section-info topic)
(forward-line)))
(delete-region (line-beginning-position) (1+ (line-end-position))))
t)
(defun magit-wash-topics ()
(let ((magit-old-top-section nil))
(magit-wash-sequence #'magit-wash-topic)))
(defun magit-insert-topics ()
(magit-git-section 'topics
"Topics:" 'magit-wash-topics
"branch" "-v"))
;;; Commits ;;; Commits
(defun magit-commit-at-point (&optional nil-ok-p) (defun magit-commit-at-point (&optional nil-ok-p)
@ -3617,7 +3620,7 @@ With a non numeric prefix ARG, show all entries"
(defvar magit-log-grep-buffer-name "*magit-grep-log*" (defvar magit-log-grep-buffer-name "*magit-grep-log*"
"Buffer name for display of log grep results.") "Buffer name for display of log grep results.")
(defun magit-display-log (ask-for-range &rest extra-args) (magit-define-command display-log (ask-for-range &rest extra-args)
(let* ((log-range (if ask-for-range (let* ((log-range (if ask-for-range
(magit-read-rev-range "Log" "HEAD") (magit-read-rev-range "Log" "HEAD")
"HEAD")) "HEAD"))
@ -3656,7 +3659,7 @@ level commits."
(format "--grep=%s" (shell-quote-argument str)))) (format "--grep=%s" (shell-quote-argument str))))
(magit-log-mode t))) (magit-log-mode t)))
(defun magit-log-long (&optional arg) (magit-define-command log-long (&optional arg)
(interactive "P") (interactive "P")
(let* ((range (if arg (let* ((range (if arg
(magit-read-rev-range "Long log" "HEAD") (magit-read-rev-range "Long log" "HEAD")
@ -3687,7 +3690,7 @@ level commits."
:lighter () :lighter ()
:keymap magit-reflog-mode-map) :keymap magit-reflog-mode-map)
(defun magit-reflog (head) (magit-define-command reflog (head)
(interactive (list (magit-read-rev "Reflog of" (or (magit-guess-branch) "HEAD")))) (interactive (list (magit-read-rev "Reflog of" (or (magit-guess-branch) "HEAD"))))
(if head (if head
(let* ((topdir (magit-get-top-dir default-directory)) (let* ((topdir (magit-get-top-dir default-directory))
@ -3697,7 +3700,7 @@ level commits."
#'magit-refresh-reflog-buffer head args) #'magit-refresh-reflog-buffer head args)
(magit-reflog-mode t)))) (magit-reflog-mode t))))
(defun magit-reflog-head () (magit-define-command reflog-head ()
(interactive) (interactive)
(magit-reflog "HEAD")) (magit-reflog "HEAD"))
@ -3717,7 +3720,7 @@ level commits."
:lighter () :lighter ()
:keymap magit-diff-mode-map) :keymap magit-diff-mode-map)
(defun magit-diff (range) (magit-define-command diff (range)
(interactive (list (magit-read-rev-range "Diff"))) (interactive (list (magit-read-rev-range "Diff")))
(if range (if range
(let* ((dir default-directory) (let* ((dir default-directory)
@ -3728,7 +3731,7 @@ level commits."
(magit-mode-init dir 'diff #'magit-refresh-diff-buffer range args) (magit-mode-init dir 'diff #'magit-refresh-diff-buffer range args)
(magit-diff-mode t))))) (magit-diff-mode t)))))
(defun magit-diff-working-tree (rev) (magit-define-command diff-working-tree (rev)
(interactive (list (magit-read-rev "Diff with" (magit-default-rev)))) (interactive (list (magit-read-rev "Diff with" (magit-default-rev))))
(magit-diff (or rev "HEAD"))) (magit-diff (or rev "HEAD")))
@ -3772,7 +3775,7 @@ level commits."
(dolist (branch branches) (dolist (branch branches)
(let* ((name (car branch)) (let* ((name (car branch))
(ref (cdr branch)) (ref (cdr branch))
(hash (magit-git-string "rev-parse" ref)) (hash (magit-rev-parse ref))
(reported-branch (gethash hash reported))) (reported-branch (gethash hash reported)))
(unless (or (and reported-branch (unless (or (and reported-branch
(string= (file-name-nondirectory ref) (string= (file-name-nondirectory ref)
@ -3916,8 +3919,6 @@ level commits."
((stash) ((stash)
(magit-show-stash info) (magit-show-stash info)
(pop-to-buffer magit-stash-buffer-name)) (pop-to-buffer magit-stash-buffer-name))
((topic)
(magit-checkout info))
((longer) ((longer)
(magit-log-show-more-entries ())))) (magit-log-show-more-entries ()))))
@ -4018,6 +4019,7 @@ Return values:
(defvar magit-show-branches-mode-map (defvar magit-show-branches-mode-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(define-key map (kbd "RET") 'magit-branches-window-checkout)
(define-key map (kbd "b") 'magit-branches-window-checkout) (define-key map (kbd "b") 'magit-branches-window-checkout)
(define-key map (kbd "k") 'magit-remove-branch) (define-key map (kbd "k") 'magit-remove-branch)
(define-key map (kbd "m") 'magit-branches-window-manual-merge) (define-key map (kbd "m") 'magit-branches-window-manual-merge)
@ -4041,12 +4043,7 @@ Return values:
(defun magit--branch-name-from-line (line) (defun magit--branch-name-from-line (line)
"Extract the branch name from line LINE of 'git branch' output." "Extract the branch name from line LINE of 'git branch' output."
(let ((branch (get-text-property 0 'branch-name line))) (get-text-property 0 'branch-name line))
(if (and branch
(get-text-property 0 'remote line)
(string-match-p "^remotes/" branch))
(substring branch 8)
branch)))
(defun magit--branch-name-at-point () (defun magit--branch-name-at-point ()
"Get the branch name in the line at point." "Get the branch name in the line at point."
@ -4060,6 +4057,12 @@ Return values:
(save-excursion (save-excursion
(magit-show-branches))) (magit-show-branches)))
(defun magit-remove-remote (ref)
"Return REF with any remote part removed."
(if (string-match "^remotes/" ref)
(substring ref 8)
ref))
(defun magit-remove-branch (&optional force) (defun magit-remove-branch (&optional force)
"Remove the branch in the line at point. "Remove the branch in the line at point.
With prefix force the removal even it it hasn't been merged." With prefix force the removal even it it hasn't been merged."
@ -4067,7 +4070,9 @@ With prefix force the removal even it it hasn't been merged."
(let ((args (list "branch" (let ((args (list "branch"
(if force "-D" "-d") (if force "-D" "-d")
(when (magit--is-branch-at-point-remote) "-r") (when (magit--is-branch-at-point-remote) "-r")
(magit--branch-name-at-point)))) ;; remove the remotes part
(magit-remove-remote
(magit--branch-name-at-point)))))
(save-excursion (save-excursion
(apply 'magit-run-git (remq nil args)) (apply 'magit-run-git (remq nil args))
(magit-show-branches)))) (magit-show-branches))))
@ -4097,7 +4102,7 @@ With prefix force the removal even it it hasn't been merged."
"\\(.+?\\) +" ; branch name "\\(.+?\\) +" ; branch name
"\\(?:" "\\(?:"
"\\([0-9a-fA-F]\\{7\\}\\) " ; sha1 "\\([0-9a-fA-F]\\{7,8\\}\\) " ; sha1
"\\|\\(-> \\)" ; or the pointer to a ref "\\|\\(-> \\)" ; or the pointer to a ref
"\\)" "\\)"
@ -4235,6 +4240,46 @@ With prefix force the removal even it it hasn't been merged."
(magit-list-buffers)) (magit-list-buffers))
'string=))) 'string=)))
;; Extensions
(defvar magit-active-extensions '())
(defstruct magit-extension
keys menu actions insert remote-string commands)
(defun magit-install-extension (ext)
(add-to-list 'magit-active-extensions ext)
(let ((keys (magit-extension-keys ext))
(menu (magit-extension-menu ext))
(actions (magit-extension-actions ext))
(insert (magit-extension-insert ext))
(remote-string (magit-extension-remote-string ext))
(commands (magit-extension-commands ext)))
(when keys
(mapc (lambda (x) (define-key magit-mode-map (car x) (cdr x)))
keys))
(when menu
(easy-menu-add-item 'magit-mode-menu '("Extensions") menu))
(when insert
(mapc (lambda (x)
(destructuring-bind (position reference hook) x
(add-hook (intern (format "magit-insert-%s%s-hook"
reference position))
hook)))
insert))
(when remote-string
(add-hook 'magit-remote-string-hook remote-string))
(when commands
(mapc (lambda (x)
(add-hook (intern (format "magit-%s:functions" (car x)))
(cdr x)))
commands))))
(defun magit-get-extensions-actions (action)
(mapcar (lambda (ext)
(cadr (assoc action (magit-extension-actions ext))))
magit-active-extensions))
(provide 'magit) (provide 'magit)
;;; magit.el ends here ;;; magit.el ends here

View file

@ -504,7 +504,8 @@ local branch. Deleting works for both local and remote branches.
You can merge the branch in the current line by typing @kbd{m} for a You can merge the branch in the current line by typing @kbd{m} for a
manual merge and @kbd{M} for an automatic merge. manual merge and @kbd{M} for an automatic merge.
With @kbd{b} you can check out the branch in the current line. With @kbd{RET} or @kbd{b} you can check out the branch in the current
line.
Typing @kbd{$} shows the @code{*magit-process*} buffer which contains Typing @kbd{$} shows the @code{*magit-process*} buffer which contains
the transcript of the most recent command. the transcript of the most recent command.
@ -653,10 +654,12 @@ it, like from any other diff.
Magit will run @code{git push} when you type @kbd{P}. If you give a Magit will run @code{git push} when you type @kbd{P}. If you give a
prefix argument to @kbd{P}, you will be prompted for the repository to prefix argument to @kbd{P}, you will be prompted for the repository to
push to. When no default remote repositor has been configured yet for push to. When no default remote repository has been configured yet for
the current branch, you will be prompted as well. Typing @kbd{P} will the current branch, you will be prompted as well. Typing @kbd{P} will
only push the current branch to the remote. In other words, it will only push the current branch to the remote. In other words, it will run
run @code{git push <remote> <branch>}. @code{git push <remote> <branch>}. The branch will be created in the
remote if it doesn't exist already. The local branch will be configured
so that it pulls from the new remote branch.
Typing @kbd{f} will run @code{git remote update}. With a prefix arg, it Typing @kbd{f} will run @code{git remote update}. With a prefix arg, it
will prompt for the name of the remote to update. Typing @kbd{F} will will prompt for the name of the remote to update. Typing @kbd{F} will
@ -680,13 +683,13 @@ Magit shows them in a section called @emph{Unpulled changes}. Typing
@node Interfacing with Subversion @node Interfacing with Subversion
@chapter Interfacing with Subversion @chapter Interfacing with Subversion
Typing @kbd{N r} runs @code{git svn rebase} and typing @kbd{N c} runs Typing @kbd{N r} runs @code{git svn rebase}, typing @kbd{N c} runs
@code{git svn dcommit}. @code{git svn dcommit} and typing @kbd{N f} runs @code{git svn fetch}.
@kbd{N f} will prompt you for a (numeric, Subversion) revision and @kbd{N s} will prompt you for a (numeric, Subversion) revision and
then search for a corresponding Git sha1 for the commit. This is then search for a corresponding Git sha1 for the commit. This is
limited to the path of the remote Subversion repository. With a prefix limited to the path of the remote Subversion repository. With a prefix
(@kbd{C-u N f} the user will also be prompted for a branch to search (@kbd{C-u N s} the user will also be prompted for a branch to search
in. in.
@node Using Git Directly @node Using Git Directly