EOS: Git Module

Table of Contents

(provide 'eos-git)

Git magic with Magit

I use C-x g everywhere to go directly to Magit.

(use-package magit
  :ensure t
  :bind (("C-x g" . magit-status))
  :init (add-hook 'magit-mode-hook 'eos/turn-on-hl-line)
  :config
  (setq git-commit-summary-max-length 70)
  (setenv "GIT_PAGER" "")
  (if (file-exists-p  "/usr/local/bin/emacsclient")
      (setq magit-emacsclient-executable "/usr/local/bin/emacsclient")
    (setq magit-emacsclient-executable (executable-find "emacsclient")))
  (defun eos/magit-browse ()
    "Browse to the project's github URL, if available"
    (interactive)
    (let ((url (with-temp-buffer
                 (unless (zerop (call-process-shell-command
                                 "git remote -v" nil t))
                   (error "Failed: 'git remote -v'"))
                 (goto-char (point-min))
                 (when (re-search-forward
                        "github\\.com[:/]\\(.+?\\)\\.git" nil t)
                   (format "https://github.com/%s" (match-string 1))))))
      (unless url
        (error "Can't find repository URL"))
      (browse-url url)))

  (define-key magit-mode-map (kbd "C-c C-b") #'eos/magit-browse)
  ;; Magit has its own binding, so re-bind them
  (bind-key "M-1" #'eos/create-or-switch-to-eshell-1 magit-mode-map)
  (bind-key "M-2" #'eos/create-or-switch-to-eshell-2 magit-mode-map)
  (bind-key "M-3" #'eos/create-or-switch-to-eshell-3 magit-mode-map)
  (bind-key "M-4" #'eos/create-or-switch-to-eshell-4 magit-mode-map)

  ;; Allow gpg signing merge commits
  (magit-define-popup-option 'magit-merge-popup
                             ?S "Sign using gpg" "--gpg-sign="
                             #'magit-read-gpg-secret-key))

Viewing Github PRs and Issues

There's also a package called magit-gh-pulls that shows the pull requests when viewing the magit buffer

(use-package magit-gh-pulls
  :ensure t
  :init
  (add-hook 'magit-mode-hook #'turn-on-magit-gh-pulls)
  :config
  ;; work around https://github.com/sigma/magit-gh-pulls/issues/83
  (setq magit-gh-pulls-pull-detail-limit 50))

As an alternative to magit-gh-pulls, there is magithub

(use-package magithub
  :ensure t
  :disabled t
  :after magit
  :config
  (magithub-feature-autoinject t)

  ;; Workaround for https://github.com/vermiculus/magithub/issues/71
  (defun magithub-issue--sort (issues)
    "Sort ISSUES by issue number."
    (sort issues
          (lambda (a b) (> (plist-get a :number)
                      (plist-get b :number))))))

Visualizing git changes in a buffer

Quite useful, as well as the C-x n and C-x p bindings.

(use-package git-gutter
  :ensure t
  :when window-system
  :defer t
  :bind (("C-x P" . git-gutter:popup-hunk)
         ("C-x p" . git-gutter:previous-hunk)
         ("C-x n" . git-gutter:next-hunk)
         ("C-c G" . git-gutter:popup-hunk))
  :diminish ""
  :init
  (add-hook 'prog-mode-hook #'git-gutter-mode)
  (add-hook 'text-mode-hook #'git-gutter-mode)
  :config
  (use-package git-gutter-fringe
    :ensure t
    :init
    (require 'git-gutter-fringe)
    (when (fboundp 'define-fringe-bitmap)
      (define-fringe-bitmap 'git-gutter-fr:added
        [224 224 224 224 224 224 224 224 224 224 224 224 224
             224 224 224 224 224 224 224 224 224 224 224 224]
        nil nil 'center)
      (define-fringe-bitmap 'git-gutter-fr:modified
        [224 224 224 224 224 224 224 224 224 224 224 224 224
             224 224 224 224 224 224 224 224 224 224 224 224]
        nil nil 'center)
      (define-fringe-bitmap 'git-gutter-fr:deleted
        [0 0 0 0 0 0 0 0 0 0 0 0 0 128 192 224 240 248]
        nil nil 'center))))

Git-messenger allows you to look up the commit message for the last commit that touched the line wherever your current cursor is.

(use-package git-messenger
  :ensure t
  :commands git-messenger:popup-message
  :bind (("C-c M" . git-messenger:popup-message))
  :config
  (setq git-messenger:show-detail t))

A nice helper to browse code whenever it remotely may be, browse-at-remote

(use-package browse-at-remote
  :ensure t
  :commands browse-at-remote
  :bind ("C-c g g" . browse-at-remote))

Another nice thing is looking at the file through different revisions by checking out the same thing, but with git-timemachine.

(use-package git-timemachine
  :ensure t)

Git-annex integration

I've been back and forth on git-annex, but when I want to use it, I want to have it integrated into Emacs/magit when possible.

(use-package git-annex
  :ensure t)

(use-package magit-annex
  :ensure t)

Ediff

Ediff is fantastic for looking through diffs, and it's what magit can invoke on merge conflicts.

(use-package ediff
  :init
  (setq
   ;; Always split nicely for wide screens
   ediff-split-window-function 'split-window-horizontally)
  (defun ediff-copy-both-to-C ()
    (interactive)
    (ediff-copy-diff
     ediff-current-difference nil 'C nil
     (concat
      (ediff-get-region-contents
       ediff-current-difference 'A ediff-control-buffer)
      (ediff-get-region-contents
       ediff-current-difference 'B ediff-control-buffer))))
  (defun add-d-to-ediff-mode-map ()
    (define-key ediff-mode-map "d" 'ediff-copy-both-to-C))
  (add-hook 'ediff-keymap-setup-hook 'add-d-to-ediff-mode-map))

Smerge

Emacs has a nice built-in way of handling git conflicts, smerge-mode. There's a nice hydra I borrowed that allows you to run through conflicts pretty easily

(defhydra eos/hydra-smerge
  (:color red :hint nil
          :pre (smerge-mode 1))
  "
^Move^ ^Keep^ ^Diff^ ^Pair^
------------------------------------------------------
_n_ext _b_ase _R_efine _<_: base-mine
_p_rev _m_ine _E_diff _=_: mine-other
^ ^ _o_ther _C_ombine _>_: base-other
^ ^ _a_ll _r_esolve
_q_uit _RET_: current
"
  ("RET" smerge-keep-current)
  ("C" smerge-combine-with-next)
  ("E" smerge-ediff)
  ("R" smerge-refine)
  ("a" smerge-keep-all)
  ("b" smerge-keep-base)
  ("m" smerge-keep-mine)
  ("n" smerge-next)
  ("o" smerge-keep-other)
  ("p" smerge-prev)
  ("r" smerge-resolve)
  ("<" smerge-diff-base-mine)
  ("=" smerge-diff-mine-other)
  (">" smerge-diff-base-other)
  ("q" nil :color blue))

Author: Lee Hinman

Created: 2017-08-21 Mon 14:27