From 60780379f715a5cf837a3a64d0bef54fb188022f Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Wed, 9 Jun 2010 14:36:29 -0700 Subject: [PATCH 01/39] Make sure the status buffer is updated after a rebase. --- magit.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/magit.el b/magit.el index c03ad68d..ba06da8f 100644 --- a/magit.el +++ b/magit.el @@ -2939,7 +2939,7 @@ Uncomitted changes in both working tree and staging area are lost. (when (or noconfirm (yes-or-no-p "Stop rewrite? ")) (magit-write-rewrite-info nil) - (magit-need-refresh)))) + (magit-refresh)))) (defun magit-rewrite-abort () (interactive) From f846afe8507e5ca4cfdd7149b8b8ef13e13bc0cb Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Wed, 9 Jun 2010 22:26:13 -0700 Subject: [PATCH 02/39] Add an option to use "remote/name" style refs rather than "name (remote)". --- magit.el | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/magit.el b/magit.el index c03ad68d..1a20f50e 100644 --- a/magit.el +++ b/magit.el @@ -150,6 +150,16 @@ after a confirmation." :group 'magit :type 'boolean) +(defcustom magit-remote-ref-format 'branch-then-remote + "What format to use for autocompleting refs, in pariticular for remotes. + +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\"." + :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)) "Connection type used for the git process. @@ -571,12 +581,20 @@ return nil." (let ((branch (match-string 1 ref))) (push (cons branch branch) refs))) ((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)) ((string-match "refs/remotes/\\([^/]+\\)/\\(.+\\)" ref) - (push (cons (format "%s (%s)" - (match-string 2 ref) - (match-string 1 ref)) + (push (cons (if (eq magit-remote-ref-format 'branch-then-remote) + (format "%s (%s)" + (match-string 2 ref) + (match-string 1 ref)) + (format "%s/%s" + (match-string 1 ref) + (match-string 2 ref))) ref) refs)))))) refs)) From 7ef0b9e9cb357e760b929453ee72edae115d3686 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Thu, 10 Jun 2010 16:09:58 -0700 Subject: [PATCH 03/39] Make magit-update-remote respect a named remote above SVN. --- magit.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/magit.el b/magit.el index c03ad68d..1069937c 100644 --- a/magit.el +++ b/magit.el @@ -2985,8 +2985,8 @@ prefix arg is given. With prefix arg, prompt for a remote and update it." (interactive (list (when current-prefix-arg (magit-read-remote)))) (cond - ((magit-svn-enabled) (magit-run-git-async "svn" "fetch")) (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 () From c337dcc07cdbfd9e9724055708be249a40e746bf Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Wed, 16 Jun 2010 23:55:51 -0700 Subject: [PATCH 04/39] Make magit-name-rev a little cleaner. The main thing is using --no-undefined to eliminate an extra check. --- magit.el | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/magit.el b/magit.el index c03ad68d..7590e376 100644 --- a/magit.el +++ b/magit.el @@ -509,11 +509,9 @@ return nil." default-directory))))) (defun magit-name-rev (rev) - (and rev - (let ((name (magit-git-string "name-rev" "--name-only" rev))) - (if (or (not name) (string= name "undefined")) - rev - name)))) + (when rev + (let ((name (magit-git-string "name-rev" "--no-undefined" "--name-only" rev))) + (or name rev)))) (defun magit-put-line-property (prop val) (put-text-property (line-beginning-position) (line-beginning-position 2) From daa3ab8987db19194cbbf499af46738f0577861a Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Thu, 17 Jun 2010 00:10:35 -0700 Subject: [PATCH 05/39] Remove tags/ and remotes/ in name-rev when that doesn't create ambiguity. --- magit.el | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/magit.el b/magit.el index 7590e376..b2080531 100644 --- a/magit.el +++ b/magit.el @@ -508,10 +508,22 @@ return nil." (or (magit-get-top-dir default-directory) default-directory))))) +(defun magit-ref-ambiguous-p (ref) + "Return whether or not REF is ambiguous." + (/= (magit-git-exit-code "rev-parse" "--abbrev-ref" ref) 0)) + (defun magit-name-rev (rev) + "Return a human-readable name for REV. +Unlike git name-rev, this will remove tags/ and remotes/ prefixes +if that can be done unambiguously." (when rev (let ((name (magit-git-string "name-rev" "--no-undefined" "--name-only" rev))) - (or name 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) (put-text-property (line-beginning-position) (line-beginning-position 2) From 8cc37dcb99abee8dd83481500b81e2aa32e985a2 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Thu, 17 Jun 2010 01:57:28 -0700 Subject: [PATCH 06/39] Fix ref ambiguity detection. --- magit.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/magit.el b/magit.el index b2080531..1d54f9bb 100644 --- a/magit.el +++ b/magit.el @@ -510,7 +510,9 @@ return nil." (defun magit-ref-ambiguous-p (ref) "Return whether or not REF is ambiguous." - (/= (magit-git-exit-code "rev-parse" "--abbrev-ref" ref) 0)) + ;; 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) "Return a human-readable name for REV. From 2ea8cb2595328e685761258b15b307ba7629af29 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Thu, 24 Jun 2010 15:53:20 -0700 Subject: [PATCH 07/39] Add a magit-rev-parse function. --- magit.el | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/magit.el b/magit.el index 1d54f9bb..5e4863d4 100644 --- a/magit.el +++ b/magit.el @@ -508,6 +508,10 @@ return nil." (or (magit-get-top-dir 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, @@ -2935,7 +2939,7 @@ Uncomitted changes in both working tree and staging area are lost. (error "You have uncommitted changes")) (or (not (magit-read-rewrite-info)) (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)) (error "Can't rewrite a commit without a parent, sorry"))) (pending (magit-git-lines "rev-list" (concat base "..")))) @@ -3765,7 +3769,7 @@ level commits." (dolist (branch branches) (let* ((name (car branch)) (ref (cdr branch)) - (hash (magit-git-string "rev-parse" ref)) + (hash (magit-rev-parse ref)) (reported-branch (gethash hash reported))) (unless (or (and reported-branch (string= (file-name-nondirectory ref) From 1efde9202ce712495ed7010fac1c172be90d8b94 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Thu, 24 Jun 2010 15:56:54 -0700 Subject: [PATCH 08/39] Filter out HEAD refs from magit-name-rev. HEAD refs are nasty because they're highly contingent. Branches, tags, and remotes all require some commit to be made in order for the ref to point to a different rev, but HEADs just need something else to be checked out. Also, filtering out HEADs makes the name more portable. This is useful for Magithub, where the name may be passed on to GitHub. --- magit.el | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/magit.el b/magit.el index 5e4863d4..81aaaee4 100644 --- a/magit.el +++ b/magit.el @@ -521,9 +521,23 @@ return nil." (defun magit-name-rev (rev) "Return a human-readable name for REV. Unlike git name-rev, this will remove tags/ and remotes/ prefixes -if that can be done unambiguously." +if that can be done unambiguously. In addition, it will filter +out revs involving HEAD." (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 "^\\(.*\\" name)) + (setq name (magit-rev-parse ref))))) (setq rev (or name rev)) (when (string-match "^\\(?:tags\\|remotes\\)/\\(.*\\)" rev) (let ((plain-name (match-string 1 rev))) From 9b195b61e92c66ee73b1712f9b44c8893353320b Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Thu, 24 Jun 2010 16:40:28 -0700 Subject: [PATCH 09/39] Properly handle pushing a branch without a remote. Before, this did "git push remote branch-name:nil". Now it does "git push remote branch-name". Git automatically sets up the remote. --- magit.el | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/magit.el b/magit.el index c03ad68d..6ca688e9 100644 --- a/magit.el +++ b/magit.el @@ -3042,7 +3042,10 @@ typing and automatically refreshes the status buffer." (if (and (not branch-remote) (not current-prefix-arg)) (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)))) ;;; Log edit mode From a5b72daa029118db62d5a2530966131be50cd7be Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Thu, 24 Jun 2010 16:56:18 -0700 Subject: [PATCH 10/39] When pushing a new branch, manually add merge configuration. --- magit.el | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/magit.el b/magit.el index 6ca688e9..311e760a 100644 --- a/magit.el +++ b/magit.el @@ -3045,7 +3045,12 @@ typing and automatically refreshes the status buffer." (magit-run-git-async "push" "-v" push-remote (if ref-branch (format "%s:%s" branch ref-branch) - 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 From 9cc5e7e5d2e8f961fe6a4b19be0e362faf84fd3c Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Thu, 24 Jun 2010 17:17:58 -0700 Subject: [PATCH 11/39] Document the new branch behavior. --- magit.texi | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/magit.texi b/magit.texi index 5955aa6b..23c8d528 100644 --- a/magit.texi +++ b/magit.texi @@ -649,10 +649,12 @@ it, like from any other diff. 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 -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 -only push the current branch to the remote. In other words, it will -run @code{git push }. +only push the current branch to the remote. In other words, it will run +@code{git push }. 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 will prompt for the name of the remote to update. Typing @kbd{F} will From 51fffcb3a97b5d16dc48a6d38726707a316e6099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Fuentes?= Date: Sun, 27 Jun 2010 02:20:40 +0200 Subject: [PATCH 12/39] A better way for updating the VC modeline Revision 51a1b6d8 introduced a change that reverts all buffers after a commit operation for refreshing the VC modeline info. This can be slow (because refontification, etc) and have side effects (changes on display settings for some modes.) Instead of reverting the buffer, we now call `vc-find-file-hook' which is much faster and have no side effects. We now update the VC modeline info after resetting, because that operation may change the VC status without changing the file contents (commit a change and then reset to HEAD^, for instance.) --- magit.el | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/magit.el b/magit.el index 3af0ad3b..6c291a85 100644 --- a/magit.el +++ b/magit.el @@ -1805,6 +1805,15 @@ Please see the manual for a complete description of Magit. (ignore-errors (revert-buffer t t nil)))))) +(defun magit-update-vc-modeline (dir) + (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-pending nil) @@ -2833,9 +2842,10 @@ and staging area are lost. (or (magit-default-rev) "HEAD^")) current-prefix-arg)) - (if revision - (magit-run-git "reset" (if hard "--hard" "--soft") - (magit-rev-to-git revision)))) + (when revision + (magit-run-git "reset" (if hard "--hard" "--soft") + (magit-rev-to-git revision)) + (magit-update-vc-modeline default-directory))) (defun magit-reset-head-hard (revision) "Switch 'HEAD' to REVISION, losing all changes. @@ -3210,7 +3220,7 @@ Prefix arg means justify as well." (bury-buffer) (when (file-exists-p ".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 (set-window-configuration magit-pre-log-edit-window-configuration) (setq magit-pre-log-edit-window-configuration nil)))) From 613834919f499d54c48157b185d91df20b0da55c Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Sun, 27 Jun 2010 19:05:59 +0100 Subject: [PATCH 13/39] Docstring for `magit-update-vc-modeline'. --- magit.el | 1 + 1 file changed, 1 insertion(+) diff --git a/magit.el b/magit.el index 6c291a85..acab41cd 100644 --- a/magit.el +++ b/magit.el @@ -1806,6 +1806,7 @@ Please see the manual for a complete description of Magit. (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) From 2d70b0868274f2644d64902b5054867241b70105 Mon Sep 17 00:00:00 2001 From: Yann Hodique Date: Mon, 28 Jun 2010 20:03:42 +0200 Subject: [PATCH 14/39] minimizing extensions patch on top of upstream --- magit-svn.el | 186 ++++++++++++++++ magit-topgit.el | 99 +++++++++ magit.el | 553 ++++++++++++++++++++++-------------------------- 3 files changed, 536 insertions(+), 302 deletions(-) create mode 100644 magit-svn.el create mode 100644 magit-topgit.el diff --git a/magit-svn.el b/magit-svn.el new file mode 100644 index 00000000..127bb8a1 --- /dev/null +++ b/magit-svn.el @@ -0,0 +1,186 @@ +;;; 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 . + +;;; 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 () + (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-find-rev))) + +(easy-menu-define magit-svn-extension-menu + nil + "Git SVN extension menu" + '("Git SVN" + ["Rebase" magit-svn-rebase (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-commands + '((remote-update . magit-svn-remote-update))) + +(defvar magit-svn-extension + (make-magit-extension :keys magit-svn-extension-keys + :menu magit-svn-extension-menu + :insert magit-svn-extension-inserters + :commands magit-svn-extension-commands + :remote-string 'magit-svn-remote-string)) + +(magit-install-extension magit-svn-extension) + +(provide 'magit-svn) +;;; magit-svn.el ends here diff --git a/magit-topgit.el b/magit-topgit.el new file mode 100644 index 00000000..17d42c83 --- /dev/null +++ b/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 . + +;;; 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 diff --git a/magit.el b/magit.el index acab41cd..7b4a66e5 100644 --- a/magit.el +++ b/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 ;; Maintainer: Phil Jackson @@ -1157,6 +1158,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) @@ -1192,12 +1205,32 @@ 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-helper (clauses context) + `(((magit-dynamic-clauses ,clauses ,context) t))) + +(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. @@ -1211,30 +1244,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)) @@ -1246,7 +1282,29 @@ 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 ,@(remove-if (lambda (x) (member x '(&optional &rest))) + arglist)) + ,@instr)))) ;;; Running commands @@ -1438,7 +1496,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) @@ -1474,9 +1531,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) @@ -1650,10 +1704,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] @@ -1666,6 +1716,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])) @@ -2204,22 +2256,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")))) + "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)))) +(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 @@ -2411,29 +2464,19 @@ insert a line to tell how to insert more of them" (or magit-marked-commit (error "No commit marked"))) -(defun magit-insert-unpulled-commits (remote branch) - (magit-git-section 'unpulled - "Unpulled commits:" 'magit-wash-log - "log" "--pretty=format:* %H %s" - (format "HEAD..%s/%s" 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/%s" 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/%s..HEAD" 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)))) +(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/%s..HEAD" remote branch)))) (defun magit-remote-branch-for (local-branch) "Guess the remote branch name that LOCAL-BRANCH is tracking." @@ -2444,62 +2487,54 @@ insert a line to tell how to insert more of them" ;;; Status -(defun magit-remote-string (remote svn-info) +(defvar magit-remote-string-hook nil) + +(defun magit-remote-string (remote) (if remote (concat remote " " (magit-get "remote" remote "url")) - (when svn-info - (concat (cdr (assoc 'url svn-info)) - " @ " - (cdr (assoc 'revision svn-info)))))) + (run-hook-with-args-until-success 'magit-remote-string-hook))) + +(defvar magit-refresh-status-hook nil) (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 svn-info)) - (head (magit-git-string - "log" "--max-count=1" "--abbrev-commit" "--pretty=oneline")) - (no-commit (not head))) - (when remote-string - (insert "Remote: " remote-string "\n")) - (insert (format "Local: %s %s\n" - (propertize (or branch "(detached)") - 'face 'magit-branch) - (abbreviate-file-name default-directory))) - (insert (format "Head: %s\n" - (if no-commit "nothing commited (yet)" head))) - (let ((merge-heads (magit-file-lines ".git/MERGE_HEAD"))) - (if merge-heads - (insert (format "Merging: %s\n" - (magit-concat-with-delim - ", " - (mapcar 'magit-name-rev merge-heads)))))) - (let ((rebase (magit-rebase-info))) - (if rebase - (insert (apply 'format "Rebasing: %s (%s of %s)\n" rebase)))) - (insert "\n") - (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)) - (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)))))) + (remote (and branch (magit-get "branch" branch "remote"))) + (remote-string (magit-remote-string remote)) + (head (magit-git-string + "log" "--max-count=1" "--abbrev-commit" "--pretty=oneline")) + (no-commit (not head))) + (when remote-string + (insert "Remote: " remote-string "\n")) + (insert (format "Local: %s %s\n" + (propertize (or branch "(detached)") + 'face 'magit-branch) + (abbreviate-file-name default-directory))) + (insert (format "Head: %s\n" + (if no-commit "nothing commited (yet)" head))) + (let ((merge-heads (magit-file-lines ".git/MERGE_HEAD"))) + (if merge-heads + (insert (format "Merging: %s\n" + (magit-concat-with-delim + ", " + (mapcar 'magit-name-rev merge-heads)))))) + (let ((rebase (magit-rebase-info))) + (if rebase + (insert (apply 'format "Rebasing: %s (%s of %s)\n" rebase)))) + (insert "\n") + (magit-git-exit-code "update-index" "--refresh") + (magit-insert-untracked-files) + (magit-insert-stashes) + (magit-insert-pending-changes) + (magit-insert-pending-commits) + (magit-insert-unpulled-commits remote branch) + (let ((staged (or no-commit (magit-anything-staged-p)))) + (magit-insert-unstaged-changes + (if staged "Unstaged changes:" "Changes:")) + (magit-insert-staged-changes staged no-commit)) + (magit-insert-unpushed-commits remote branch) + (run-hooks 'magit-refresh-status-hook))))) (defun magit-init (dir) "Initialize git repository in the DIR directory." @@ -2634,7 +2669,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. @@ -2650,7 +2685,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')." @@ -2685,7 +2720,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)))) @@ -2719,118 +2754,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 @@ -2848,7 +2785,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')." @@ -2857,7 +2794,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) @@ -2878,7 +2815,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 @@ -2921,7 +2858,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 @@ -2991,7 +2928,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 @@ -3003,7 +2940,7 @@ update it." (remote (magit-run-git-async "fetch" remote)) (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"))) @@ -3042,7 +2979,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"))) @@ -3351,7 +3288,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 @@ -3360,7 +3297,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: ") @@ -3389,12 +3326,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. @@ -3405,7 +3342,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) @@ -3435,50 +3372,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 @@ -3620,7 +3531,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")) @@ -3659,7 +3570,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") @@ -3690,7 +3601,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)) @@ -3700,7 +3611,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")) @@ -3720,18 +3631,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))))) + (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) +(magit-define-command diff-working-tree (rev) (interactive (list (magit-read-rev "Diff with" (magit-default-rev)))) (magit-diff (or rev "HEAD"))) @@ -3919,8 +3830,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 ())))) @@ -4238,6 +4147,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 From 04984e5265fccc65822500b4daeebef66b4a7edc Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Tue, 29 Jun 2010 22:08:14 +0100 Subject: [PATCH 15/39] Checkout works again in the branch view. --- magit.el | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/magit.el b/magit.el index 884a4ecb..311633ab 100644 --- a/magit.el +++ b/magit.el @@ -4074,12 +4074,7 @@ Return values: (defun magit--branch-name-from-line (line) "Extract the branch name from line LINE of 'git branch' output." - (let ((branch (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))) + (get-text-property 0 'branch-name line)) (defun magit--branch-name-at-point () "Get the branch name in the line at point." @@ -4093,6 +4088,12 @@ Return values: (save-excursion (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) "Remove the branch in the line at point. With prefix force the removal even it it hasn't been merged." @@ -4100,7 +4101,9 @@ With prefix force the removal even it it hasn't been merged." (let ((args (list "branch" (if force "-D" "-d") (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 (apply 'magit-run-git (remq nil args)) (magit-show-branches)))) From b65979510e9ab71123ec87b022a9aadd30847105 Mon Sep 17 00:00:00 2001 From: Alan Falloon Date: Wed, 28 Apr 2010 10:10:00 +0800 Subject: [PATCH 16/39] Show branch name in "Remote:" section when tracking local branch When the current branch is tracking a local branch (the remote is ".") show the local upstream branch in the "Remote:" section. --- magit.el | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/magit.el b/magit.el index 311633ab..2f8e8a4a 100644 --- a/magit.el +++ b/magit.el @@ -2474,10 +2474,14 @@ insert a line to tell how to insert more of them" ;;; Status -(defun magit-remote-string (remote svn-info) - (if remote - (concat remote " " (magit-get "remote" remote "url")) - (when svn-info +(defun magit-remote-string (remote remote-branch svn-info) + (cond + ((string= "." remote) + (format "branch %s" + (propertize remote-branch 'face 'magit-branch))) + (remote + (concat remote " " (magit-get "remote" remote "url"))) + (svn-info (concat (cdr (assoc 'url svn-info)) " @ " (cdr (assoc 'revision svn-info)))))) @@ -2489,7 +2493,7 @@ insert a line to tell how to insert more of them" (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 svn-info)) + (remote-string (magit-remote-string remote remote-branch svn-info)) (head (magit-git-string "log" "--max-count=1" "--abbrev-commit" "--pretty=oneline")) (no-commit (not head))) From 809a5cb81c465a5deb6c109eca53d605ce49a109 Mon Sep 17 00:00:00 2001 From: Alan Falloon Date: Wed, 28 Apr 2010 09:35:50 +0800 Subject: [PATCH 17/39] Use just the branch name for unpushed/unpulled when the remote is "." When the remote is "." it signifies that the current branch is tracking another local branch, not a branch in one of the remotes. So, in that case, use just the branch name as the upstream branch instead of the "remote/branch" naming scheme. --- magit.el | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/magit.el b/magit.el index 2f8e8a4a..548b610d 100644 --- a/magit.el +++ b/magit.el @@ -2441,17 +2441,23 @@ insert a line to tell how to insert more of them" (or magit-marked-commit (error "No commit marked"))) +(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/%s" remote branch))) + (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/%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 From 42a70d14cc5ac517bce2d810fc30b26ba2b7107d Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Tue, 29 Jun 2010 22:53:09 +0100 Subject: [PATCH 18/39] RET checks out a branch in the branch view. --- magit.el | 1 + 1 file changed, 1 insertion(+) diff --git a/magit.el b/magit.el index 548b610d..e80253d2 100644 --- a/magit.el +++ b/magit.el @@ -4061,6 +4061,7 @@ Return values: (defvar magit-show-branches-mode-map (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 "k") 'magit-remove-branch) (define-key map (kbd "m") 'magit-branches-window-manual-merge) From fd6f6d5ea7b209f8968dfcd999a20f84e6e63edc Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Tue, 29 Jun 2010 22:55:40 +0100 Subject: [PATCH 19/39] Manual entry for new branch mode binding. --- magit.texi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/magit.texi b/magit.texi index 23c8d528..fbbb9eae 100644 --- a/magit.texi +++ b/magit.texi @@ -500,7 +500,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 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 the transcript of the most recent command. From dc49fde45e598812039623d77bf67410aea0e61e Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Tue, 29 Jun 2010 23:09:05 +0100 Subject: [PATCH 20/39] Replace slashes in tracking branch name suggestion. --- magit.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/magit.el b/magit.el index e80253d2..02ab7340 100644 --- a/magit.el +++ b/magit.el @@ -2653,7 +2653,9 @@ With prefix argument, add remaining untracked files as well. tracking brach name suggesting a sensible default." (when (yes-or-no-p (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) nil nil From bdba20d5ccc645b01401e6876005f86a0ca809ae Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Wed, 30 Jun 2010 15:55:01 +0100 Subject: [PATCH 21/39] Fixed the ref/rev typo. --- magit.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/magit.el b/magit.el index 163ac635..c38dd2ed 100644 --- a/magit.el +++ b/magit.el @@ -550,7 +550,7 @@ out revs involving HEAD." modifier)) ;; If rev-parse doesn't give us what we want, just use the SHA. (when (or (null name) (string-match-p "\\" name)) - (setq name (magit-rev-parse ref))))) + (setq name (magit-rev-parse rev))))) (setq rev (or name rev)) (when (string-match "^\\(?:tags\\|remotes\\)/\\(.*\\)" rev) (let ((plain-name (match-string 1 rev))) From d4dd5c5da0f228c309084c31e3e38ec8207b2691 Mon Sep 17 00:00:00 2001 From: Leo Date: Thu, 1 Jul 2010 09:52:00 +0100 Subject: [PATCH 22/39] Don't run magit-log-edit-mode-hook twice. --- magit.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/magit.el b/magit.el index 163ac635..996314fa 100644 --- a/magit.el +++ b/magit.el @@ -3160,8 +3160,7 @@ Prefix arg means justify as well." (define-derived-mode magit-log-edit-mode text-mode "Magit Log Edit" (set (make-local-variable 'fill-paragraph-function) - 'magit-log-fill-paragraph) - (run-mode-hooks 'magit-log-edit-mode-hook)) + 'magit-log-fill-paragraph)) (defun magit-log-edit-cleanup () (save-excursion From 997ecb4e104a75666e0f41cdadbf26d9682db784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Sat, 3 Jul 2010 00:31:48 +0800 Subject: [PATCH 23/39] magit-remote-ref-format: Improved documentation --- magit.el | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/magit.el b/magit.el index 5c6c3af1..f62137cf 100644 --- a/magit.el +++ b/magit.el @@ -153,9 +153,15 @@ after a confirmation." (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\"." +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))) From 82883d1de353c06fc07f412fe5cac0b8321af837 Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Mon, 5 Jul 2010 23:32:29 +0100 Subject: [PATCH 24/39] Removed old insert functions. --- magit.el | 41 ++++++++--------------------------------- 1 file changed, 8 insertions(+), 33 deletions(-) diff --git a/magit.el b/magit.el index b7b7af50..83b357dc 100644 --- a/magit.el +++ b/magit.el @@ -2521,43 +2521,19 @@ insert a line to tell how to insert more of them" (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" + "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 "HEAD..%s" + "Unpushed commits:" 'magit-wash-log + "log" "--pretty=format:* %H %s" + (format "HEAD..%s" (magit-remote-branch-name 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/%s" 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/%s..HEAD" 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) "Guess the remote branch name that LOCAL-BRANCH is tracking." (let ((merge (magit-get "branch" local-branch "merge"))) @@ -2592,11 +2568,11 @@ insert a line to tell how to insert more of them" (no-commit (not head))) (when remote-string (insert "Remote: " remote-string "\n")) - (insert (format "Local: %s %s\n" + (insert (format "Local: %s %s\n" (propertize (or branch "(detached)") 'face 'magit-branch) (abbreviate-file-name default-directory))) - (insert (format "Head: %s\n" + (insert (format "Head: %s\n" (if no-commit "nothing commited (yet)" head))) (let ((merge-heads (magit-file-lines ".git/MERGE_HEAD"))) (if merge-heads @@ -3027,7 +3003,6 @@ 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")))) (magit-define-command pull () From e58b3c379ce2f57dc52c66f803c413eb2ad10723 Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Mon, 5 Jul 2010 23:53:22 +0100 Subject: [PATCH 25/39] Added `magit-remote-branch-name'. Fixed unpushed args. --- magit.el | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/magit.el b/magit.el index 83b357dc..acc2af34 100644 --- a/magit.el +++ b/magit.el @@ -2518,6 +2518,12 @@ insert a line to tell how to insert more of them" (or magit-marked-commit (error "No commit marked"))) +(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 @@ -2531,7 +2537,7 @@ insert a line to tell how to insert more of them" (magit-git-section 'unpushed "Unpushed commits:" 'magit-wash-log "log" "--pretty=format:* %H %s" - (format "HEAD..%s" + (format "%s..HEAD" (magit-remote-branch-name remote branch))))) (defun magit-remote-branch-for (local-branch) From 67af1eead8438177961da306ba5bacacc3068e3c Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Mon, 5 Jul 2010 23:54:23 +0100 Subject: [PATCH 26/39] Stop `magit-remote-string' expecting the svn-info cache. --- magit.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/magit.el b/magit.el index acc2af34..e634ae7a 100644 --- a/magit.el +++ b/magit.el @@ -2551,7 +2551,7 @@ insert a line to tell how to insert more of them" (defvar magit-remote-string-hook nil) -(defun magit-remote-string (remote remote-branch svn-info) +(defun magit-remote-string (remote remote-branch) (cond ((string= "." remote) (format "branch %s" From f569ff83597fb805d3bf9562dbd9fca7c54fd049 Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Tue, 6 Jul 2010 00:02:51 +0100 Subject: [PATCH 27/39] Fix `magit-refresh-status'. --- magit.el | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/magit.el b/magit.el index e634ae7a..c6ae0154 100644 --- a/magit.el +++ b/magit.el @@ -2567,18 +2567,17 @@ insert a line to tell how to insert more of them" (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))) (when remote-string (insert "Remote: " remote-string "\n")) - (insert (format "Local: %s %s\n" + (insert (format "Local: %s %s\n" (propertize (or branch "(detached)") 'face 'magit-branch) (abbreviate-file-name default-directory))) - (insert (format "Head: %s\n" + (insert (format "Head: %s\n" (if no-commit "nothing commited (yet)" head))) (let ((merge-heads (magit-file-lines ".git/MERGE_HEAD"))) (if merge-heads @@ -2593,17 +2592,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)) + (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 staged no-commit))) - (when remote - (magit-insert-unpushed-commits remote remote-branch)) + (magit-insert-staged-changes staged no-commit)) + (magit-insert-unpushed-commits remote branch) (run-hooks 'magit-refresh-status-hook))))) (defun magit-init (dir) From 9e457184916fc49878dcb28dbe9b94a042ee4a32 Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Tue, 6 Jul 2010 00:07:37 +0100 Subject: [PATCH 28/39] Formatting. --- magit.el | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/magit.el b/magit.el index c6ae0154..6f71e917 100644 --- a/magit.el +++ b/magit.el @@ -2557,7 +2557,13 @@ insert a line to tell how to insert more of them" (format "branch %s" (propertize remote-branch 'face 'magit-branch))) (remote - (concat remote " " (magit-get "remote" remote "url"))) + (concat + (propertize remote-branch 'face 'magit-branch) + " @ " + remote + " (" + (magit-get "remote" remote "url") + ")")) (t (run-hook-with-args-until-success 'magit-remote-string-hook)))) @@ -2573,11 +2579,11 @@ insert a line to tell how to insert more of them" (no-commit (not head))) (when remote-string (insert "Remote: " remote-string "\n")) - (insert (format "Local: %s %s\n" + (insert (format "Local: %s %s\n" (propertize (or branch "(detached)") 'face 'magit-branch) (abbreviate-file-name default-directory))) - (insert (format "Head: %s\n" + (insert (format "Head: %s\n" (if no-commit "nothing commited (yet)" head))) (let ((merge-heads (magit-file-lines ".git/MERGE_HEAD"))) (if merge-heads From 6599b6ac579146553d681a5f37e323decf085973 Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Tue, 6 Jul 2010 00:10:50 +0100 Subject: [PATCH 29/39] Use remote branch for unpushed ref. --- magit.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/magit.el b/magit.el index 6f71e917..ce31ad63 100644 --- a/magit.el +++ b/magit.el @@ -2606,7 +2606,7 @@ insert a line to tell how to insert more of them" (magit-insert-unstaged-changes (if staged "Unstaged changes:" "Changes:")) (magit-insert-staged-changes staged no-commit)) - (magit-insert-unpushed-commits remote branch) + (magit-insert-unpushed-commits remote remote-branch) (run-hooks 'magit-refresh-status-hook))))) (defun magit-init (dir) From bf14e965baefe66aa217f19146af81fa054ad036 Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Tue, 6 Jul 2010 00:19:23 +0100 Subject: [PATCH 30/39] Actual branch name in remote string. --- magit.el | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/magit.el b/magit.el index f62137cf..051c2924 100644 --- a/magit.el +++ b/magit.el @@ -2507,14 +2507,20 @@ insert a line to tell how to insert more of them" (defun magit-remote-string (remote remote-branch svn-info) (cond ((string= "." remote) - (format "branch %s" - (propertize remote-branch 'face 'magit-branch))) + (format "branch %s" + (propertize remote-branch 'face 'magit-branch))) (remote - (concat remote " " (magit-get "remote" remote "url"))) + (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 (cdr (assoc 'url svn-info)) + " @ " + (cdr (assoc 'revision svn-info)))))) (defun magit-refresh-status () (magit-create-buffer-sections From fd2fd4725c28f8377890c5c61ba403e171bfc734 Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Tue, 6 Jul 2010 11:01:12 +0100 Subject: [PATCH 31/39] Make git svn fetch an explicit command rather than overriding remote-fetch. --- magit-svn.el | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/magit-svn.el b/magit-svn.el index 127bb8a1..5aab5bd3 100644 --- a/magit-svn.el +++ b/magit-svn.el @@ -151,33 +151,32 @@ If USE-CACHE is non nil, use the cached information." (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-find-rev))) + (,(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-commands - '((remote-update . magit-svn-remote-update))) - (defvar magit-svn-extension (make-magit-extension :keys magit-svn-extension-keys :menu magit-svn-extension-menu :insert magit-svn-extension-inserters - :commands magit-svn-extension-commands :remote-string 'magit-svn-remote-string)) (magit-install-extension magit-svn-extension) From 64756e9940592f134a829da63de53764fb21ab69 Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Tue, 6 Jul 2010 11:03:18 +0100 Subject: [PATCH 32/39] Update manual with regards to the svn change. --- magit.texi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/magit.texi b/magit.texi index fbbb9eae..6c201330 100644 --- a/magit.texi +++ b/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 From 3153f777d12beb67b360815ab3b50f9825e93a9e Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Sat, 10 Jul 2010 11:39:50 +0100 Subject: [PATCH 33/39] Add magit-wanderlust.el. --- magit-wanderlust.el | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 magit-wanderlust.el diff --git a/magit-wanderlust.el b/magit-wanderlust.el new file mode 100644 index 00000000..bf140448 --- /dev/null +++ b/magit-wanderlust.el @@ -0,0 +1,18 @@ +;;; magit-wanderlust.el --- wanderlust extension for Magit + +(require 'magit) + +(defun magit-wl-pipe-to-am () + "Ask the user for a project in which to apply (via am) the +current email in wl." + (interactive) + "Pipe a wanderlust message into git am." + (let* ((proj (funcall magit-completing-read + "Apply to project: " + (magit-list-projects) + nil t nil nil))) + (wl-summary-pipe-message-subr + nil (format "cd '%s' && git am" proj)))) + +(provide 'magit-wanderlust) +;;; magit-wanderlust.el ends here From b3beac42cb82a0f33a99b8bd8da00734857b6e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Vanicat?= Date: Fri, 9 Jul 2010 11:10:50 +0200 Subject: [PATCH 34/39] Handle 7 and 8 char small sha Otherwise this lead to an error in branch view mode. --- magit.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/magit.el b/magit.el index 051c2924..5d5d16b7 100644 --- a/magit.el +++ b/magit.el @@ -4175,7 +4175,7 @@ With prefix force the removal even it it hasn't been merged." "\\(.+?\\) +" ; branch name "\\(?:" - "\\([0-9a-fA-F]\\{7\\}\\) " ; sha1 + "\\([0-9a-fA-F]\\{7,8\\}\\) " ; sha1 "\\|\\(-> \\)" ; or the pointer to a ref "\\)" From 1a9ae85faaa3bb98954a869b4204eb3d3cfef265 Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Sat, 10 Jul 2010 11:41:12 +0100 Subject: [PATCH 35/39] Formatting. --- magit.el | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/magit.el b/magit.el index 5d5d16b7..847b5625 100644 --- a/magit.el +++ b/magit.el @@ -4171,15 +4171,15 @@ With prefix force the removal even it it hasn't been merged." (defun magit--branch-view-details (branch-line) "Extract details from branch -va output." (string-match (concat - "^\\(\\*? \\{1,2\\}\\)" ; current branch marker (maybe) - "\\(.+?\\) +" ; branch name + "^\\(\\*? \\{1,2\\}\\)" ; current branch marker (maybe) + "\\(.+?\\) +" ; branch name "\\(?:" - "\\([0-9a-fA-F]\\{7,8\\}\\) " ; sha1 - "\\|\\(-> \\)" ; or the pointer to a ref + "\\([0-9a-fA-F]\\{7,8\\}\\) " ; sha1 + "\\|\\(-> \\)" ; or the pointer to a ref "\\)" - "\\(.+\\)" ; message or ref + "\\(.+\\)" ; message or ref ) branch-line) (let ((res (list (cons 'current (match-string 1 branch-line)) From 8be54f67577478ce05cf68a44a377cab893e9ea0 Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Sat, 10 Jul 2010 12:41:05 +0100 Subject: [PATCH 36/39] Release 0.8.2. --- bin/mk_rel.bash | 22 ++++++++++++++++++++++ configure.ac | 2 +- magit.el | 2 +- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/bin/mk_rel.bash b/bin/mk_rel.bash index 3b206cc3..41104a90 100755 --- a/bin/mk_rel.bash +++ b/bin/mk_rel.bash @@ -2,6 +2,14 @@ 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="${1}" @@ -20,6 +28,20 @@ fi # grab that 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 [ -f Makefile ] && make distclean diff --git a/configure.ac b/configure.ac index 53eea1d8..6aeb0203 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(magit, 0.8.1) +AC_INIT(magit, 0.8.2) AC_CONFIG_SRCDIR([magit.el]) AM_INIT_AUTOMAKE([1.10]) diff --git a/magit.el b/magit.el index 847b5625..315e732a 100644 --- a/magit.el +++ b/magit.el @@ -28,7 +28,7 @@ ;; Author: Marius Vollmer ;; Maintainer: Phil Jackson -;; Version: 0.8.1 +;; Version: 0.8.2 ;; Keywords: tools ;; From 07dbd674950cb8933f0cd71431bb03035db6f0f3 Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Sun, 11 Jul 2010 18:53:49 +0100 Subject: [PATCH 37/39] Removed wanderlust again. --- magit-wanderlust.el | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 magit-wanderlust.el diff --git a/magit-wanderlust.el b/magit-wanderlust.el deleted file mode 100644 index bf140448..00000000 --- a/magit-wanderlust.el +++ /dev/null @@ -1,18 +0,0 @@ -;;; magit-wanderlust.el --- wanderlust extension for Magit - -(require 'magit) - -(defun magit-wl-pipe-to-am () - "Ask the user for a project in which to apply (via am) the -current email in wl." - (interactive) - "Pipe a wanderlust message into git am." - (let* ((proj (funcall magit-completing-read - "Apply to project: " - (magit-list-projects) - nil t nil nil))) - (wl-summary-pipe-message-subr - nil (format "cd '%s' && git am" proj)))) - -(provide 'magit-wanderlust) -;;; magit-wanderlust.el ends here From 761d6ad09bfce0d354c8fe958f5fc1b0fdde0a9a Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Sun, 11 Jul 2010 18:54:03 +0100 Subject: [PATCH 38/39] Build system updated. --- Makefile.am | 9 +++++---- magit.el | 7 ++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Makefile.am b/Makefile.am index 0fd1afc0..149d1899 100644 --- a/Makefile.am +++ b/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 diff --git a/magit.el b/magit.el index efd9655c..e0217593 100644 --- a/magit.el +++ b/magit.el @@ -359,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) @@ -1274,9 +1278,6 @@ TITLE is the displayed title of the section." `((magit-prefix-p ',prefix ,context) ,@body)))) -(defun magit-dynamic-clauses-helper (clauses context) - `(((magit-dynamic-clauses ,clauses ,context) t))) - (defun magit-dynamic-clauses (clauses context) (let* ((c (car clauses)) (prefix (reverse (car c))) From 6a5fbcee8da073884a84cc1ee1d59452cef79c06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Sun, 25 Jul 2010 15:06:48 +0000 Subject: [PATCH 39/39] magit-stash: Prefix user-supplied description with -- MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes a bug in magit-stash that prevented magit from creating stashes that began with "-", since git-stash parse them as options. Signed-off-by: Ævar Arnfjörð Bjarmason --- magit.el | 1 + 1 file changed, 1 insertion(+) diff --git a/magit.el b/magit.el index 57bd83fa..bd706a5b 100644 --- a/magit.el +++ b/magit.el @@ -3412,6 +3412,7 @@ With prefix argument, changes in staging area are kept. (apply 'magit-run-git `("stash" "save" ,@(when current-prefix-arg '("--keep-index")) + "--" ,description))) (magit-define-command stash-snapshot ()