;; sy-git.el --- A couple of nice git tools -*- Emacs-Lisp -*-
-;; Copyright (C) 2015 Steve Youngs
+;; Copyright (C) 2015 - 2017 Steve Youngs
;; Author: Steve Youngs <steve@sxemacs.org>
;; Maintainer: Steve Youngs <steve@sxemacs.org>
;; Created: <2015-07-05>
-;; Time-stamp: <Friday Jul 15, 2016 15:02:16 steve>
+;; Time-stamp: <Monday Oct 16, 2017 09:05:17 steve>
;; Homepage: http://git.sxemacs.org/slh
;; Keywords: git, tools, convenience
;; lets you write commit logs in a similar format to that of
;; `add-change-log-entry'. It is globally bound to `C-x G a'.
;; See: `sy-git-add-log-entry'.
+;;
+;; [2017-10-16 08:59]: Added rudimentary support for git-diff,
+;; git-blame, and git-log. For examining changes you can use
+;; either plain `diff-mode' with `sy-git-diff', or Ediff with
+;; `sy-git-ediff'.
;;; Todo:
;;
-;; o Implement a variation of `patch-to-change-log'
+;; o Implement a variation of `patch-to-change-log'.
+;; [2017-10-15 15:09]: Turns out that this isn't really needed
+;; as you can invoke `sy-git-add-log-entry' directly from a diff.
;;; Code:
+;; Need VC, ediff, and diff-mode
+(vc-load-vc-hooks)
+(add-to-list 'vc-handled-backends 'GIT)
+(require 'ediff)
+(require 'diff-mode)
+
+;; diff
+(defun sy-git-diff ()
+ "Show a diff of the current file against HEAD."
+ (interactive)
+ (vc-diff nil))
+
+(defun sy-git-ediff ()
+ "Run ediff-buffers on the working file and the HEAD version."
+ (interactive)
+ (let* ((bufferA (file-basename (buffer-file-name)))
+ (bufferB (concat bufferA ".~HEAD~")))
+ (progn
+ (vc-version-other-window "HEAD")
+ (ediff-buffers bufferA bufferB))))
+
+;; blame
+(defun sy-git-blame ()
+ "Display git blame for the current file.
+
+If the region is active the output will be for just the lines of the
+file within the region."
+ (interactive)
+ (let ((gitcmd "git blame ")
+ beg end)
+ (when (region-active-p)
+ (setq beg (line-number (region-beginning))
+ end (line-number (region-end))))
+ (and beg end
+ (setq gitcmd (concat gitcmd (format "-L%d,%d " beg end))))
+ (setq gitcmd (concat gitcmd (file-basename (buffer-file-name))))
+ (with-electric-help
+ #'(lambda ()
+ (setq truncate-lines t)
+ (insert
+ (with-temp-buffer
+ (insert (shell-command-to-string gitcmd))
+ (buffer-string (current-buffer)))))
+ "*GIT Blame*")))
+
+;; log
+(defun sy-git-log (all)
+ "Display git log of current file.
+
+With prefix arg, ALL, display the log for the entire repo."
+ (interactive "p")
+ (let ((gitcmd "git log --format=fuller"))
+ (unless current-prefix-arg
+ (setq gitcmd
+ (concat gitcmd
+ (format " %s" (file-basename (buffer-file-name))))))
+ (with-electric-help
+ #'(lambda ()
+ (insert
+ (with-temp-buffer
+ (insert (shell-command-to-string gitcmd))
+ (buffer-string (current-buffer)))))
+ "*GIT Log*")))
+
(defun sy-git-check-hook (hook)
"Return non-nil when HOOK script exists and is usable.