Browse files

Support for magit-repo-dirs and nice completion based on it.

Thanks to Travis B. Hartwell for the initial implementation!
  • Loading branch information...
1 parent 31b8be9 commit ea6105fbbf390c02290a47111237c51115093923 @mvollmer mvollmer committed Jul 27, 2009
Showing with 97 additions and 8 deletions.
  1. +7 −0 NEWS
  2. +69 −7 magit.el
  3. +21 −1 magit.texi
@@ -1,5 +1,12 @@
Changes in magit 0.8:
+* By setting magit-repo-dirs, you can get better repo completion.
+ Magit will offer all subdirectories (upto magit-repo-dirs level
+ deep) of the listed directories when magit-status asks for a
+ directory to work on.
+ You can get the old behavior with a double prefix to magit-status.
* Hitting 'c' or 'C' while resolving a conflict in the middle of a
rebase will offer to continue the rebase instead of trying to commit
your changes.
@@ -68,6 +68,17 @@
:group 'magit
:type '(repeat string))
+(defcustom magit-repo-dirs nil
+ "Directories containing Git repositories.
+Magit will look into these directories for Git repositories and offers them as choices for magit-status."
+ :group 'magit
+ :type '(repeat string))
+(defcustom magit-repo-dirs-depth 3
+ "When looking for Git repositors below the directories in magit-repo-dirs, Magit will only descend this many levels deep."
+ :group 'magit
+ :type 'integer)
(defcustom magit-save-some-buffers t
"Non-nil means that \\[magit-status] will save modified buffers before running.
Setting this to t will ask which buffers to save, setting it to 'dontask will
@@ -272,6 +283,51 @@ Many Magit faces inherit from this one by default."
(magit-git-string "config" (magit-concat-with-delim "." keys) val)
(magit-git-string "config" "--unset" (magit-concat-with-delim "." keys))))
+(defun magit-remove-conflicts (alist)
+ (let ((dict (make-hash-table :test 'equal))
+ (result nil))
+ (dolist (a alist)
+ (puthash (car a) (cons (cdr a) (gethash (car a) dict))
+ dict))
+ (maphash (lambda (key value)
+ (if (= (length value) 1)
+ (push (cons key (car value)) result)
+ (let ((sub (magit-remove-conflicts
+ (mapcar (lambda (entry)
+ (let ((dir (directory-file-name
+ (subseq entry 0 (- (length key))))))
+ (cons (concat (file-name-nondirectory dir) "/" key)
+ entry)))
+ value))))
+ (setq result (append result sub)))))
+ dict)
+ result))
+(defun magit-git-repo-p (dir)
+ (file-exists-p (expand-file-name ".git" dir)))
+(defun magit-list-repos* (dir level)
+ (if (magit-git-repo-p dir)
+ (list dir)
+ (apply #'append
+ (mapcar (lambda (entry)
+ (unless (or (string= (substring entry -3) "/..")
+ (string= (substring entry -2) "/."))
+ (magit-list-repos* entry (+ level 1))))
+ (and (file-directory-p dir)
+ (< level magit-repo-dirs-depth)
+ (directory-files dir t nil t))))))
+(defun magit-list-repos (dirs)
+ (magit-remove-conflicts
+ (apply #'append
+ (mapcar (lambda (dir)
+ (mapcar #'(lambda (repo)
+ (cons (file-name-nondirectory repo)
+ repo))
+ (magit-list-repos* dir 0)))
+ dirs))))
(defun magit-get-top-dir (cwd)
(let ((cwd (expand-file-name cwd)))
(and (file-directory-p cwd)
@@ -295,11 +351,17 @@ Many Magit faces inherit from this one by default."
(defun magit-ref-exists-p (ref)
(= (magit-git-exit-code "show-ref" "--verify" ref) 0))
-(defun magit-read-top-dir ()
- (file-name-as-directory
- (read-directory-name "Git repository: "
- (or (magit-get-top-dir default-directory)
- default-directory))))
+(defun magit-read-top-dir (rawp)
+ (if (and (not rawp) magit-repo-dirs)
+ (let* ((repos (magit-list-repos magit-repo-dirs))
+ (reply (completing-read "Git repository: "
+ (magit-list-repos magit-repo-dirs))))
+ (file-name-as-directory
+ (cdr (assoc reply repos))))
+ (file-name-as-directory
+ (read-directory-name "Git repository: "
+ (or (magit-get-top-dir default-directory)
+ default-directory)))))
(defun magit-name-rev (rev)
(and rev
@@ -1927,7 +1989,8 @@ in log buffer."
(defun magit-status (dir)
(interactive (list (or (and (not current-prefix-arg)
(magit-get-top-dir default-directory))
- (magit-read-top-dir))))
+ (magit-read-top-dir (and (listp current-prefix-arg)
+ (> (car current-prefix-arg) 4))))))
(if magit-save-some-buffers
(save-some-buffers (eq magit-save-some-buffers 'dontask)))
(let ((topdir (magit-get-top-dir dir)))
@@ -1946,7 +2009,6 @@ in log buffer."
(switch-to-buffer buf)
(magit-mode-init topdir 'status #'magit-refresh-status)))))
;;; Staging and Unstaging
(defun magit-stage-item ()
@@ -166,8 +166,28 @@ will switch to the status buffer of that repository. Otherwise, it
will prompt for a directory. With a prefix argument, it will always
+You can set @code{magit-repo-dirs} to customize how
+@code{magit-status} asks for the repository to work on. When
+@code{magit-repo-dirs} is nil, @code{magit-status} will simply ask for
+a directory.
If you specify a directory that is not a Git repository, @kbd{M-x
-magit-status} will ask whether to create one.
+magit-status} will offer to initialize it as one.
+When @code{magit-repo-dirs} is not nil, it is treated as a list of
+directory names, and @code{magit-status} will find all Git
+repositories in those directories and offer them for completion.
+(Magit will only look @code{magit-repo-dirs-depth} levels deep,
+With two prefix arguments, @code{magit-status} will always prompt for
+a raw directory.
+Thus, you would normally set @code{magit-repo-dirs} to the places
+where you keep most of your Git repositories and switch between them
+with @kbd{C-u M-x magit-status}. If you want to go to a repository
+outside of your normal working areas, or if you want to create a new
+repository, you would use @kbd{C-u C-u M-x magit-status}.
You need to explicitly refresh the status buffer when you have made
changes to the repository from outside of Emacs. You can type @kbd{g}

0 comments on commit ea6105f

Please sign in to comment.