DEV Community

Jeremy Friesen for The DEV Team

Posted on • Originally published at on

Further Hacking on Emacs for Github Pull Requests

You Ain't Emacs-ing if You Ain't Always Hacking Your Config

I wrote Emacs Function to Open Magit Log PR at Point. Over on Reddit, a user asked about not requiring git-link dependency nor browse-url-default-macosx-browser.

Since then, I’ve split apart the functions and added another use case. First and foremost, the magic “open the pull request associated with a commit” relies on an implementation feature of Github’s “Squash and merge” command. That command creates a commit with a summary (e.g., the first line of the commit message) that is the pull request’s title and the associated pull request.


With that as a caveat, there are five functions that I’ve written to help jump to pull requests on Github:

  • jnf/git-current-remote-url
  • jnf/open-pull-request-for
  • jnf/magit-browse-pull-request
  • jnf/open-pull-request-for-current-line
  • jnf/git-messenger-popup


The following Elisp: dialect of Lisp used in GNU Emacs (Elisp 🔍) code defines the jnf/git-current-remote-url function which gets the current remote url (for the given branch).
It’s usually “origin.”

(defun jnf/git-current-remote-url ()
  "Get the current remote url."
     "git remote get-url "
     (format "%s" (magit-get-current-remote))))))
Enter fullscreen mode Exit fullscreen mode


The following elsip code defines jnf/open-pull-request-for, which takes the named parameter :summary. If that :summary contains a pull request number, opens the pull request in an external browser.

(cl-defun jnf/open-pull-request-for (&key summary)
  "Given the SUMMARY open the related pull request."
  (let ((remote-url (jnf/git-current-remote-url)))
      (and (string-match "(\\#\\([0-9]+\\))$" summary)
             ;; I tend to favor HTTPS and the
             ;; repos end in ".git"
             (s-replace ".git" "" remote-url)
             (match-string 1 summary)))))))

Enter fullscreen mode Exit fullscreen mode


The following Elisp code defines jnf/magit-browse-pull-request, which will open the associate pull request when your point is on a Magit 🔍 log entry.
I’ve mapped that to s-6 (or Cmd+6)

(defun jnf/magit-browse-pull-request ()
  "In `magit-log-mode' open the associated pull request
at point.

Assumes that the commit log title ends in the PR #, which
is the case when you use the Squash and Merge strategy.

This implementation is dependent on `magit' and `s'."
  (let* ((beg (line-beginning-position))
         (end (line-end-position))
           beg end)))
    (jnf/open-pull-request-for :summary summary)))
Enter fullscreen mode Exit fullscreen mode


The following Elisp code defines jnf/open-pull-request-for-current-line. When invoked, this function will open the pull request for the commit associated with the current line.
It does that by using git annotate on the current line, and pulling the commit’s summary via ripgrep.

(defun jnf/open-pull-request-for-current-line ()
  "For the current line open the applicable pull request."
  (let ((summary
           (concat "git --no-pager annotate "
                   "-L "
                   (format "%s" (line-number-at-pos))
                   ",+1 "
                   "--porcelain "
                   " | rg \"^summary\"")))))
    (jnf/open-pull-request-for :summary summary)))
Enter fullscreen mode Exit fullscreen mode


The following Elisp code defines jnf/git-messenger-popup. When invoked it launches the git-messenger popup.

(defun jnf/git-messenger-popup ()
  "Open `git-messenger' or github PR.

With universal argument, open the github PR for
current line.

Without universal argument, open `git-messenger'."
  (if (equal current-prefix-arg nil) ; no C-u
Enter fullscreen mode Exit fullscreen mode

I have mapped the function to s-6 (e.g., Cmd+6 on OS X 🔍).

If I first pass the universal argument, that is I first type C-u then s-6 (or Ctrl+u then Cmd+6 in OS X) I will open that line’s pull request.
When in the git-messenger’s popup, I can type p to go to that line’s pull request.


I wrote these functions to better help me better understand Forem’s codebase. It was also a chance to continue practicing coding and learning.

If you’re interested, you can see more of my git configuration on Github

Top comments (0)