Configure Git Pairs with MagitΒΆ
Like me, you’ve probably used a git pair script at some point. There are a number of such scripts out there [1] and they all work the same way – creating a local git config with the pair author information.
While I used to be an avid user of the git cli, that’s changed since I switched to Magit. Unfortunately, I still need to do so when I want to setup my git pairing session. I decided to change that, partly to keep me from having to switch out of emacs but also as an exercise to improve my elisp chops.
Here are my requirements:
- Only override the commit author, not the committer.
- A single command to add the author override through the mini-buffer.
- A single command to remove the author override.
- A single command to toggle the author override.
- Persist the override across buffers.
- The overridden author value must be visible in the Magit commit popup.
After some code spelunking, I found that Magit exposes [2] the variable
magit-commit-arguments
, defined in git-commit.el
, which holds
a list of strings representing commit arguments. While it is
customizable, my requirements call for a user experience that’s little
more dynamic than setting an emacs custom variable. But, by using this
variable, I’ll satisfy requirements 1
, 5
and 6
. Time to
write some code to manipulate it!
First I’ll create a function named my/git-set-author
that
let’s me add an --author
commit argument.
(defun my/git-set-author (author)
"Sets the '--author' argument to the input author."
(when (not (string= "" author))
(add-to-list 'magit-commit-arguments (concat "--author=" author))
(minibuffer-message (concat "Author overridden with '" author "'"))))
This works but it’s not interactive, meaning it can’t be invoked from the minibuffer, and I won’t get prompt for input. It’s a good start, though so I’ll add another function that fills in the gaps.
(defun my/git-override-author ()
"Activates a git commit author override using the input author."
(interactive)
(let ((author (read-string "i.e., A U Thor <[email protected]>: "
my/magit-gc-override-author)))
(my/git-set-author author)))
The function my/git-override-author
is interactive and prompts
me with a message that’s a convenient reminder of the --author
format. This satisfies requirement 2
. Now that I can set it, I
need to be able to remove it. The function,
my/git-remove-author-override
will do that.
(defun my/git-remove-author-override ()
"Removes the '--author' commit argument."
(interactive)
(setq magit-commit-arguments
(remove-if (lambda (s) (string-match "--author" s))
magit-commit-arguments))
(minibuffer-message "Author override removed."))
Great, now I can add and remove overrides! That checks off requirement
3
. Time to add override toggling. To do that I’ll define the
variable my/magit-gc-override-author
to persist the author
override. I can then update my/git-override-author
to use it as
follows:
(defun my/git-override-author ()
"Activates a git commit author override using the input author."
(interactive)
(let ((author (read-string "i.e., A U Thor <[email protected]>: " my/magit-gc-override-author)))
(setq my/magit-gc-override-author author)
(my/git-set-author author)))
Now I can implement my/git-author-toggle
to check of requirement 4
.
(defun my/git-author-toggle ()
"Toggles the git commit author override."
(interactive)
(if (find-if (lambda (s) (string-match "--author" s)) magit-commit-arguments)
(my/git-remove-author-override)
(my/git-set-author my/magit-gc-override-author)))
Finally, I’ll tie it all together through some keybindings that get
set when Magit is initialized. I really like use-package
for
things like this.
(use-package magit
:bind (("C-c C-p" . my/git-override-author)
("C-c C-u" . my/git-remove-author-override)
("C-c C-t" . my/git-author-toggle)))
;; Require 'magit-commit otherwise magit-commit-arguments won't be
;; initialized until you first try to commit something.
(require 'magit-commit)
In the future I’ll probably add some niceties like support for selecting known pairs and support for pair initials but this is good enough for now.
The full implementation can be found in my emacs config [3] [4]. I’ve got some other goodies in there but, as you peruse my config, keep in mind that I use the Prelude Emacs distribution.
Cheers!
/Dan
Footnotes
[1] | Here are a few: pivotal/git_scripts, ryanbriones/git-pair, peterjwest/git-pair. |
[2] | Check out the source. |
[3] | I suppose this goes without saying, but never lift config without understanding what it does first! |
[4] | I’m constantly mucking with my Emacs configuration. It’s like a virtual garden that requires constant tending. |