1 ;;; Magit -- control Git from Emacs.
3 ;; Copyright (C) 2008 Marius Vollmer
4 ;; Copyright (C) 2008 Linh Dang
6 ;; Magit is free software; you can redistribute it and/or modify it
7 ;; under the terms of the GNU General Public License as published by
8 ;; the Free Software Foundation; either version 3, or (at your option)
11 ;; Magit is distributed in the hope that it will be useful, but WITHOUT
12 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 ;; License for more details.
16 ;; You should have received a copy of the GNU General Public License
17 ;; along with Magit. If not, see <http://www.gnu.org/licenses/>.
21 ;; Invoking the magit-status function will show a buffer with the
22 ;; status of the current git repository and its working tree. That
23 ;; buffer offers key bindings for manipulating the status in simple
26 ;; The status buffer mainly shows the difference between the working
27 ;; tree and the index, and the difference between the index and the
28 ;; current HEAD. You can add individual hunks from the working tree
29 ;; to the index, and you can commit the index.
31 ;; See the Magit User Manual for more information.
36 ;; - Amending commits other than HEAD.
37 ;; - Visiting from staged hunks doesn't always work since the line
38 ;; numbers don't refer to the working tree. Fix that somehow.
39 ;; - Get current defun from removed lines in a diff
40 ;; - Equivalent of git-wtf, http://git-wt-commit.rubyforge.org/#git-wtf
41 ;; - 'Subsetting', only looking at a subset of all files.
50 "Controlling Git from Emacs."
54 (defcustom magit-collapse-threshold
50
55 "Sections with more lines than this are collapsed automatically."
61 "Face for generic header lines.
63 Many Magit faces inherit from this one by default."
66 (defface magit-section-title
67 '((t :weight bold
:inherit magit-header
))
68 "Face for section titles."
72 '((t :weight bold
:inherit magit-header
))
73 "Face for the current branch."
76 (defface magit-diff-file-header
77 '((t :inherit magit-header
))
78 "Face for diff file header lines."
81 (defface magit-diff-hunk-header
82 '((t :slant italic
:inherit magit-header
))
83 "Face for diff hunk header lines."
86 (defface magit-diff-add
87 '((((class color
) (background light
))
89 (((class color
) (background dark
))
91 "Face for lines in a diff that have been added."
94 (defface magit-diff-none
96 "Face for lines in a diff that are unchanged."
99 (defface magit-diff-del
100 '((((class color
) (background light
))
102 (((class color
) (background dark
))
103 :foreground
"OrangeRed"))
104 "Face for lines in a diff that have been deleted."
107 (defface magit-item-highlight
108 '((((class color
) (background light
))
109 :background
"gray95")
110 (((class color
) (background dark
))
111 :background
"dim gray"))
112 "Face for highlighting the current item."
115 (defface magit-log-tag-label
116 '((((class color
) (background light
))
117 :background
"LightGoldenRod")
118 (((class color
) (background dark
))
119 :background
"DarkGoldenRod"))
120 "Face for git tag labels shown in log buffer."
123 (defface magit-log-head-label
124 '((((class color
) (background light
))
125 :background
"spring green")
126 (((class color
) (background dark
))
127 :background
"DarkGreen"))
128 "Face for branch head labels shown in log buffer."
133 (defmacro magit-with-refresh
(&rest body
)
135 `(magit-refresh-wrapper (lambda () ,@body
)))
139 (defun magit-use-region-p ()
140 (if (fboundp 'use-region-p
)
142 (and transient-mark-mode mark-active
)))
144 (defun magit-goto-line (line)
145 ;; Like goto-line but doesn't set the mark.
149 (forward-line (1- line
))))
151 (defun magit-shell (cmd &rest args
)
152 (let ((str (shell-command-to-string
153 (apply 'format cmd
(mapcar #'magit-escape-for-shell args
)))))
156 (if (equal (elt str
(- (length str
) 1)) ?
\n)
157 (substring str
0 (- (length str
) 1))
160 (defun magit-shell-lines (cmd &rest args
)
161 (let ((str (shell-command-to-string
162 (apply 'format cmd
(mapcar #'magit-escape-for-shell args
)))))
165 (let ((lines (nreverse (split-string str
"\n"))))
166 (if (string= (car lines
) "")
167 (setq lines
(cdr lines
)))
170 (defun magit-shell-exit-code (cmd &rest args
)
171 (call-process shell-file-name nil nil nil
173 (apply 'format cmd
(mapcar #'magit-escape-for-shell args
))))
175 (defun magit-file-lines (file)
176 (if (file-exists-p file
)
177 (magit-shell-lines "cat %s" file
)
180 (defun magit-concat-with-delim (delim seqs
)
186 (concat (car seqs
) delim
(magit-concat-with-delim delim
(cdr seqs
))))))
188 (defun magit-get (&rest keys
)
189 (magit-shell "git config %s" (magit-concat-with-delim "." keys
)))
191 (defun magit-set (val &rest keys
)
193 (magit-shell "git config %s %s" (magit-concat-with-delim "." keys
) val
)
194 (magit-shell "git config --unset %s" (magit-concat-with-delim "." keys
))))
196 (defun magit-get-top-dir (cwd)
197 (let* ((cwd (expand-file-name cwd
))
198 (magit-dir (magit-shell
199 "cd %s && git rev-parse --git-dir 2>/dev/null"
202 (file-name-as-directory (or (file-name-directory magit-dir
) cwd
))
205 (defun magit-get-ref (ref)
206 (magit-shell "git symbolic-ref -q %s" ref
))
208 (defun magit-get-current-branch ()
209 (let* ((head (magit-get-ref "HEAD"))
210 (pos (and head
(string-match "^refs/heads/" head
))))
215 (defun magit-read-top-dir ()
217 (read-directory-name "Git repository: "
218 (magit-get-top-dir default-directory
))))
220 (defun magit-name-rev (rev)
222 (let ((name (magit-shell "git name-rev --name-only %s" rev
)))
223 (if (or (not name
) (string= name
"undefined"))
227 (defun magit-put-line-property (prop val
)
228 (put-text-property (line-beginning-position) (line-beginning-position 2)
231 (defun magit-escape-for-shell (str)
232 (concat "'" (replace-regexp-in-string "'" "'\\''" str
) "'"))
234 (defun magit-format-commit (commit format
)
235 (magit-shell "git log --max-count=1 --pretty=format:%s %s"
239 (defun magit-current-line ()
240 (buffer-substring-no-properties (line-beginning-position)
241 (line-end-position)))
243 (defun magit-insert-region (beg end buf
)
244 (let ((text (buffer-substring-no-properties beg end
)))
245 (with-current-buffer buf
248 (defun magit-insert-current-line (buf)
249 (let ((text (buffer-substring-no-properties
250 (line-beginning-position) (line-beginning-position 2))))
251 (with-current-buffer buf
254 (defun magit-file-uptodate-p (file)
255 (eq (magit-shell-exit-code "git diff --quiet -- %s" file
) 0))
257 (defun magit-anything-staged-p ()
258 (not (eq (magit-shell-exit-code "git diff --quiet --cached") 0)))
260 (defun magit-everything-clean-p ()
261 (and (not (magit-anything-staged-p))
262 (eq (magit-shell-exit-code "git diff --quiet") 0)))
264 (defun magit-commit-parents (commit)
265 (cdr (magit-shell-lines "git rev-list -1 --parents %s | tr ' ' '\n'"
268 ;; XXX - let the user choose the parent
270 (defun magit-choose-parent (commit op
)
271 (let* ((parents (magit-commit-parents commit
)))
272 (if (> (length parents
) 1)
273 (error "Can't %s merge commits." op
)
276 (defun magit-choose-parent-id (commit op
)
277 (let* ((parents (magit-commit-parents commit
)))
278 (if (> (length parents
) 1)
279 (error "Can't %s merge commits." op
)
282 ;;; Revisions and ranges
284 (defun magit-list-interesting-revisions ()
285 (append (magit-shell-lines "git branch -a | cut -c3-")
286 (magit-shell-lines "git tag")))
288 (defun magit-read-rev (prompt &optional def
)
289 (let* ((prompt (if def
290 (format "%s (default %s): " prompt def
)
291 (format "%s: " prompt
)))
292 (rev (completing-read prompt
(magit-list-interesting-revisions)
293 nil nil nil nil def
)))
298 (defun magit-read-rev-range (op &optional def-beg def-end
)
299 (if current-prefix-arg
300 (read-string (format "%s range: " op
))
301 (let ((beg (magit-read-rev (format "%s start" op
)
305 (let ((end (magit-read-rev (format "%s end" op
) def-end
)))
308 (defun magit-rev-to-git (rev)
310 (error "No revision specified"))
311 (if (string= rev
".")
312 (magit-marked-commit)
315 (defun magit-rev-range-to-git (range)
317 (error "No revision range specified"))
322 (magit-rev-to-git (car range
))
323 (magit-rev-to-git (cdr range
)))
324 (format "%s" (magit-rev-to-git (car range
))))))
326 (defun magit-rev-describe (rev)
328 (error "No revision specified"))
329 (if (string= rev
".")
331 (magit-name-rev rev
)))
333 (defun magit-rev-range-describe (range things
)
335 (error "No revision range specified"))
337 (format "%s in %s" things range
)
339 (format "%s from %s to %s" things
340 (magit-rev-describe (car range
))
341 (magit-rev-describe (cdr range
)))
342 (format "%s at %s" things
(magit-rev-describe (car range
))))))
344 (defun magit-default-rev ()
345 (magit-name-rev (magit-commit-at-point t
)))
349 ;; A buffer in magit-mode is organized into hierarchical sections.
350 ;; These sections are used for navigation and for hiding parts of the
353 ;; Most sections also represent the objects that Magit works with,
354 ;; such as files, diffs, hunks, commits, etc. The 'type' of a section
355 ;; identifies what kind of object it represents (if any), and the
356 ;; parent and grand-parent, etc provide the context.
358 (defstruct magit-section
359 parent title beginning end children hidden type info
)
361 (defvar magit-top-section nil
)
362 (make-variable-buffer-local 'magit-top-section
)
363 (put 'magit-top-section
'permanent-local t
)
365 (defvar magit-old-top-section nil
)
367 (defun magit-new-section (title &rest args
)
368 (let* ((s (apply #'make-magit-section
369 :parent magit-top-section
372 (old (and magit-old-top-section
373 (magit-find-section (magit-section-path s
)
374 magit-old-top-section
))))
375 (if magit-top-section
376 (setf (magit-section-children magit-top-section
)
377 (cons s
(magit-section-children magit-top-section
)))
378 (setq magit-top-section s
))
380 (setf (magit-section-hidden s
) (magit-section-hidden old
)))
383 (defun magit-cancel-section (section)
384 (delete-region (magit-section-beginning section
)
385 (magit-section-end section
))
386 (let ((parent (magit-section-parent section
)))
388 (setf (magit-section-children parent
)
389 (delq section
(magit-section-children parent
)))
390 (setq magit-top-section nil
))))
392 (defmacro magit-with-section
(title args
&rest body
)
395 `(let* ((,s
(magit-new-section ,title
,@(if (keywordp (car args
))
398 (magit-top-section ,s
))
399 (setf (magit-section-beginning ,s
) (point))
401 (setf (magit-section-end ,s
) (point))
402 (setf (magit-section-children ,s
)
403 (nreverse (magit-section-children ,s
)))
406 (defun magit-set-section-info (info &optional section
)
407 (setf (magit-section-info (or section magit-top-section
)) info
))
409 (defmacro magit-create-buffer-sections
(&rest body
)
411 `(let ((inhibit-read-only t
))
413 (let ((magit-old-top-section magit-top-section
))
414 (setq magit-top-section nil
)
416 (when (null magit-top-section
)
417 (magit-with-section 'top nil
418 (insert "(empty)\n")))
419 (magit-propertize-section magit-top-section
)
420 (magit-section-set-hidden magit-top-section
421 (magit-section-hidden magit-top-section
)))))
423 (defun magit-propertize-section (section)
424 (put-text-property (magit-section-beginning section
)
425 (magit-section-end section
)
426 'magit-section section
)
427 (dolist (s (magit-section-children section
))
428 (magit-propertize-section s
)))
430 (defun magit-find-section (path top
)
433 (let ((sec (find-if (lambda (s) (equal (car path
)
434 (magit-section-title s
)))
435 (magit-section-children top
))))
437 (magit-find-section (cdr path
) sec
)
440 (defun magit-section-path (section)
441 (if (not (magit-section-parent section
))
443 (append (magit-section-path (magit-section-parent section
))
444 (list (magit-section-title section
)))))
446 (defun magit-find-section-at (pos secs
)
448 (not (and (<= (magit-section-beginning (car secs
)) pos
)
449 (< pos
(magit-section-end (car secs
))))))
450 (setq secs
(cdr secs
)))
452 (or (magit-find-section-at pos
(magit-section-children (car secs
)))
456 (defun magit-find-section-after (pos secs
)
458 (not (> (magit-section-beginning (car secs
)) pos
)))
459 (setq secs
(cdr secs
)))
462 (defun magit-find-section-before (pos secs
)
465 (not (> (magit-section-beginning (car secs
)) pos
)))
466 (setq prev
(car secs
))
467 (setq secs
(cdr secs
)))
470 (defun magit-current-section ()
471 (or (get-text-property (point) 'magit-section
)
474 (defun magit-insert-section (type title washer threshold cmd
&rest args
)
475 (let* ((body-beg nil
)
477 (magit-with-section type nil
479 (insert (propertize title
'face
'magit-section-title
) "\n"))
480 (setq body-beg
(point))
481 (apply 'call-process cmd nil t nil args
)
484 (narrow-to-region body-beg
(point))
485 (goto-char (point-min))
487 (goto-char (point-max)))))))
488 (if (= body-beg
(point))
489 (magit-cancel-section section
)
492 (defun magit-next-section (section)
493 (let ((parent (magit-section-parent section
)))
495 (let ((next (cadr (memq section
496 (magit-section-children parent
)))))
498 (magit-next-section parent
))))))
500 (defun magit-goto-next-section ()
502 (let* ((section (magit-current-section))
503 (next (or (and (not (magit-section-hidden section
))
504 (magit-section-children section
)
505 (magit-find-section-after (point)
506 (magit-section-children
508 (magit-next-section section
))))
511 (goto-char (magit-section-beginning next
))
512 (if (memq magit-submode
'(log reflog
))
513 (magit-show-commit next
)))
514 (message "No next section"))))
516 (defun magit-prev-section (section)
517 (let ((parent (magit-section-parent section
)))
519 (let ((prev (cadr (memq section
520 (reverse (magit-section-children parent
))))))
522 (while (and (not (magit-section-hidden prev
))
523 (magit-section-children prev
))
524 (setq prev
(car (reverse (magit-section-children prev
)))))
529 (defun magit-goto-previous-section ()
531 (let ((section (magit-current-section)))
532 (cond ((= (point) (magit-section-beginning section
))
533 (let ((prev (magit-prev-section (magit-current-section))))
536 (if (memq magit-submode
'(log reflog
))
537 (magit-show-commit (or prev section
)))
538 (goto-char (magit-section-beginning prev
)))
539 (message "No previous section"))))
541 (let ((prev (magit-find-section-before (point)
542 (magit-section-children
544 (if (memq magit-submode
'(log reflog
))
545 (magit-show-commit (or prev section
)))
546 (goto-char (magit-section-beginning (or prev section
))))))))
548 (defun magit-goto-section (path)
549 (let ((sec (magit-find-section path magit-top-section
)))
551 (goto-char (magit-section-beginning sec
))
552 (message "No such section"))))
554 (defun magit-for-all-sections (func &optional top
)
555 (let ((section (or top magit-top-section
)))
557 (funcall func section
)
558 (dolist (c (magit-section-children section
))
559 (magit-for-all-sections func c
)))))
561 (defun magit-section-set-hidden (section hidden
)
562 (setf (magit-section-hidden section
) hidden
)
563 (let ((inhibit-read-only t
)
565 (goto-char (magit-section-beginning section
))
568 (end (magit-section-end section
)))
569 (put-text-property beg end
'invisible hidden
)
570 (put-text-property beg end
'rear-nonsticky t
))
572 (dolist (c (magit-section-children section
))
573 (magit-section-set-hidden c
(magit-section-hidden c
)))))
575 (defun magit-section-any-hidden (section)
576 (or (magit-section-hidden section
)
577 (some #'magit-section-any-hidden
(magit-section-children section
))))
579 (defun magit-section-collapse (section)
580 (dolist (c (magit-section-children section
))
581 (setf (magit-section-hidden c
) t
))
582 (magit-section-set-hidden section nil
))
584 (defun magit-section-expand (section)
585 (dolist (c (magit-section-children section
))
586 (setf (magit-section-hidden c
) nil
))
587 (magit-section-set-hidden section nil
))
589 (defun magit-section-expand-all-aux (section)
590 (dolist (c (magit-section-children section
))
591 (setf (magit-section-hidden c
) nil
)
592 (magit-section-expand-all-aux c
)))
594 (defun magit-section-expand-all (section)
595 (magit-section-expand-all-aux section
)
596 (magit-section-set-hidden section nil
))
598 (defun magit-section-hideshow (flag-or-func)
599 (let ((section (magit-current-section)))
600 (cond ((magit-section-parent section
)
601 (goto-char (magit-section-beginning section
))
602 (if (functionp flag-or-func
)
603 (funcall flag-or-func section
)
604 (magit-section-set-hidden section flag-or-func
))))))
606 (defun magit-show-section ()
608 (magit-section-hideshow nil
))
610 (defun magit-hide-section ()
612 (magit-section-hideshow t
))
614 (defun magit-collapse-section ()
616 (magit-section-hideshow #'magit-section-collapse
))
618 (defun magit-expand-section ()
620 (magit-section-hideshow #'magit-section-expand
))
622 (defun magit-toggle-section ()
624 (magit-section-hideshow
626 (magit-section-set-hidden s
(not (magit-section-hidden s
))))))
628 (defun magit-expand-collapse-section ()
630 (magit-section-hideshow
632 (cond ((magit-section-any-hidden s
)
633 (magit-section-expand-all s
))
635 (magit-section-collapse s
))))))
637 (defun magit-cycle-section ()
639 (magit-section-hideshow
641 (cond ((magit-section-hidden s
)
642 (magit-section-collapse s
))
643 ((notany #'magit-section-hidden
(magit-section-children s
))
644 (magit-section-set-hidden s t
))
646 (magit-section-expand s
))))))
648 (defmacro magit-define-section-jumper
(sym title
)
649 (let ((fun (intern (format "magit-jump-to-%s" sym
)))
650 (doc (format "Jump to section `%s'." title
)))
653 (magit-goto-section '(,sym
)))))
655 (defvar magit-highlight-overlay nil
)
657 (defvar magit-highlighted-section nil
)
659 (defun magit-highlight-section ()
660 (let ((section (magit-current-section)))
661 (when (not (eq section magit-highlighted-section
))
662 (setq magit-highlighted-section section
)
663 (if (not magit-highlight-overlay
)
664 (let ((ov (make-overlay 1 1)))
665 (overlay-put ov
'face
'magit-item-highlight
)
666 (setq magit-highlight-overlay ov
)))
667 (if (and section
(magit-section-type section
))
668 (move-overlay magit-highlight-overlay
669 (magit-section-beginning section
)
670 (magit-section-end section
)
672 (delete-overlay magit-highlight-overlay
)))))
674 (defun magit-section-context-type (section)
677 (let ((c (or (magit-section-type section
)
678 (if (symbolp (magit-section-title section
))
679 (magit-section-title section
)))))
681 (cons c
(magit-section-context-type
682 (magit-section-parent section
)))
685 (defun magit-prefix-p (prefix list
)
688 (if (eq (car prefix
) '*)
689 (or (magit-prefix-p (cdr prefix
) list
)
690 (and (not (null list
))
691 (magit-prefix-p prefix
(cdr list
))))
692 (and (not (null list
))
693 (eq (car prefix
) (car list
))
694 (magit-prefix-p (cdr prefix
) (cdr list
))))))
696 (defmacro magit-section-case
(head &rest clauses
)
698 (let ((section (car head
))
702 (opname (caddr head
)))
703 `(let* ((,section
(magit-current-section))
704 (,info
(magit-section-info ,section
))
705 (,type
(magit-section-type ,section
))
706 (,context
(magit-section-context-type ,section
)))
707 (cond ,@(mapcar (lambda (clause)
708 (let ((prefix (reverse (car clause
)))
710 `((magit-prefix-p ',prefix
,context
)
715 (error "Nothing to %s here." ,opname
))
717 (error "Can't %s a %s."
719 (or (get ,type
'magit-description
)
722 (defmacro magit-section-action
(head &rest clauses
)
725 (magit-section-case ,head
,@clauses
)))
727 (defun magit-wash-sequence (func)
728 (while (and (not (eobp))
733 (defun magit-set-mode-line-process (str)
734 (let ((pr (if str
(concat " " str
) "")))
736 (magit-for-all-buffers (lambda ()
737 (setq mode-line-process pr
))))))
739 (defun magit-process-indicator-from-command (cmd args
)
740 (cond ((or (null args
)
741 (not (equal cmd
"git")))
743 ((or (null (cdr args
))
744 (not (member (car args
) '("remote"))))
747 (concat (car args
) " " (cadr args
)))))
749 (defvar magit-process nil
)
750 (defvar magit-process-client-buffer nil
)
752 (defun magit-run* (cmd-and-args
753 &optional logline noerase noerror nowait input
)
754 (let ((cmd (car cmd-and-args
))
755 (args (cdr cmd-and-args
))
756 (dir default-directory
)
757 (buf (get-buffer-create "*magit-process*"))
759 (or (not magit-process
)
760 (error "Git is already running."))
761 (magit-set-mode-line-process
762 (magit-process-indicator-from-command
763 (car cmd-and-args
) (cdr cmd-and-args
)))
764 (setq magit-process-client-buffer
(current-buffer))
767 (setq default-directory dir
)
769 (goto-char (point-max))
771 (insert "$ " (or logline
772 (magit-concat-with-delim " " cmd-and-args
))
776 (apply 'start-process
"git" buf cmd args
))
777 (set-process-sentinel magit-process
'magit-process-sentinel
)
778 (set-process-filter magit-process
'magit-process-filter
)
781 (with-current-buffer input
782 (setq default-directory dir
)
784 (equal (apply 'call-process-region
(point-min) (point-max)
785 cmd nil buf nil args
) 0)))
786 (magit-set-mode-line-process nil
)
787 (magit-need-refresh magit-process-client-buffer
))
790 (equal (apply 'call-process cmd nil buf nil args
) 0))
791 (magit-set-mode-line-process nil
)
792 (magit-need-refresh magit-process-client-buffer
))))
795 (error "Git failed."))
798 (defun magit-process-sentinel (process event
)
799 (let ((msg (format "Git %s." (substring event
0 -
1)))
800 (successp (string-match "^finished" event
)))
801 (with-current-buffer (process-buffer process
)
804 (setq magit-process nil
)
805 (magit-set-mode-line-process nil
)
806 (magit-refresh-buffer magit-process-client-buffer
)))
808 (defun magit-process-filter (proc string
)
810 (set-buffer (process-buffer proc
))
811 (goto-char (process-mark proc
))
812 ;; Find last ^M in string. If one was found, ignore everything
813 ;; before it and delete the current line.
814 (let ((ret-pos (position ?
\r string
:from-end t
)))
816 (goto-char (line-beginning-position))
817 (delete-region (point) (line-end-position))
818 (insert (substring string
(+ ret-pos
1))))
821 (set-marker (process-mark proc
) (point))))
823 (defun magit-run (cmd &rest args
)
825 (magit-run* (cons cmd args
))))
827 (defun magit-run-with-input (input cmd
&rest args
)
829 (magit-run* (cons cmd args
) nil nil nil nil input
)))
831 (defun magit-run-shell (fmt &rest args
)
832 (let ((cmd (apply #'format fmt
(mapcar #'magit-escape-for-shell args
))))
834 (magit-run* (list shell-file-name shell-command-switch cmd
)
837 (defun magit-run-async (cmd &rest args
)
838 (magit-run* (cons cmd args
) nil nil nil t
))
840 (defun magit-display-process ()
842 (display-buffer "*magit-process*"))
846 ;; We define individual functions (instead of using lambda etc) so
847 ;; that the online help can show something meaningful.
849 (magit-define-section-jumper untracked
"Untracked files")
850 (magit-define-section-jumper unstaged
"Unstaged changes")
851 (magit-define-section-jumper staged
"Staged changes")
852 (magit-define-section-jumper unpushed
"Unpushed commits")
854 (defvar magit-mode-map
855 (let ((map (make-keymap)))
856 (suppress-keymap map t
)
857 (define-key map
(kbd "n") 'magit-goto-next-section
)
858 (define-key map
(kbd "p") 'magit-goto-previous-section
)
859 (define-key map
(kbd "TAB") 'magit-toggle-section
)
860 (define-key map
(kbd "<backtab>") 'magit-expand-collapse-section
)
861 (define-key map
(kbd "1") 'magit-jump-to-untracked
)
862 (define-key map
(kbd "2") 'magit-jump-to-unstaged
)
863 (define-key map
(kbd "3") 'magit-jump-to-staged
)
864 (define-key map
(kbd "4") 'magit-jump-to-unpushed
)
865 (define-key map
(kbd "g") 'magit-refresh
)
866 (define-key map
(kbd "G") 'magit-refresh-all
)
867 (define-key map
(kbd "s") 'magit-stage-item
)
868 (define-key map
(kbd "S") 'magit-stage-all
)
869 (define-key map
(kbd "u") 'magit-unstage-item
)
870 (define-key map
(kbd "U") 'magit-unstage-all
)
871 (define-key map
(kbd "i") 'magit-ignore-item
)
872 (define-key map
(kbd "I") 'magit-ignore-item-locally
)
873 (define-key map
(kbd "i") 'magit-ignore-item
)
874 (define-key map
(kbd "?") 'magit-describe-item
)
875 (define-key map
(kbd ".") 'magit-mark-item
)
876 (define-key map
(kbd "=") 'magit-diff-with-mark
)
877 (define-key map
(kbd "l") 'magit-log-head
)
878 (define-key map
(kbd "L") 'magit-log
)
879 (define-key map
(kbd "h") 'magit-reflog-head
)
880 (define-key map
(kbd "H") 'magit-reflog
)
881 (define-key map
(kbd "d") 'magit-diff-working-tree
)
882 (define-key map
(kbd "D") 'magit-diff
)
883 (define-key map
(kbd "a") 'magit-apply-item
)
884 (define-key map
(kbd "A") 'magit-cherry-pick-item
)
885 (define-key map
(kbd "v") 'magit-revert-item
)
886 (define-key map
(kbd "x") 'magit-reset-head
)
887 (define-key map
(kbd "X") 'magit-reset-working-tree
)
888 (define-key map
(kbd "k") 'magit-discard-item
)
889 (define-key map
(kbd "RET") 'magit-visit-item
)
890 (define-key map
(kbd "SPC") 'magit-show-item-or-scroll-up
)
891 (define-key map
(kbd "DEL") 'magit-show-item-or-scroll-down
)
892 (define-key map
(kbd "C-w") 'magit-copy-item-as-kill
)
893 (define-key map
(kbd "b") 'magit-checkout
)
894 (define-key map
(kbd "B") 'magit-create-branch
)
895 (define-key map
(kbd "m") 'magit-manual-merge
)
896 (define-key map
(kbd "M") 'magit-automatic-merge
)
897 (define-key map
(kbd "N r") 'magit-svn-rebase
)
898 (define-key map
(kbd "N c") 'magit-svn-dcommit
)
899 (define-key map
(kbd "R") 'magit-rebase-step
)
900 (define-key map
(kbd "r s") 'magit-rewrite-start
)
901 (define-key map
(kbd "r t") 'magit-rewrite-stop
)
902 (define-key map
(kbd "r a") 'magit-rewrite-abort
)
903 (define-key map
(kbd "r f") 'magit-rewrite-finish
)
904 (define-key map
(kbd "r *") 'magit-rewrite-set-unused
)
905 (define-key map
(kbd "r .") 'magit-rewrite-set-used
)
906 (define-key map
(kbd "P") 'magit-push
)
907 (define-key map
(kbd "f") 'magit-remote-update
)
908 (define-key map
(kbd "F") 'magit-pull
)
909 (define-key map
(kbd "c") 'magit-log-edit
)
910 (define-key map
(kbd "C") 'magit-add-log
)
911 (define-key map
(kbd "t") 'magit-tag
)
912 (define-key map
(kbd "T") 'magit-annotated-tag
)
913 (define-key map
(kbd "z") 'magit-stash
)
914 (define-key map
(kbd "$") 'magit-display-process
)
915 (define-key map
(kbd "q") 'quit-window
)
918 (easy-menu-define magit-mode-menu magit-mode-map
921 ["Refresh" magit-refresh t
]
922 ["Refresh all" magit-refresh-all t
]
924 ["Stage" magit-stage-item t
]
925 ["Stage all" magit-stage-all t
]
926 ["Unstage" magit-unstage-item t
]
927 ["Unstage all" magit-unstage-all t
]
928 ["Commit" magit-log-edit t
]
929 ["Add log entry" magit-add-log t
]
931 ["Annotated tag" magit-annotated-tag t
]
933 ["Diff working tree" magit-diff-working-tree t
]
934 ["Diff" magit-diff t
]
935 ["Log head" magit-log-head t
]
937 ["Reflog head" magit-reflog-head t
]
938 ["Reflog" magit-reflog t
]
940 ["Cherry pick" magit-cherry-pick-item t
]
941 ["Apply" magit-apply-item t
]
942 ["Revert" magit-revert-item t
]
944 ["Ignore" magit-ignore-item t
]
945 ["Ignore locally" magit-ignore-item-locally t
]
946 ["Discard" magit-discard-item t
]
947 ["Reset head" magit-reset-head t
]
948 ["Reset working tree" magit-reset-working-tree t
]
949 ["Stash" magit-stash t
]
951 ["Switch branch" magit-checkout t
]
952 ["Create branch" magit-create-branch t
]
953 ["Merge" magit-automatic-merge t
]
954 ["Merge (no commit)" magit-manual-merge t
]
955 ["Rebase" magit-rebase-step t
]
957 ["Rebase" magit-svn-rebase
(magit-svn-enabled)]
958 ["Commit" magit-svn-dcommit
(magit-svn-enabled)]
961 ["Start" magit-rewrite-start t
]
962 ["Stop" magit-rewrite-stop t
]
963 ["Finish" magit-rewrite-finish t
]
964 ["Abort" magit-rewrite-abort t
]
965 ["Set used" magit-rewrite-set-used t
]
966 ["Set unused" magit-rewrite-set-unused t
])
968 ["Push" magit-push t
]
969 ["Pull" magit-pull t
]
970 ["Remote update" magit-remote-update t
]
972 ["Display Git output" magit-display-process t
]
973 ["Quit Magit" quit-window t
]))
975 (defvar magit-mode-hook nil
)
977 (put 'magit-mode
'mode-class
'special
)
979 (defvar magit-submode nil
)
980 (make-variable-buffer-local 'magit-submode
)
981 (put 'magit-submode
'permanent-local t
)
983 (defvar magit-refresh-function nil
)
984 (make-variable-buffer-local 'magit-refresh-function
)
985 (put 'magit-refresh-function
'permanent-local t
)
987 (defvar magit-refresh-args nil
)
988 (make-variable-buffer-local 'magit-refresh-args
)
989 (put 'magit-refresh-args
'permanent-local t
)
992 "Review the status of a git repository and act on it.
994 Please see the manual for a complete description of Magit.
997 (kill-all-local-variables)
998 (setq buffer-read-only t
)
999 (setq major-mode
'magit-mode
1001 mode-line-process
""
1003 (add-hook 'post-command-hook
#'magit-highlight-section nil t
)
1004 (use-local-map magit-mode-map
)
1005 (run-mode-hooks 'magit-mode-hook
))
1007 (defun magit-mode-init (dir submode refresh-func
&rest refresh-args
)
1008 (setq default-directory dir
1009 magit-submode submode
1010 magit-refresh-function refresh-func
1011 magit-refresh-args refresh-args
)
1013 (magit-refresh-buffer))
1015 (defun magit-find-buffer (submode &optional dir
)
1016 (let ((topdir (magit-get-top-dir (or dir default-directory
))))
1017 (dolist (buf (buffer-list))
1020 (and (equal default-directory topdir
)
1021 (eq major-mode
'magit-mode
)
1022 (eq magit-submode submode
)))
1025 (defun magit-find-status-buffer (&optional dir
)
1026 (magit-find-buffer 'status dir
))
1028 (defun magit-for-all-buffers (func &optional dir
)
1029 (dolist (buf (buffer-list))
1032 (if (and (eq major-mode
'magit-mode
)
1034 (equal default-directory dir
)))
1037 (defun magit-refresh-buffer (&optional buffer
)
1038 (with-current-buffer (or buffer
(current-buffer))
1039 (let* ((old-line (line-number-at-pos))
1040 (old-section (magit-current-section))
1041 (old-path (and old-section
1042 (magit-section-path (magit-current-section))))
1043 (section-line (and old-section
1045 (magit-section-beginning old-section
)
1047 (if magit-refresh-function
1048 (apply magit-refresh-function
1049 magit-refresh-args
))
1050 (magit-refresh-marked-commits-in-buffer)
1051 (let ((s (and old-path
(magit-find-section old-path magit-top-section
))))
1053 (goto-char (magit-section-beginning s
))
1054 (forward-line section-line
))
1056 (magit-goto-line old-line
)))
1057 (dolist (w (get-buffer-window-list (current-buffer)))
1058 (set-window-point w
(point)))
1059 (magit-highlight-section)))))
1061 (defun magit-revert-buffers ()
1062 (dolist (buffer (buffer-list))
1064 (not (verify-visited-file-modtime buffer
))
1065 (not (buffer-modified-p buffer
)))
1066 (with-current-buffer buffer
1068 (revert-buffer t t t
))))))
1070 (defvar magit-refresh-needing-buffers nil
)
1071 (defvar magit-refresh-pending nil
)
1073 (defun magit-refresh-wrapper (func)
1074 (if magit-refresh-pending
1076 (let ((status-buffer (magit-find-buffer 'status default-directory
))
1077 (magit-refresh-needing-buffers nil
)
1078 (magit-refresh-pending t
))
1081 (when magit-refresh-needing-buffers
1082 (magit-revert-buffers)
1083 (dolist (b (adjoin status-buffer
1084 magit-refresh-needing-buffers
))
1085 (magit-refresh-buffer b
)))))))
1087 (defun magit-need-refresh (&optional buffer
)
1088 (let ((buffer (or buffer
(current-buffer))))
1089 (when (not (memq buffer magit-refresh-needing-buffers
))
1090 (setq magit-refresh-needing-buffers
1091 (cons buffer magit-refresh-needing-buffers
)))))
1093 (defun magit-refresh ()
1096 (magit-need-refresh)))
1098 (defun magit-refresh-all ()
1100 (magit-for-all-buffers #'magit-refresh-buffer default-directory
))
1104 (defun magit-wash-untracked-file ()
1105 (if (looking-at "^? \\(.*\\)$")
1106 (let ((file (match-string-no-properties 1)))
1107 (delete-region (point) (+ (line-end-position) 1))
1108 (magit-with-section file
'file
1109 (magit-set-section-info file
)
1110 (insert "\t" file
"\n"))
1114 (defun magit-wash-untracked-files ()
1115 (magit-wash-sequence #'magit-wash-untracked-file
))
1117 (defun magit-insert-untracked-files ()
1118 (magit-insert-section 'untracked
"Untracked files:"
1119 'magit-wash-untracked-files
1120 magit-collapse-threshold
1121 "git" "ls-files" "-t" "--others" "--exclude-standard"))
1125 (defun magit-diff-line-file ()
1126 (cond ((looking-at "^diff --git a/\\(.*\\) b/\\(.*\\)$")
1127 (match-string-no-properties 2))
1128 ((looking-at "^diff --cc +\\(.*\\)$")
1129 (match-string-no-properties 1))
1133 (defun magit-wash-diffs ()
1134 (magit-wash-sequence #'magit-wash-diff-or-other-file
))
1136 (defun magit-wash-diff-or-other-file ()
1137 (or (magit-wash-diff)
1138 (magit-wash-other-file)))
1140 (defun magit-wash-other-file ()
1141 (if (looking-at "^? \\(.*\\)$")
1142 (let ((file (match-string-no-properties 1)))
1143 (delete-region (point) (+ (line-end-position) 1))
1144 (magit-with-section file
'file
1145 (magit-set-section-info file
)
1146 (insert "\tNew " file
"\n"))
1150 (defvar magit-hide-diffs nil
)
1152 (defun magit-wash-diff ()
1153 (cond ((looking-at "^diff")
1155 (magit-current-line)
1156 (:type
'diff
:hidden magit-hide-diffs
)
1157 (let ((file (magit-diff-line-file))
1158 (end (save-excursion
1159 (forward-line) ;; skip over "diff" line
1160 (if (search-forward-regexp "^diff\\|^@@" nil t
)
1161 (goto-char (match-beginning 0))
1162 (goto-char (point-max)))
1164 (let* ((status (cond
1165 ((looking-at "^diff --cc")
1168 (search-forward-regexp "^new" end t
))
1171 (search-forward-regexp "^deleted" end t
))
1174 (search-forward-regexp "^rename" end t
))
1180 (search-forward-regexp "^rename from \\(.*\\)"
1182 (match-string-no-properties 1))))
1183 (status-text (case status
1185 (format "Unmerged %s" file
))
1187 (format "New %s" file
))
1189 (format "Deleted %s" file
))
1191 (format "Renamed %s (from %s)"
1194 (format "Modified %s" file
))
1196 (format "? %s" file
)))))
1197 (magit-set-section-info (list status file file2
))
1198 (insert "\t" status-text
"\n")
1200 (magit-wash-sequence #'magit-wash-hunk
)
1205 (defun magit-diff-item-kind (diff)
1206 (car (magit-section-info diff
)))
1208 (defun magit-diff-item-file (diff)
1209 (cadr (magit-section-info diff
)))
1211 (defun magit-diff-item-file2 (diff)
1212 (caddr (magit-section-info diff
)))
1214 (defun magit-wash-hunk ()
1215 (cond ((looking-at "\\(^@+\\)[^@]*@+")
1216 (let ((n-files (length (match-string 1)))
1217 (head (match-string 0)))
1218 (magit-with-section head
'hunk
1219 (magit-put-line-property 'face
'magit-diff-hunk-header
)
1221 (while (not (or (eobp)
1222 (looking-at "^diff\\|^@@")))
1223 (let ((prefix (buffer-substring-no-properties
1224 (point) (min (+ (point) n-files
) (point-max)))))
1225 (cond ((string-match "\\+" prefix
)
1226 (magit-put-line-property 'face
'magit-diff-add
))
1227 ((string-match "-" prefix
)
1228 (magit-put-line-property 'face
'magit-diff-del
))
1230 (magit-put-line-property 'face
'magit-diff-none
))))
1236 (defun magit-hunk-item-diff (hunk)
1237 (let ((diff (magit-section-parent hunk
)))
1238 (or (eq (magit-section-type diff
) 'diff
)
1239 (error "Huh? Parent of hunk not a diff."))
1242 (defun magit-diff-item-insert-header (diff buf
)
1243 (let ((beg (save-excursion
1244 (goto-char (magit-section-beginning diff
))
1247 (end (if (magit-section-children diff
)
1248 (magit-section-beginning (car (magit-section-children diff
)))
1249 (magit-section-end diff
))))
1250 (magit-insert-region beg end buf
)))
1252 (defun magit-insert-diff-item-patch (diff buf
)
1253 (let ((beg (save-excursion
1254 (goto-char (magit-section-beginning diff
))
1257 (end (magit-section-end diff
)))
1258 (magit-insert-region beg end buf
)))
1260 (defun magit-insert-hunk-item-patch (hunk buf
)
1261 (magit-diff-item-insert-header (magit-hunk-item-diff hunk
) buf
)
1262 (magit-insert-region (magit-section-beginning hunk
) (magit-section-end hunk
)
1265 (defun magit-insert-hunk-item-region-patch (hunk beg end buf
)
1266 (magit-diff-item-insert-header (magit-hunk-item-diff hunk
) buf
)
1268 (goto-char (magit-section-beginning hunk
))
1269 (magit-insert-current-line buf
)
1271 (while (< (point) (magit-section-end hunk
))
1272 (if (and (<= beg
(point)) (< (point) end
))
1273 (magit-insert-current-line buf
)
1274 (cond ((looking-at " ")
1275 (magit-insert-current-line buf
))
1277 (let ((text (buffer-substring-no-properties
1278 (+ (point) 1) (line-beginning-position 2))))
1279 (with-current-buffer buf
1280 (insert " " text
))))))
1282 (with-current-buffer buf
1283 (diff-fixup-modifs (point-min) (point-max))))
1285 (defun magit-hunk-item-is-conflict-p (hunk)
1286 ;;; XXX - Using the title is a bit too clever...
1287 (string-match "^diff --cc"
1288 (magit-section-title (magit-hunk-item-diff hunk
))))
1290 (defun magit-hunk-item-target-line (hunk)
1293 (let ((line (line-number-at-pos)))
1294 (if (looking-at "-")
1295 (error "Can't visit removed lines."))
1296 (goto-char (magit-section-beginning hunk
))
1297 (if (not (looking-at "@@+ .* \\+\\([0-9]+\\),[0-9]+ @@+"))
1298 (error "Hunk header not found."))
1299 (let ((target (parse-integer (match-string 1))))
1301 (while (< (line-number-at-pos) line
)
1302 ;; XXX - deal with combined diffs
1303 (if (not (looking-at "-"))
1304 (setq target
(+ target
1)))
1308 (defun magit-apply-diff-item (diff &rest args
)
1309 (with-current-buffer (get-buffer-create "*magit-tmp*")
1311 (magit-insert-diff-item-patch diff
"*magit-tmp*")
1312 (apply #'magit-run
"git" "apply" (append args
(list "-"))))
1314 (defun magit-apply-hunk-item (hunk &rest args
)
1315 (let ((tmp (get-buffer-create "*magit-tmp*")))
1316 (with-current-buffer tmp
1318 (if (magit-use-region-p)
1319 (magit-insert-hunk-item-region-patch
1320 hunk
(region-beginning) (region-end) tmp
)
1321 (magit-insert-hunk-item-patch hunk tmp
))
1322 (apply #'magit-run-with-input tmp
1323 "git" "apply" (append args
(list "-")))))
1325 (defun magit-insert-unstaged-changes (title)
1326 (let ((magit-hide-diffs t
))
1327 (magit-insert-section 'unstaged title
'magit-wash-diffs
1328 magit-collapse-threshold
1331 (defun magit-insert-staged-changes ()
1332 (let ((magit-hide-diffs t
))
1333 (magit-insert-section 'staged
"Staged changes:" 'magit-wash-diffs
1334 magit-collapse-threshold
1335 "git" "diff" "--cached")))
1337 ;;; Logs and Commits
1339 (defun magit-parse-log-ref (refname)
1340 "Return shortened and propertized version of full REFNAME, like
1341 \"refs/remotes/origin/master\"."
1342 (let ((face 'magit-log-head-label
))
1343 (cond ((string-match "^\\(tag: +\\)?refs/tags/\\(.+\\)" refname
)
1344 (setq refname
(match-string 2 refname
)
1345 face
'magit-log-tag-label
))
1346 ((string-match "^refs/remotes/\\(.+\\)" refname
)
1347 (setq refname
(match-string 1 refname
)))
1348 ((string-match "[^/]+$" refname
)
1349 (setq refname
(match-string 0 refname
))))
1350 (propertize refname
'face face
)))
1352 (defun magit-parse-log-refs (refstring)
1353 "Parse REFSTRING annotation from `git log --decorate'
1354 output (for example: \"refs/remotes/origin/master,
1355 refs/heads/master\") and return prettified string for displaying
1357 (mapconcat 'identity
1358 (mapcar 'magit-parse-log-ref
1359 (remove-if (lambda (refname)
1360 (string-match "/HEAD$" refname
))
1361 (reverse (split-string refstring
", *" t
))))
1364 (defun magit-wash-log-line ()
1365 (if (search-forward-regexp "[0-9a-fA-F]\\{40\\}" (line-end-position) t
)
1366 (let ((commit (match-string-no-properties 0)))
1367 (delete-region (match-beginning 0) (match-end 0))
1368 (goto-char (match-beginning 0))
1370 (goto-char (line-beginning-position))
1371 (when (search-forward-regexp "^[|*\\/ ]+\\((\\(tag:.+?\\|refs/.+?\\))\\)"
1372 (line-end-position) t
)
1373 (let ((refstring (match-string-no-properties 2)))
1374 (delete-region (match-beginning 1) (match-end 1))
1375 (insert (magit-parse-log-refs refstring
)))
1376 (goto-char (line-beginning-position)))
1377 (magit-with-section commit
'commit
1378 (magit-set-section-info commit
)
1383 (defun magit-wash-log ()
1384 (let ((magit-old-top-section nil
))
1385 (magit-wash-sequence #'magit-wash-log-line
)))
1387 (defvar magit-currently-shown-commit nil
)
1389 (defun magit-wash-commit ()
1390 (cond ((search-forward-regexp "^diff" nil t
)
1391 (goto-char (match-beginning 0))
1392 (magit-wash-diffs))))
1394 (defun magit-refresh-commit-buffer (commit)
1395 (magit-create-buffer-sections
1396 (magit-insert-section 'commitbuf nil
1397 'magit-wash-commit nil
1398 "git" "log" "--max-count=1" "--cc" "-p" commit
)))
1400 (defun magit-show-commit (commit &optional scroll
)
1401 (when (magit-section-p commit
)
1402 (setq commit
(magit-section-info commit
)))
1403 (let ((dir default-directory
)
1404 (buf (get-buffer-create "*magit-commit*")))
1405 (cond ((equal magit-currently-shown-commit commit
)
1406 (let ((win (get-buffer-window buf
)))
1408 (display-buffer buf
))
1410 (with-selected-window win
1411 (funcall scroll
))))))
1413 (setq magit-currently-shown-commit commit
)
1414 (display-buffer buf
)
1415 (with-current-buffer buf
1417 (goto-char (point-min))
1418 (magit-mode-init dir
'commit
1419 #'magit-refresh-commit-buffer commit
))))))
1421 (defvar magit-marked-commit nil
)
1423 (defun magit-refresh-marked-commits ()
1424 (magit-for-all-buffers #'magit-refresh-marked-commits-in-buffer
))
1426 (defun magit-refresh-marked-commits-in-buffer ()
1427 (let ((inhibit-read-only t
))
1428 (magit-for-all-sections
1430 (if (not (magit-section-p section
))
1431 (message "%s" section
))
1432 (when (and (eq (magit-section-type section
) 'commit
)
1433 (equal (magit-section-info section
)
1434 magit-marked-commit
))
1435 (put-text-property (magit-section-beginning section
)
1436 (magit-section-end section
)
1437 'face
'(:foreground
"red")))))))
1439 (defun magit-set-marked-commit (commit)
1440 (setq magit-marked-commit commit
)
1441 (magit-refresh-marked-commits))
1443 (defun magit-marked-commit ()
1444 (or magit-marked-commit
1445 (error "Not commit marked")))
1447 (defun magit-insert-unpulled-commits (remote branch
)
1448 (magit-insert-section 'unpulled
1449 "Unpulled commits:" 'magit-wash-log
1451 "git" "log" "--pretty=format:* %H %s"
1452 (format "HEAD..%s/%s" remote branch
)))
1454 (defun magit-insert-unpushed-commits (remote branch
)
1455 (magit-insert-section 'unpushed
1456 "Unpushed commits:" 'magit-wash-log
1458 "git" "log" "--pretty=format:* %H %s"
1459 (format "%s/%s..HEAD" remote branch
)))
1463 (defun magit-refresh-status ()
1464 (magit-create-buffer-sections
1465 (magit-with-section 'status nil
1466 (let* ((branch (magit-get-current-branch))
1467 (remote (and branch
(magit-get "branch" branch
"remote"))))
1469 (insert (format "Remote: %s %s\n"
1470 remote
(magit-get "remote" remote
"url"))))
1471 (insert (format "Local: %s %s\n"
1472 (propertize (or branch
"(detached)")
1473 'face
'magit-branch
)
1474 (abbreviate-file-name default-directory
)))
1479 "git log --max-count=1 --abbrev-commit --pretty=oneline")))
1480 (let ((merge-heads (magit-file-lines ".git/MERGE_HEAD")))
1482 (insert (format "Merging: %s\n"
1483 (magit-concat-with-delim
1485 (mapcar 'magit-name-rev merge-heads
))))))
1486 (let ((rebase (magit-rebase-info)))
1488 (insert (apply 'format
"Rebasing: %s (%s of %s)\n" rebase
))))
1490 (magit-insert-untracked-files)
1491 (magit-insert-stashes)
1492 (magit-insert-pending-changes)
1493 (magit-insert-pending-commits)
1495 (magit-insert-unpulled-commits remote branch
))
1496 (let ((staged (magit-anything-staged-p)))
1497 (magit-insert-unstaged-changes
1498 (if staged
"Unstaged changes:" "Changes:"))
1500 (magit-insert-staged-changes)))
1502 (magit-insert-unpushed-commits remote branch
))))))
1504 (defun magit-status (dir)
1505 (interactive (list (magit-read-top-dir)))
1507 (let* ((topdir (magit-get-top-dir dir
))
1508 (buf (or (magit-find-buffer 'status topdir
)
1510 (generate-new-buffer
1512 (file-name-nondirectory
1513 (directory-file-name topdir
)) "*"))))))
1514 (switch-to-buffer buf
)
1515 (magit-mode-init topdir
'status
#'magit-refresh-status
)))
1517 ;;; Staging and Unstaging
1519 (defun magit-stage-item ()
1520 "Add the item at point to the staging area."
1522 (magit-section-action (item info
"stage")
1524 (magit-run "git" "add" info
))
1525 ((unstaged diff hunk
)
1526 (if (magit-hunk-item-is-conflict-p item
)
1527 (error (concat "Can't stage individual resolution hunks. "
1528 "Please stage the whole file.")))
1529 (magit-apply-hunk-item item
"--cached"))
1531 (magit-run "git" "add" "-u" (magit-diff-item-file item
)))
1533 (error "Already staged"))
1535 (error "Can't stage this hunk"))
1537 (error "Can't stage this diff"))))
1539 (defun magit-unstage-item ()
1540 "Remove the item at point from the staging area."
1542 (magit-section-action (item info
"unstage")
1544 (magit-apply-hunk-item item
"--cached" "--reverse"))
1546 (magit-run "git" "reset" "-q" "HEAD" "--" (magit-diff-item-file item
)))
1548 (error "Already unstaged"))
1550 (error "Can't unstage this hunk"))
1552 (error "Can't unstage this diff"))))
1554 (defun magit-stage-all ()
1556 (magit-run "git" "add" "-u" "."))
1558 (defun magit-unstage-all ()
1560 (magit-run "git" "reset" "HEAD"))
1564 (defun magit-checkout (rev)
1565 (interactive (list (magit-read-rev "Switch to" (magit-default-rev))))
1567 (magit-run "git" "checkout" (magit-rev-to-git rev
))))
1569 (defun magit-read-create-branch-args ()
1570 (let* ((cur-branch (magit-get-current-branch))
1571 (branch (read-string "Create branch: "))
1572 (parent (magit-read-rev "Parent" cur-branch
)))
1573 (list branch parent
)))
1575 (defun magit-create-branch (branch parent
)
1576 (interactive (magit-read-create-branch-args))
1577 (if (and branch
(not (string= branch
""))
1579 (magit-run "git" "checkout" "-b"
1581 (magit-rev-to-git parent
))))
1585 (defun magit-manual-merge (rev)
1586 (interactive (list (magit-read-rev "Manually merge")))
1588 (magit-run "git" "merge" "--no-ff" "--no-commit"
1589 (magit-rev-to-git rev
))))
1591 (defun magit-automatic-merge (rev)
1592 (interactive (list (magit-read-rev "Merge")))
1594 (magit-run "git" "merge" (magit-rev-to-git rev
))))
1598 (defun magit-rebase-info ()
1599 (cond ((file-exists-p ".dotest")
1600 (list (magit-name-rev (car (magit-file-lines ".dotest/onto")))
1601 (car (magit-file-lines ".dotest/next"))
1602 (car (magit-file-lines ".dotest/last"))))
1603 ((file-exists-p ".git/.dotest-merge")
1604 (list (car (magit-file-lines ".git/.dotest-merge/onto_name"))
1605 (car (magit-file-lines ".git/.dotest-merge/msgnum"))
1606 (car (magit-file-lines ".git/.dotest-merge/end"))))
1610 (defun magit-rebase-step ()
1612 (let ((info (magit-rebase-info)))
1614 (let ((rev (magit-read-rev "Rebase to")))
1616 (magit-run "git" "rebase" (magit-rev-to-git rev
))))
1617 (let ((cursor-in-echo-area t
)
1618 (message-log-max nil
))
1619 (message "Rebase in progress. Abort, Skip, or Continue? ")
1620 (let ((reply (read-event)))
1623 (magit-run "git" "rebase" "--abort"))
1625 (magit-run "git" "rebase" "--skip"))
1627 (magit-run "git" "rebase" "--continue"))))))))
1631 (defun magit-svn-rebase ()
1633 (magit-run "git" "svn" "rebase"))
1635 (defun magit-svn-dcommit ()
1637 (magit-run "git" "svn" "dcommit"))
1639 (defun magit-svn-enabled ()
1640 (not (null (find "git-svn" (magit-list-interesting-revisions) :test
'equal
))))
1644 (defun magit-reset-head (rev)
1645 (interactive (list (magit-read-rev "Reset head to"
1646 (or (magit-default-rev)
1649 (magit-run "git" "reset" "--soft" (magit-rev-to-git rev
))))
1651 (defun magit-reset-working-tree ()
1653 (if (yes-or-no-p "Discard all uncommitted changes? ")
1654 (magit-run "git" "reset" "--hard")))
1658 (defun magit-read-rewrite-info ()
1659 (when (file-exists-p ".git/magit-rewrite-info")
1661 (insert-file-contents ".git/magit-rewrite-info")
1662 (goto-char (point-min))
1663 (read (current-buffer)))))
1665 (defun magit-write-rewrite-info (info)
1666 (with-temp-file ".git/magit-rewrite-info"
1667 (prin1 info
(current-buffer))
1668 (princ "\n" (current-buffer))))
1670 (defun magit-insert-pending-commits ()
1671 (let* ((info (magit-read-rewrite-info))
1672 (pending (cdr (assq 'pending info
))))
1674 (magit-with-section 'pending nil
1675 (insert (propertize "Pending commits:\n"
1676 'face
'magit-section-title
))
1678 (let* ((commit (car p
))
1679 (properties (cdr p
))
1680 (used (plist-get properties
'used
)))
1681 (magit-with-section commit
'commit
1682 (magit-set-section-info commit
)
1683 (insert (magit-shell
1684 "git log --max-count=1 --pretty=format:%s %s --"
1685 (if used
". %s" "* %s")
1690 (defun magit-rewrite-set-commit-property (commit prop value
)
1691 (let* ((info (magit-read-rewrite-info))
1692 (pending (cdr (assq 'pending info
)))
1693 (p (assoc commit pending
)))
1695 (setf (cdr p
) (plist-put (cdr p
) prop value
))
1696 (magit-write-rewrite-info info
)
1697 (magit-need-refresh))))
1699 (defun magit-rewrite-set-used ()
1701 (magit-section-action (item info
)
1703 (magit-rewrite-set-commit-property info
'used t
))))
1705 (defun magit-rewrite-set-unused ()
1707 (magit-section-action (item info
)
1709 (magit-rewrite-set-commit-property info
'used nil
))))
1711 (defun magit-insert-pending-changes ()
1712 (let* ((info (magit-read-rewrite-info))
1713 (orig (cadr (assq 'orig info
))))
1715 (let ((magit-hide-diffs t
))
1716 (magit-insert-section 'pending-changes
1718 'magit-wash-diffs nil
1719 "git" "diff" "-R" orig
)))))
1721 (defun magit-rewrite-start (from &optional onto
)
1722 (interactive (list (magit-read-rev "Rewrite from" (magit-default-rev))))
1723 (or (magit-everything-clean-p)
1724 (error "You have uncommitted changes."))
1725 (or (not (magit-read-rewrite-info))
1726 (error "Rewrite in progress."))
1727 (let* ((orig (magit-shell "git rev-parse HEAD"))
1728 (base (magit-shell "git rev-parse %s^" from
))
1729 (pending (magit-shell-lines "git rev-list %s.." base
)))
1730 (magit-write-rewrite-info `((orig ,orig
)
1731 (pending ,@(mapcar #'list pending
))))
1732 (magit-run "git" "reset" "--hard" base
)))
1734 (defun magit-rewrite-stop (&optional noconfirm
)
1736 (let* ((info (magit-read-rewrite-info)))
1738 (error "No rewrite in progress."))
1740 (yes-or-no-p "Stop rewrite? "))
1741 (magit-write-rewrite-info nil
)
1742 (magit-need-refresh))))
1744 (defun magit-rewrite-abort ()
1746 (let* ((info (magit-read-rewrite-info))
1747 (orig (cadr (assq 'orig info
))))
1749 (error "No rewrite in progress."))
1750 (or (magit-everything-clean-p)
1751 (error "You have uncommitted changes."))
1752 (when (yes-or-no-p "Abort rewrite? ")
1753 (magit-write-rewrite-info nil
)
1754 (magit-run "git" "reset" "--hard" orig
))))
1756 (defun magit-rewrite-finish ()
1759 (magit-rewrite-finish-step t
)))
1761 (defun magit-rewrite-finish-step (first-p)
1762 (let ((info (magit-read-rewrite-info)))
1764 (error "No rewrite in progress."))
1765 (let* ((pending (cdr (assq 'pending info
)))
1766 (first-unused (find-if (lambda (p)
1767 (not (plist-get (cdr p
) 'used
)))
1770 (commit (car first-unused
)))
1771 (cond ((not first-unused
)
1772 (magit-rewrite-stop t
))
1773 ((magit-cherry-pick-commit commit
(not first-p
))
1774 (magit-rewrite-set-commit-property commit
'used t
)
1775 (magit-rewrite-finish-step nil
))))))
1777 ;;; Updating, pull, and push
1780 (defun magit-list-remotes ()
1781 "retrieve list of remotes, registered in current repository"
1782 (magit-shell-lines "git remote show"))
1784 (defun magit-read-remote (prompt &optional def
)
1785 "reads name of remote repository from mini-buffer"
1786 (let* ((prompt (if def
1787 (format "%s (default %s): " prompt def
)
1788 (format "%s: " prompt
)))
1789 (remote (completing-read prompt
(magit-list-remotes)
1790 nil nil nil nil def
)))
1791 (if (string= remote
"")
1795 (defun magit-get-remote-refspec (remote)
1796 "obtain refspec for given remote"
1797 (let ((refspec (magit-get "remote" remote
"fetch")))
1798 (if (string= refspec
"")
1802 (defun magit-remote-update (remote)
1803 "Check for updates in remote repository"
1804 (interactive (list (magit-read-remote "Pull from:" "origin")))
1806 (let ((refspec (magit-get-remote-refspec remote
)))
1808 (magit-run-async "git" "fetch" remote refspec
)))))
1810 (defun magit-pull (remote)
1811 "Pull changes from remote repository"
1812 (interactive (list (magit-read-remote "Pull from:" "origin")))
1814 (let ((refspec (magit-get-remote-refspec remote
)))
1816 (magit-run-async "git" "pull" remote refspec
"-v")))))
1818 (defun magit-push (remote)
1819 "Push changes to remote repository"
1820 (interactive (list (magit-read-remote "Pull to:" "origin")))
1822 (magit-run-async "git" "push" "-v" remote
)))
1826 (defvar magit-log-edit-map
1827 (let ((map (make-sparse-keymap)))
1828 (define-key map
(kbd "C-c C-c") 'magit-log-edit-commit
)
1829 (define-key map
(kbd "C-c C-a") 'magit-log-edit-toggle-amending
)
1830 (define-key map
(kbd "M-p") 'log-edit-previous-comment
)
1831 (define-key map
(kbd "M-n") 'log-edit-next-comment
)
1834 (defvar magit-pre-log-edit-window-configuration nil
)
1836 (defun magit-log-fill-paragraph (&optional justify
)
1837 "Fill the paragraph, but preserve open parentheses at beginning of lines.
1838 Prefix arg means justify as well."
1840 ;; Add lines starting with a left paren or an asterisk.
1841 (let ((paragraph-start (concat paragraph-start
"\\|*\\|(")))
1842 (let ((end (progn (forward-paragraph) (point)))
1843 (beg (progn (backward-paragraph) (point)))
1844 (adaptive-fill-mode nil
))
1845 (fill-region beg end justify
)
1848 (define-derived-mode magit-log-edit-mode text-mode
"Magit Log Edit"
1849 (set (make-local-variable 'fill-paragraph-function
)
1850 'magit-log-fill-paragraph
)
1851 (use-local-map magit-log-edit-map
))
1853 (defun magit-log-edit-cleanup ()
1855 (goto-char (point-min))
1857 (goto-char (point-min))
1858 (if (re-search-forward "[ \t\n]*\\'" nil t
)
1859 (replace-match "\n" nil nil
))))
1861 (defun magit-log-edit-append (str)
1863 (set-buffer (get-buffer-create "*magit-log-edit*"))
1864 (goto-char (point-max))
1867 (defconst magit-log-header-end
"-- End of Magit header --\n")
1869 (defun magit-log-edit-get-fields ()
1870 (let ((buf (get-buffer "*magit-log-edit*"))
1875 (goto-char (point-min))
1876 (while (looking-at "^\\([A-Za-z0-9]+\\): *\\(.*\\)$")
1877 (setq result
(acons (intern (downcase (match-string 1)))
1881 (if (not (looking-at (regexp-quote magit-log-header-end
)))
1882 (setq result nil
))))
1885 (defun magit-log-edit-set-fields (fields)
1886 (let ((buf (get-buffer-create "*magit-log-edit*")))
1889 (goto-char (point-min))
1890 (if (search-forward-regexp (format "^\\([A-Za-z0-9]+:.*\n\\)+%s"
1891 (regexp-quote magit-log-header-end
))
1893 (delete-region (match-beginning 0) (match-end 0)))
1894 (goto-char (point-min))
1897 (insert (capitalize (symbol-name (caar fields
))) ": "
1899 (setq fields
(cdr fields
)))
1900 (insert magit-log-header-end
)))))
1902 (defun magit-log-edit-set-field (name value
)
1903 (let* ((fields (magit-log-edit-get-fields))
1904 (cell (assq name fields
)))
1908 (setq fields
(delq cell fields
))))
1911 (setq fields
(append fields
(list (cons name value
)))))))
1912 (magit-log-edit-set-fields fields
)))
1914 (defun magit-log-edit-setup-author-env (author)
1916 ;; XXX - this is a bit strict, probably.
1917 (or (string-match "\\(.*\\) <\\(.*\\)>, \\(.*\\)" author
)
1918 (error "Can't parse author string."))
1919 ;; Shucks, setenv destroys the match data.
1920 (let ((name (match-string 1 author
))
1921 (email (match-string 2 author
))
1922 (date (match-string 3 author
)))
1923 (setenv "GIT_AUTHOR_NAME" name
)
1924 (setenv "GIT_AUTHOR_EMAIL" email
)
1925 (setenv "GIT_AUTHOR_DATE" date
)))
1927 (setenv "GIT_AUTHOR_NAME")
1928 (setenv "GIT_AUTHOR_EMAIL")
1929 (setenv "GIT_AUTHOR_DATE"))))
1931 (defun magit-log-edit-push-to-comment-ring (comment)
1932 (when (or (ring-empty-p log-edit-comment-ring
)
1933 (not (equal comment
(ring-ref log-edit-comment-ring
0))))
1934 (ring-insert log-edit-comment-ring comment
)))
1936 (defun magit-log-edit-commit ()
1938 (let* ((fields (magit-log-edit-get-fields))
1939 (amend (equal (cdr (assq 'amend fields
)) "yes"))
1940 (tag (cdr (assq 'tag fields
)))
1941 (author (cdr (assq 'author fields
))))
1942 (magit-log-edit-push-to-comment-ring (buffer-string))
1943 (magit-log-edit-setup-author-env author
)
1944 (magit-log-edit-set-fields nil
)
1945 (magit-log-edit-cleanup)
1946 (if (= (buffer-size) 0)
1947 (insert "(Empty description)\n"))
1948 (let ((commit-buf (current-buffer)))
1949 (with-current-buffer (magit-find-buffer 'status default-directory
)
1951 (magit-run-with-input commit-buf
1952 "git" "tag" tag
"-a" "-F" "-"))
1954 (apply #'magit-run-with-input commit-buf
1955 "git" "commit" "-F" "-"
1956 (append (if (not (magit-anything-staged-p))
1958 (if amend
'("--amend") '())))))))
1961 (when magit-pre-log-edit-window-configuration
1962 (set-window-configuration magit-pre-log-edit-window-configuration
)
1963 (setq magit-pre-log-edit-window-configuration nil
))))
1965 (defun magit-log-edit-toggle-amending ()
1967 (let* ((fields (magit-log-edit-get-fields))
1968 (cell (assq 'amend fields
)))
1970 (rplacd cell
(if (equal (cdr cell
) "yes") "no" "yes"))
1971 (setq fields
(acons 'amend
"yes" fields
))
1972 (magit-log-edit-append
1973 (magit-format-commit "HEAD" "%s%n%n%b")))
1974 (magit-log-edit-set-fields fields
)))
1976 (defun magit-pop-to-log-edit (operation)
1977 (let ((dir default-directory
)
1978 (buf (get-buffer-create "*magit-log-edit*")))
1979 (setq magit-pre-log-edit-window-configuration
1980 (current-window-configuration))
1982 (setq default-directory dir
)
1983 (magit-log-edit-mode)
1984 (message "Type C-c C-c to %s." operation
)))
1986 (defun magit-log-edit ()
1988 (magit-log-edit-set-field 'tag nil
)
1989 (magit-pop-to-log-edit "commit"))
1991 (defun magit-add-log ()
1993 (let ((section (magit-current-section)))
1994 (let ((fun (if (eq (magit-section-type section
) 'hunk
)
1995 (save-window-excursion
1998 (add-log-current-defun)))
2000 (file (magit-diff-item-file
2001 (cond ((eq (magit-section-type section
) 'hunk
)
2002 (magit-hunk-item-diff section
))
2003 ((eq (magit-section-type section
) 'diff
)
2006 (error "No change at point"))))))
2008 (goto-char (point-min))
2009 (cond ((not (search-forward-regexp (format "^\\* %s" (regexp-quote file
))
2011 ;; No entry for file, create it.
2012 (goto-char (point-max))
2013 (insert (format "\n* %s" file
))
2015 (insert (format " (%s)" fun
)))
2018 ;; found entry for file, look for fun
2019 (let ((limit (or (save-excursion
2020 (and (search-forward-regexp "^\\* " nil t
)
2021 (match-beginning 0)))
2023 (cond ((search-forward-regexp (format "(.*\\<%s\\>.*):"
2026 ;; found it, goto end of current entry
2027 (if (search-forward-regexp "^(" limit t
)
2031 ;; not found, insert new entry
2036 (insert (format "(%s): " fun
))))))))))
2040 (defun magit-tag (name)
2041 (interactive "sNew tag name: ")
2042 (magit-run "git" "tag" name
))
2044 (defun magit-annotated-tag (name)
2045 (interactive "sNew tag name: ")
2046 (magit-log-edit-set-field 'tag name
)
2047 (magit-pop-to-log-edit "tag"))
2051 (defun magit-wash-stash ()
2052 (if (search-forward-regexp "stash@{\\(.*\\)}" (line-end-position) t
)
2053 (let ((stash (match-string-no-properties 0))
2054 (name (match-string-no-properties 1)))
2055 (delete-region (match-beginning 0) (match-end 0))
2056 (goto-char (match-beginning 0))
2058 (goto-char (line-beginning-position))
2060 (goto-char (line-beginning-position))
2061 (magit-with-section stash
'stash
2062 (magit-set-section-info stash
)
2067 (defun magit-wash-stashes ()
2068 (let ((magit-old-top-section nil
))
2069 (magit-wash-sequence #'magit-wash-stash
)))
2071 (defun magit-insert-stashes ()
2072 (magit-insert-section 'stashes
2073 "Stashes:" 'magit-wash-stashes
2075 "git" "stash" "list"))
2077 (defun magit-stash (description)
2078 (interactive "sStash description: ")
2079 (magit-run "git" "stash" "save" description
))
2083 (defun magit-commit-at-point (&optional nil-ok-p
)
2084 (let* ((section (magit-current-section))
2085 (commit (and (eq (magit-section-type section
) 'commit
)
2086 (magit-section-info section
))))
2090 (error "No commit at point.")))))
2092 (defun magit-apply-commit (commit)
2093 (let ((parent (magit-choose-parent commit
"apply")))
2094 (magit-log-edit-append
2095 (magit-format-commit commit
"%s%n%n%b"))
2096 (magit-log-edit-set-field
2098 (magit-format-commit commit
"%an <%ae>, %ai"))
2099 (magit-run-shell "git diff %s %s | git apply -" parent commit
)))
2101 (defun magit-cherry-pick-commit (commit &optional noerase
)
2102 (let ((parent-id (magit-choose-parent-id commit
"cherry-pick")))
2103 (magit-run* `("git" "cherry-pick"
2105 (list "-m" (number-to-string parent-id
)))
2109 (defun magit-apply-item ()
2111 (magit-section-action (item info
"apply")
2113 (magit-apply-commit info
)
2114 (magit-rewrite-set-commit-property info
'used t
))
2116 (magit-apply-commit info
))
2118 (error "Change is already in your working tree"))
2120 (error "Change is already in your working tree"))
2122 (magit-apply-hunk-item item
))
2124 (magit-apply-diff-item item
))
2126 (magit-run "git" "stash" "apply" info
))))
2128 (defun magit-cherry-pick-item ()
2130 (magit-section-action (item info
"cherry-pick")
2132 (magit-cherry-pick-commit info
)
2133 (magit-rewrite-set-commit-property info
'used t
))
2135 (magit-cherry-pick-commit info
))
2137 (magit-run "git" "stash" "pop" info
))))
2139 (defun magit-revert-commit (commit)
2140 (let ((parent (magit-choose-parent commit
"revert")))
2141 (magit-log-edit-append
2142 (magit-format-commit commit
"Reverting \"%s\""))
2143 (magit-run-shell "git diff %s %s | git apply --reverse -" parent commit
)))
2145 (defun magit-revert-item ()
2147 (magit-section-action (item info
"revert")
2149 (magit-revert-commit info
)
2150 (magit-rewrite-set-commit-property info
'used nil
))
2152 (magit-revert-commit info
))
2154 (magit-apply-hunk-item item
"--reverse"))
2156 (magit-apply-diff-item item
"--reverse"))))
2158 (defvar magit-have-graph
'unset
)
2159 (defvar magit-have-decorate
'unset
)
2161 (defun magit-configure-have-graph ()
2162 (if (eq magit-have-graph
'unset
)
2163 (let ((res (magit-shell-exit-code "git log --graph --max-count=0")))
2164 (message "result %s" res
)
2165 (setq magit-have-graph
(eq res
0)))))
2167 (defun magit-configure-have-decorate ()
2168 (if (eq magit-have-decorate
'unset
)
2169 (let ((res (magit-shell-exit-code "git log --decorate --max-count=0")))
2170 (setq magit-have-decorate
(eq res
0)))))
2172 (defun magit-refresh-log-buffer (range args
)
2173 (magit-configure-have-graph)
2174 (magit-configure-have-decorate)
2175 (magit-create-buffer-sections
2176 (apply #'magit-insert-section
'log
2177 (magit-rev-range-describe range
"Commits")
2179 `("git" "log" "--max-count=1000" "--pretty=oneline"
2180 ,@(if magit-have-decorate
(list "--decorate"))
2181 ,@(if magit-have-graph
(list "--graph"))
2184 (defun magit-log (range)
2185 (interactive (list (magit-read-rev-range "Log" (magit-get-current-branch))))
2187 (let* ((topdir (magit-get-top-dir default-directory
))
2188 (args (magit-rev-range-to-git range
)))
2189 (switch-to-buffer "*magit-log*")
2190 (magit-mode-init topdir
'log
#'magit-refresh-log-buffer range args
))))
2192 (defun magit-log-head ()
2198 (defun magit-refresh-reflog-buffer (head args
)
2199 (magit-create-buffer-sections
2200 (magit-insert-section 'reflog
2201 (format "Local history of head %s" head
)
2203 "git" "log" "--walk-reflogs"
2205 "--pretty=oneline" args
)))
2207 (defun magit-reflog (head)
2208 (interactive (list (magit-read-rev "Reflog of" "HEAD")))
2210 (let* ((topdir (magit-get-top-dir default-directory
))
2211 (args (magit-rev-to-git head
)))
2212 (switch-to-buffer "*magit-reflog*")
2213 (magit-mode-init topdir
'reflog
2214 #'magit-refresh-reflog-buffer head args
))))
2216 (defun magit-reflog-head ()
2218 (magit-reflog "HEAD"))
2222 (defun magit-refresh-diff-buffer (range args
)
2223 (magit-create-buffer-sections
2224 (magit-insert-section 'diffbuf
2225 (magit-rev-range-describe range
"Changes")
2226 'magit-wash-diffs nil
2227 "git" "diff" args
)))
2229 (defun magit-diff (range)
2230 (interactive (list (magit-read-rev-range "Diff")))
2232 (let* ((dir default-directory
)
2233 (args (magit-rev-range-to-git range
))
2234 (buf (get-buffer-create "*magit-diff*")))
2235 (display-buffer buf
)
2238 (magit-mode-init dir
'diff
#'magit-refresh-diff-buffer range args
)))))
2240 (defun magit-diff-working-tree (rev)
2241 (interactive (list (magit-read-rev "Diff with (default HEAD)")))
2242 (magit-diff (or rev
"HEAD")))
2244 (defun magit-diff-with-mark ()
2246 (magit-diff (cons (magit-marked-commit)
2247 (magit-commit-at-point))))
2251 (defun magit-ignore-file (file edit local
)
2252 (let ((ignore-file (if local
".git/info/exclude" ".gitignore")))
2254 (setq file
(read-string "File to ignore: " file
)))
2255 (append-to-file (concat "/" file
"\n") nil ignore-file
)
2256 (magit-need-refresh)))
2258 (defun magit-ignore-item ()
2260 (magit-section-action (item info
"ignore")
2262 (magit-ignore-file info current-prefix-arg nil
))))
2264 (defun magit-ignore-item-locally ()
2266 (magit-section-action (item info
"ignore")
2268 (magit-ignore-file info current-prefix-arg t
))))
2270 (defun magit-discard-diff (diff)
2271 (let ((kind (magit-diff-item-kind diff
))
2272 (file (magit-diff-item-file diff
)))
2273 (cond ((eq kind
'deleted
)
2274 (when (yes-or-no-p (format "Resurrect %s? " file
))
2275 (magit-shell "git reset -q -- %s" file
)
2276 (magit-run "git" "checkout" "--" file
)))
2278 (if (yes-or-no-p (format "Delete %s? " file
))
2279 (magit-run "git" "rm" "-f" "--" file
)))
2281 (if (yes-or-no-p (format "Discard changes to %s? " file
))
2282 (magit-run "git" "checkout" "--" file
))))))
2284 (defun magit-discard-item ()
2286 (magit-section-action (item info
"discard")
2288 (if (yes-or-no-p (format "Delete %s? " info
))
2289 (magit-run "rm" info
)))
2290 ((unstaged diff hunk
)
2291 (when (yes-or-no-p "Discard hunk? ")
2292 (magit-apply-hunk-item item
"--reverse")))
2294 (if (magit-file-uptodate-p (magit-diff-item-file
2295 (magit-hunk-item-diff item
)))
2296 (when (yes-or-no-p "Discard hunk? ")
2297 (magit-apply-hunk-item item
"--reverse" "--index"))
2298 (error "Can't discard this hunk. Please unstage it first.")))
2300 (magit-discard-diff item
))
2302 (magit-discard-diff item
))
2304 (error "Can't discard this hunk"))
2306 (error "Can't discard this diff"))
2308 (when (yes-or-no-p "Discard stash? ")
2309 (magit-run "git" "stash" "drop" info
)))))
2311 (defun magit-visit-item ()
2313 (magit-section-action (item info
"visit")
2317 (find-file (magit-diff-item-file item
)))
2319 (let ((file (magit-diff-item-file (magit-hunk-item-diff item
)))
2320 (line (magit-hunk-item-target-line item
)))
2324 (magit-show-commit info
)
2325 (pop-to-buffer "*magit-commit*"))))
2327 (defun magit-show-item-or-scroll-up ()
2329 (magit-section-action (item info
)
2331 (magit-show-commit info
#'scroll-up
))))
2333 (defun magit-show-item-or-scroll-down ()
2335 (magit-section-action (item info
)
2337 (magit-show-commit info
#'scroll-down
))))
2339 (defun magit-mark-item ()
2341 (magit-section-action (item info
"mark")
2343 (magit-set-marked-commit info
))))
2345 (defun magit-describe-item ()
2347 (let ((section (magit-current-section)))
2348 (message "Section: %s %s-%s %S %S"
2349 (magit-section-type section
)
2350 (magit-section-beginning section
)
2351 (magit-section-end section
)
2352 (magit-section-title section
)
2353 (magit-section-info section
))))
2355 (defun magit-copy-item-as-kill ()
2356 "Copy sha1 of commit at point into kill ring."
2358 (magit-section-action (item info
"copy")
2361 (message "%s" info
))))