Primer on formatting Git patches with Emacs (Magit)
As noted in a previous publication, I am moving all my projects to SourceHut, starting with my Emacs packages (Manuel Uberti is doing the same and maybe others will follow suit). I perform this migration because I prefer an email-centric workflow, which basically is a fancy way of admitting that I want to consolidate everything inside of Emacs. Part of this workflow involves the use of standard Git facilities to make contributions to projects. Unlike certain web UIs that have you “fork” a project and request a pull of your changes, there is the decentralised way of committing your edits as usual and sharing them with the project as patch files. The maintainers then apply those with or without further tweaks (e.g. emacs.git works this way). No more faux forks!
What follows is a short guide to help you get started. My
package shall serve as an example. I think Magit is all you will ever
need to handle most (all?) such processes, though I also include the
relevant command-line part for the sake of completeness. This is
supposed to be for beginners who already know the basics of Git and who
are using Magit. It is not an exhaustive resource. Consult the
official documentation for the technicalities.
denote package, we have these:
- Git repository: https://git.sr.ht/~protesilaos/denote.
- Mailing list: https://lists.sr.ht/~protesilaos/denote. When you write an email, it is addressed to ~firstname.lastname@example.org as noted in the list’s description.
Clone the git repo as usual: https://git.sr.ht/~protesilaos/denote.
If you already have a local copy of the repository, make sure it is up-to-date. Use
git pullif necessary.
Commit your changes the way you always do. You can conduct this operation on a separate branch, if you will, though using the main one is perfectly fine. I only ever work on the target branch for such cases: if my patch is not accepted or if I change my mind, I simply revert the changes.
- If you plan to make several changes, split your contribution in to as many commits, one per conceptual edit. This makes it easier for you to have a clear understanding of your patch set, but also for the maintainers to review the code and apply it on a case-by-case basis.
Now that you have made your commits, it is time to format them as patches. A “patch” typically is a standard file. The maintainer can then directly apply that file (“install the patch”, as we say) in their copy of the Git repo.
If you are using Magit, type
c. In the transient pop-up buffer, you can now press
C-m oto specify an output directory. Otherwise it uses the one you are in. When you are ready, hit the final
cwhich will produce a prompt to “Format range or commit”. Your obvious options are the available refs. Just select the branch you are on (e.g.
main) which means to use the latest commit on that branch. It will produce a file with the
.patchextension. This is what we are looking for.
You can follow a similar process to format a range of commits as a patchset. Display the commit log (such as with
l l), select the region that includes the desired changes and type the aforementioned sequence of
W c c(with
C-m oto change the output path, if needed). You will get a patch per commit. Voilà!
Without Magit, we do this on the command line (I have a do-what-I-mean (DWIM) Elisp code for this and for applying patches which is part of my dotemacs’
prot-vc.elfile, but I need to polish it and share it as a formal package or patchset for
vc-git.el). The gist is as follows, per the
git format-patch HASH --output-directory PATH
-o) part is optional. For a range of commits, the commit
HASHvalue should be in the form of
OLDER-HASH..NEWER-HASH. Give it a try. It will produce files for each commit in that range. Important caveat here is that the
OLDER-HASHis not part of the range. So if you want it to be included, use the one prior to it.
UPDATE 2022-04-11 07:46 +0300: As Sean Whitton points out in an email, it probably is easier to use the
-Nflag instead of specifying a range of commits, where
Nis the number of commits counting from the
HEAD(this information from the email exchange is shared with permission):
git format-patch -3
.patchfiles in place, all that remains is to prepare an email and include those files as attachments (there is also a way to send patches directly as an email, but I think standalone files are easier for the occasional contribution—check this detailed guide: https://git-send-email.io/). Compose your regular message and send the files to the maintainer’s email address or to the mailing list of the given project. In our example, the latter is found here: https://lists.sr.ht/~protesilaos/denote (the link includes the exact email address of the list). The advantage of the mailing list is that it is public, so others have a chance to review the discussion and/or store a copy of it.
Depending on the project, the mailing list will be the only option. Though I am okay if I receive patches for my packages in my personal email address.
The subject line of the email can start with the “[PATCH]” keyword to make things simpler. If your patch is just one file, you can copy the subject line it already has, which includes the one-line description of the commit, like “[PATCH] Update the doc string of some-function”.
You did it! The maintainer will take care of the rest.
UPDATE 2022-04-28 15:31 +0300: SourceHut’s web UI for mailing lists does not display indicators for attached files. The information is still available in the mbox version of the discussion. I consider this unfortunate and too advanced of a use-case. I have started a discussion on this topic, as I think a simple indicator would be helpful for those who are not subscribed to the given list.
The git-email Emacs package by Xinglu Chen is a tool I have used a few times to format and send patches as email files. This may be a bit more advanced, but you might want to check it out.
UPDATE 2022-04-28 15:32 +0300: Note my pending changes for
and revised patch for project.el integration on Emacs
For those who assume the role of applying patches from email contributions, Xinglu recommends Kyle Meyer’s piem Emacs package, though I have not used it yet.
notmuch.el, such as myself, may also want to check out Sean
Whitton’s mailscripts project
which includes a
mailscripts.el file. As with
piem, I have it on my
to-do list, but have yet to find the time to refine my toolkit…
My projects and copyright assignment to the FSF
All my projects and concomitant mailing lists are here (work-in-progress, as I am still migrating the repos and making all the relevant changes):
Note that I have assigned copyright to the Free Software Foundation and
all my Emacs-related packages require you to do the same before making
any major contribution. Contact me
if you need help on that front or ask for a copyright assignment form
from the kind folks over at the emacs-devel mailing list by sending an
email to email@example.com. It looks like this (again, using the
denote package as a demo):
Please email the following information to firstname.lastname@example.org, and we will send you the assignment form for your past and future changes. Please use your full legal name (in ASCII characters) as the subject line of the message. REQUEST: SEND FORM FOR PAST AND FUTURE CHANGES [What is the name of the program or package you're contributing to?] GNU Emacs [Did you copy any files or text written by someone else in these changes? Even if that material is free software, we need to know about it.] [Do you have an employer who might have a basis to claim to own your changes? Do you attend a school which might make such a claim?] [For the copyright registration, what country are you a citizen of?] [What year were you born?] [Please write your email address here.] [Please write your postal address here.] [Which files have you changed so far, and which new files have you written so far?] denote.el (GNU ELPA)