Browse files

Merge branch 'extensions'

Conflicts:
	magit.el
  • Loading branch information...
2 parents 8be54f6 + 761d6ad commit d93048fb947558db515a7e09b684c4646cff7ef4 @philjackson philjackson committed Jul 11, 2010
Showing with 529 additions and 294 deletions.
  1. +5 −4 Makefile.am
  2. +185 −0 magit-svn.el
  3. +99 −0 magit-topgit.el
  4. +236 −286 magit.el
  5. +4 −4 magit.texi
View
9 Makefile.am
@@ -1,17 +1,18 @@
lispdir = $(datadir)/emacs/site-lisp
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
info_TEXINFOS = magit.texi
-CLEANFILES = magit.elc
-EXTRA_DIST = magit.el 50magit.el magit.spec
+CLEANFILES = magit-*.elc
+EXTRA_DIST = magit.el 50magit.el magit.spec magit-svn.el magit-topgit.el
%.elc: %.el
@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
View
185 magit-svn.el
@@ -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
View
99 magit-topgit.el
@@ -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
View
522 magit.el
@@ -25,6 +25,7 @@
;; Copyright (C) 2009 Steve Purcell.
;; Copyright (C) 2010 Ævar Arnfjörð Bjarmason.
;; Copyright (C) 2010 Óscar Fuentes.
+;; Copyright (C) 2010 Yann Hodique
;; Author: Marius Vollmer <marius.vollmer@nokia.com>
;; Maintainer: Phil Jackson <phil@shellarchive.co.uk>
@@ -358,6 +359,10 @@ Many Magit faces inherit from this one by default."
(make-variable-buffer-local 'magit-submode)
(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 ()
(if (fboundp 'use-region-p)
(use-region-p)
@@ -1211,6 +1216,18 @@ TITLE is the displayed title of the section."
(interactive)
(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-highlighted-section nil)
@@ -1246,12 +1263,29 @@ TITLE is the displayed title of the section."
;;; Very schemish...
(or (null prefix)
(if (eq (car prefix) '*)
- (or (magit-prefix-p (cdr prefix) list)
- (and (not (null list))
- (magit-prefix-p prefix (cdr list))))
- (and (not (null list))
- (equal (car prefix) (car list))
- (magit-prefix-p (cdr prefix) (cdr list))))))
+ (or (magit-prefix-p (cdr prefix) list)
+ (and (not (null list))
+ (magit-prefix-p prefix (cdr list))))
+ (and (not (null list))
+ (equal (car prefix) (car 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)
"Make different action depending of current section.
@@ -1265,30 +1299,33 @@ CLAUSES is a list of CLAUSE, each clause is (SECTION-TYPE &BODY)
where SECTION-TYPE describe section where BODY will be run."
(declare (indent 1))
(let ((section (car head))
- (info (cadr head))
- (type (make-symbol "*type*"))
- (context (make-symbol "*context*"))
- (opname (caddr head)))
+ (info (cadr head))
+ (type (make-symbol "*type*"))
+ (context (make-symbol "*context*"))
+ (extra (make-symbol "*extra*"))
+ (opname (caddr head)))
`(let* ((,section (magit-current-section))
- (,info (magit-section-info ,section))
- (,type (magit-section-type ,section))
- (,context (magit-section-context-type ,section)))
+ (,info (magit-section-info ,section))
+ (,type (magit-section-type ,section))
+ (,context (magit-section-context-type ,section))
+ (,extra (magit-get-extensions-actions ,opname)))
(cond ,@(mapcar (lambda (clause)
- (if (eq (car clause) t)
- clause
- (let ((prefix (reverse (car clause)))
- (body (cdr clause)))
- `((magit-prefix-p ',prefix ,context)
- ,@body))))
- clauses)
- ,@(if opname
- `(((not ,type)
- (error "Nothing to %s here" ,opname))
- (t
- (error "Can't %s a %s"
- ,opname
- (or (get ,type 'magit-description)
- ,type)))))))))
+ (if (eq (car clause) t)
+ clause
+ (let ((prefix (reverse (car clause)))
+ (body (cdr clause)))
+ `((magit-prefix-p ',prefix ,context)
+ ,@body))))
+ clauses)
+ ,@(magit-dynamic-clauses-helper extra context)
+ ,@(if opname
+ `(((not ,type)
+ (error "Nothing to %s here" ,opname))
+ (t
+ (error "Can't %s a %s"
+ ,opname
+ (or (get ,type 'magit-description)
+ ,type)))))))))
(defmacro magit-section-action (head &rest clauses)
(declare (indent 1))
@@ -1300,7 +1337,28 @@ where SECTION-TYPE describe section where BODY will be run."
FUNC should leave point at the end of the modified region"
(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
@@ -1492,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 staged "Staged changes")
(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 2)
@@ -1528,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 "DEL") 'magit-show-item-or-scroll-down)
(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 s") 'magit-rewrite-start)
(define-key map (kbd "r t") 'magit-rewrite-stop)
@@ -1704,10 +1758,6 @@ FUNC should leave point at the end of the modified region"
["Merge (no commit)" magit-manual-merge t]
["Interactive resolve" magit-interactive-resolve-item t]
["Rebase" magit-rebase-step t]
- ("Git SVN"
- ["Rebase" magit-svn-rebase (magit-svn-enabled)]
- ["Commit" magit-svn-dcommit (magit-svn-enabled)]
- )
("Rewrite"
["Start" magit-rewrite-start t]
["Stop" magit-rewrite-stop t]
@@ -1720,6 +1770,8 @@ FUNC should leave point at the end of the modified region"
["Pull" magit-pull t]
["Remote update" magit-remote-update t]
"---"
+ ("Extensions")
+ "---"
["Display Git output" magit-display-process t]
["Quit Magit" quit-window t]))
@@ -2258,22 +2310,23 @@ in the corresponding directories."
(defun magit-apply-hunk-item-reverse (hunk &rest 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-diff-options '()))
(magit-git-section 'unstaged title 'magit-wash-raw-diffs
- "diff-files"))))
-
-(defun magit-insert-staged-changes (no-commit)
- (let ((magit-hide-diffs t)
- (base (if no-commit
- (magit-git-string "mktree")
- "HEAD")))
- (let ((magit-diff-options '("--cached"))
- (magit-ignore-unmerged-raw-diffs t))
- (magit-git-section 'staged "Staged changes:" 'magit-wash-raw-diffs
- "diff-index" "--cached"
- base))))
+ "diff-files"))))
+
+(magit-define-inserter staged-changes (staged no-commit)
+ (when staged
+ (let ((magit-hide-diffs t)
+ (base (if no-commit
+ (magit-git-string "mktree")
+ "HEAD")))
+ (let ((magit-diff-options '("--cached"))
+ (magit-ignore-unmerged-raw-diffs t))
+ (magit-git-section 'staged "Staged changes:" 'magit-wash-raw-diffs
+ "diff-index" "--cached"
+ base)))))
;;; Logs and Commits
@@ -2467,33 +2520,25 @@ insert a line to tell how to insert more of them"
(defun magit-remote-branch-name (remote branch)
"Get the name of the branch BRANCH on remote REMOTE"
- (if (string= remote ".") branch (concat remote "/" branch)))
-
-(defun magit-insert-unpulled-commits (remote branch)
- (magit-git-section 'unpulled
- "Unpulled commits:" 'magit-wash-log
- "log" "--pretty=format:* %H %s"
- (format "HEAD..%s"
- (magit-remote-branch-name remote branch))))
-
-(defun magit-insert-unpushed-commits (remote branch)
- (magit-git-section 'unpushed
- "Unpushed commits:" 'magit-wash-log
- "log" "--pretty=format:* %H %s"
- (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))))
+ (if (string= remote ".")
+ branch
+ (concat remote "/" branch)))
+
+(magit-define-inserter unpulled-commits (remote branch)
+ (when remote
+ (magit-git-section 'unpulled
+ "Unpulled commits:" 'magit-wash-log
+ "log" "--pretty=format:* %H %s"
+ (format "HEAD..%s"
+ (magit-remote-branch-name remote branch)))))
+
+(magit-define-inserter unpushed-commits (remote branch)
+ (when remote
+ (magit-git-section 'unpushed
+ "Unpushed commits:" 'magit-wash-log
+ "log" "--pretty=format:* %H %s"
+ (format "%s..HEAD"
+ (magit-remote-branch-name remote branch)))))
(defun magit-remote-branch-for (local-branch)
"Guess the remote branch name that LOCAL-BRANCH is tracking."
@@ -2504,32 +2549,31 @@ insert a line to tell how to insert more of them"
;;; Status
-(defun magit-remote-string (remote remote-branch svn-info)
+(defvar magit-remote-string-hook nil)
+
+(defun magit-remote-string (remote remote-branch)
(cond
((string= "." remote)
(format "branch %s"
(propertize remote-branch 'face 'magit-branch)))
(remote
- (concat
- (propertize remote-branch 'face 'magit-branch)
- " @ "
- remote
- " ("
- (magit-get "remote" remote "url")
- ")"))
- (svn-info
- (concat (cdr (assoc 'url svn-info))
- " @ "
- (cdr (assoc 'revision svn-info))))))
+ (concat
+ (propertize remote-branch 'face 'magit-branch)
+ " @ "
+ remote
+ " ("
+ (magit-get "remote" remote "url")
+ ")"))
+ (t
+ (run-hook-with-args-until-success 'magit-remote-string-hook))))
(defun magit-refresh-status ()
(magit-create-buffer-sections
(magit-with-section 'status nil
(let* ((branch (magit-get-current-branch))
(remote (and branch (magit-get "branch" branch "remote")))
(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 svn-info))
+ (remote-string (magit-remote-string remote remote-branch))
(head (magit-git-string
"log" "--max-count=1" "--abbrev-commit" "--pretty=oneline"))
(no-commit (not head)))
@@ -2554,22 +2598,15 @@ insert a line to tell how to insert more of them"
(magit-git-exit-code "update-index" "--refresh")
(magit-insert-untracked-files)
(magit-insert-stashes)
- (magit-insert-topics)
(magit-insert-pending-changes)
(magit-insert-pending-commits)
- (when remote
- (magit-insert-unpulled-commits remote remote-branch))
- (when svn-info
- (magit-insert-unpulled-svn-commits t))
+ (magit-insert-unpulled-commits remote remote-branch)
(let ((staged (or no-commit (magit-anything-staged-p))))
(magit-insert-unstaged-changes
(if staged "Unstaged changes:" "Changes:"))
- (if staged
- (magit-insert-staged-changes no-commit)))
- (when remote
- (magit-insert-unpushed-commits remote remote-branch))
- (when svn-info
- (magit-insert-unpushed-svn-commits t))))))
+ (magit-insert-staged-changes staged no-commit))
+ (magit-insert-unpushed-commits remote remote-branch)
+ (run-hooks 'magit-refresh-status-hook)))))
(defun magit-init (dir)
"Initialize git repository in the DIR directory."
@@ -2706,7 +2743,7 @@ rev... maybe."
t))
nil))
-(defun magit-checkout (revision)
+(magit-define-command checkout (revision)
"Switch 'HEAD' to REVISION and update working tree.
Fails if working tree or staging area contain uncommitted changes.
If REVISION is a remote branch, offer to create a local tracking branch.
@@ -2722,7 +2759,7 @@ If REVISION is a remote branch, offer to create a local tracking branch.
(parent (magit-read-rev "Parent" cur-branch)))
(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.
Fails if working tree or staging area contain uncommitted changes.
\('git checkout -b BRANCH REVISION')."
@@ -2757,7 +2794,7 @@ With a prefix-arg, the merge will be squashed.
"--no-ff")
(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.
\('git merge REVISION')."
(interactive (list (magit-read-rev "Merge" (magit-guess-branch))))
@@ -2791,118 +2828,20 @@ With a prefix-arg, the merge will be squashed.
(if rev
(magit-run-git "rebase" (magit-rev-to-git rev))))
(let ((cursor-in-echo-area t)
- (message-log-max nil))
- (message "Rebase in progress. Abort, Skip, or Continue? ")
- (let ((reply (read-event)))
- (case reply
- ((?A ?a)
- (magit-run-git "rebase" "--abort"))
- ((?S ?s)
- (magit-run-git "rebase" "--skip"))
- ((?C ?c)
- (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))))
+ (message-log-max nil))
+ (message "Rebase in progress. Abort, Skip, or Continue? ")
+ (let ((reply (read-event)))
+ (case reply
+ ((?A ?a)
+ (magit-run-git "rebase" "--abort"))
+ ((?S ?s)
+ (magit-run-git "rebase" "--skip"))
+ ((?C ?c)
+ (magit-run-git "rebase" "--continue"))))))))
;;; 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.
Any differences from REVISION become new changes to be committed.
With prefix argument, all uncommitted changes in working tree
@@ -2920,7 +2859,7 @@ and staging area are lost.
(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.
Uncomitted changes in both working tree and staging area are lost.
\('git reset --hard REVISION')."
@@ -2929,7 +2868,7 @@ Uncomitted changes in both working tree and staging area are lost.
"HEAD"))))
(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.
\('git reset --hard HEAD')."
(interactive)
@@ -2950,7 +2889,7 @@ Uncomitted changes in both working tree and staging area are lost.
(prin1 info (current-buffer))
(princ "\n" (current-buffer))))
-(defun magit-insert-pending-commits ()
+(magit-define-inserter pending-commits ()
(let* ((info (magit-read-rewrite-info))
(pending (cdr (assq 'pending info))))
(when pending
@@ -2993,7 +2932,7 @@ Uncomitted changes in both working tree and staging area are lost.
((pending commit)
(magit-rewrite-set-commit-property info 'used nil))))
-(defun magit-insert-pending-changes ()
+(magit-define-inserter pending-changes ()
(let* ((info (magit-read-rewrite-info))
(orig (cadr (assq 'orig info))))
(when orig
@@ -3063,7 +3002,7 @@ Uncomitted changes in both working tree and staging area are lost.
;;; Updating, pull, and push
-(defun magit-remote-update (&optional remote)
+(magit-define-command remote-update (&optional remote)
"Update REMOTE. If nil, update all remotes.
When called interactively, update the current remote unless a
@@ -3072,10 +3011,9 @@ update it."
(interactive (list (when current-prefix-arg (magit-read-remote))))
(cond
(remote (magit-run-git-async "fetch" remote))
- ((magit-svn-enabled) (magit-run-git-async "svn" "fetch"))
(t (magit-run-git-async "remote" "update"))))
-(defun magit-pull ()
+(magit-define-command pull ()
(interactive)
(let* ((branch (magit-get-current-branch))
(config-branch (and branch (magit-get "branch" branch "merge")))
@@ -3114,7 +3052,7 @@ typing and automatically refreshes the status buffer."
args)
nil nil nil t))))
-(defun magit-push ()
+(magit-define-command push ()
(interactive)
(let* ((branch (or (magit-get-current-branch)
(error "Don't push a detached head. That's gross")))
@@ -3422,7 +3360,7 @@ Prefix arg means justify as well."
;;; Tags
-(defun magit-tag (name rev)
+(magit-define-command tag (name rev)
"Create a new lightweight tag with the given NAME at REV.
\('git tag NAME')."
(interactive
@@ -3431,7 +3369,7 @@ Prefix arg means justify as well."
(magit-read-rev "Place tag on: " (or (magit-default-rev) "HEAD"))))
(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.
Tag will point to the current 'HEAD'."
(interactive "sNew annotated tag name: ")
@@ -3460,12 +3398,12 @@ Tag will point to the current 'HEAD'."
(let ((magit-old-top-section nil))
(magit-wash-sequence #'magit-wash-stash)))
-(defun magit-insert-stashes ()
+(magit-define-inserter stashes ()
(magit-git-section 'stashes
"Stashes:" 'magit-wash-stashes
"stash" "list"))
-(defun magit-stash (description)
+(magit-define-command stash (description)
"Create new stash of working tree and staging area named DESCRIPTION.
Working tree and staging area revert to the current 'HEAD'.
With prefix argument, changes in staging area are kept.
@@ -3476,7 +3414,7 @@ With prefix argument, changes in staging area are kept.
,@(when current-prefix-arg '("--keep-index"))
,description)))
-(defun magit-stash-snapshot ()
+(magit-define-command stash-snapshot ()
"Create new stash of working tree and staging area; keep changes in place.
\('git stash save \"Snapshot...\"; git stash apply stash@{0}')"
(interactive)
@@ -3506,50 +3444,24 @@ With prefix argument, changes in staging area are kept.
(stash-id (magit-git-string "rev-list" "-1" stash)))
(cond ((and (equal magit-currently-shown-stash stash-id)
(with-current-buffer buf
- (> (length (buffer-string)) 1)))
- (let ((win (get-buffer-window buf)))
- (cond ((not win)
- (display-buffer buf))
- (scroll
- (with-selected-window win
- (funcall scroll))))))
- (t
- (setq magit-currently-shown-stash stash-id)
- (display-buffer buf)
- (with-current-buffer buf
- (set-buffer buf)
- (goto-char (point-min))
- (let* ((range (cons (concat stash "^2^") stash))
- (args (magit-rev-range-to-git range)))
- (magit-mode-init dir 'diff #'magit-refresh-diff-buffer
- range args)
- (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"))
+ (> (length (buffer-string)) 1)))
+ (let ((win (get-buffer-window buf)))
+ (cond ((not win)
+ (display-buffer buf))
+ (scroll
+ (with-selected-window win
+ (funcall scroll))))))
+ (t
+ (setq magit-currently-shown-stash stash-id)
+ (display-buffer buf)
+ (with-current-buffer buf
+ (set-buffer buf)
+ (goto-char (point-min))
+ (let* ((range (cons (concat stash "^2^") stash))
+ (args (magit-rev-range-to-git range)))
+ (magit-mode-init dir 'diff #'magit-refresh-diff-buffer
+ range args)
+ (magit-stash-mode t)))))))
;;; Commits
@@ -3691,7 +3603,7 @@ With a non numeric prefix ARG, show all entries"
(defvar magit-log-grep-buffer-name "*magit-grep-log*"
"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
(magit-read-rev-range "Log" "HEAD")
"HEAD"))
@@ -3730,7 +3642,7 @@ level commits."
(format "--grep=%s" (shell-quote-argument str))))
(magit-log-mode t)))
-(defun magit-log-long (&optional arg)
+(magit-define-command log-long (&optional arg)
(interactive "P")
(let* ((range (if arg
(magit-read-rev-range "Long log" "HEAD")
@@ -3761,7 +3673,7 @@ level commits."
:lighter ()
: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"))))
(if head
(let* ((topdir (magit-get-top-dir default-directory))
@@ -3771,7 +3683,7 @@ level commits."
#'magit-refresh-reflog-buffer head args)
(magit-reflog-mode t))))
-(defun magit-reflog-head ()
+(magit-define-command reflog-head ()
(interactive)
(magit-reflog "HEAD"))
@@ -3791,18 +3703,18 @@ level commits."
:lighter ()
:keymap magit-diff-mode-map)
-(defun magit-diff (range)
+(magit-define-command diff (range)
(interactive (list (magit-read-rev-range "Diff")))
(if range
(let* ((dir default-directory)
- (args (magit-rev-range-to-git range))
- (buf (get-buffer-create "*magit-diff*")))
- (display-buffer buf)
- (with-current-buffer buf
- (magit-mode-init dir 'diff #'magit-refresh-diff-buffer range args)
- (magit-diff-mode t)))))
-
-(defun magit-diff-working-tree (rev)
+ (args (magit-rev-range-to-git range))
+ (buf (get-buffer-create "*magit-diff*")))
+ (display-buffer buf)
+ (with-current-buffer buf
+ (magit-mode-init dir 'diff #'magit-refresh-diff-buffer range args)
+ (magit-diff-mode t)))))
+
+(magit-define-command diff-working-tree (rev)
(interactive (list (magit-read-rev "Diff with" (magit-default-rev))))
(magit-diff (or rev "HEAD")))
@@ -3990,8 +3902,6 @@ level commits."
((stash)
(magit-show-stash info)
(pop-to-buffer magit-stash-buffer-name))
- ((topic)
- (magit-checkout info))
((longer)
(magit-log-show-more-entries ()))))
@@ -4313,6 +4223,46 @@ With prefix force the removal even it it hasn't been merged."
(magit-list-buffers))
'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)
;;; magit.el ends here
View
8 magit.texi
@@ -679,13 +679,13 @@ Magit shows them in a section called @emph{Unpulled changes}. Typing
@node Interfacing with Subversion
@chapter Interfacing with Subversion
-Typing @kbd{N r} runs @code{git svn rebase} and typing @kbd{N c} runs
-@code{git svn dcommit}.
+Typing @kbd{N r} runs @code{git svn rebase}, typing @kbd{N c} runs
+@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
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.
@node Using Git Directly

0 comments on commit d93048f

Please sign in to comment.