Sending patches via email with Git

When thinking about working with a friend on a small project, we instinctively create a repository on GitHub or GitLab. This practice, or reflex, is relatively modern. But although it may seem strange, you can collaborate on projects without using Git hosting services. Though it may seem unthinkable, these services didn't exist before, and software was developed with equal or better quality.

The workflow consists of connecting git with your email, or sending patches to the maintainer's inbox. Git is designed to support this workflow natively, it contains a set of tools to facilitate each of the steps. In fact, it's used today by very important projects like the Linux kernel, QEMU, GNU, or Git itself. Don't think for a moment that it's an obsolete or outdated method.

Its advantages are several:

  • You don't depend on a specific platform (GitHub, GitLab, etc).
  • A copy of discussions and patches between developers is kept in public mailing lists.
  • You can review code offline (if you've downloaded the emails).
  • It's a very quick workflow to master.

But of course, it also has its downsides:

  • It's not as visual as using a Git hosting service (GitHub, GitLab, etc).
  • It requires knowing some extra Git tools.
  • The maintainer must manage patches and reviews by email.
  • If you want it to be open, you need a public mailing list.
  • It's not as simple for beginners.

And with that said, prepare your coffee because we're going into action.

Initial Setup

Before jumping into sending patches, you need to prepare your environment.

1. Configure your identity

First, make sure Git knows your name and email. This data will appear in your commits and in the headers of the patches you send. It's basic even if you don't want to send patches by email.

git config --global user.name "Your Name"
git config --global user.email "youremail@example.com"

2. Install git-send-email

git-send-email is the tool you'll use to send patches directly from the terminal. It's optional since you can use your email client, but it's much more convenient and avoids formatting errors.

It doesn't come installed by default on all distributions, so you'll need to install it manually:

# Debian/Ubuntu
sudo apt install git-email

# Fedora
sudo dnf install git-email

# Arch
sudo pacman -S git-send-email

If you use macOS or Windows, you may or may not already have it included with Git. I'll let you investigate.

3. Configure the SMTP server

To send emails you need to connect to an SMTP server. Here I show you typical Gmail configurations, but you'll need to adapt them to your provider if you use another one.

Gmail:

git config --global sendemail.smtpserver smtp.gmail.com
git config --global sendemail.smtpserverport 587
git config --global sendemail.smtpencryption tls
git config --global sendemail.smtpuser youremail@gmail.com

Note that Gmail requires an app password. Don't use your normal password, generate a specific one for this tool.

With this, you're all set to send patches by email. Let's send our first patch.

Creating and Sending a Patch

Now comes the interesting part: making changes to the code and sending them as a patch.

1. Prepare your environment

Clone the repository of the project you want to contribute to and create a new branch for your work:

git clone https://example.com/repo.git
cd repo
git switch -c my-fix

2. Make changes and create a commit

Modify the files you need.

Use the -s flag when making the commit: this automatically adds the Signed-off-by line with your name, which is mandatory in many projects as a way to accept the license.

Signed-off-by is not a cryptographic signature, but a declaration that you accept the project's terms. It will include your name and email address as you have it configured in Git.

git add modified-file.py
git commit -s

It's widespread that messages follow a specific structure, although it's completely optional. The typical structure is: brief summary on the first line, blank line, detailed explanation in several lines, another blank line, and finally Signed-off-by (which is added automatically with the -s flag).

component: brief description (max ~50 characters)

Detailed explanation of the change. Here you can expand
explaining the reason, context, and any relevant details.

Signed-off-by: Your Name <youremail@example.com>

3. Generate the patch

Now comes the technical part: converting your commits into patch files. Git includes the format-patch command that does exactly that.

git format-patch -1 HEAD          # last commit
git format-patch -3 HEAD          # last 3 commits
git format-patch origin/main      # all commits since main

These commands generate .patch files in your current directory. Each one contains a commit.

4. Send your patch

You have 2 options, depending on your preference.

Option A: git send-email

If you've followed the previous steps, configuring git with your email provider's SMTP configuration, you can send them directly with the command:

git send-email --to=maintainer@project.org *.patch

It takes care of everything. It's the most recommended way since it will prevent your email client from messing up the format.

When your contribution requires several related commits, you can send them as a series. Git facilitates this with the --cover-letter option, which generates an introductory email where you explain the set of changes.

git format-patch --cover-letter origin/main

This generates several files: 0000-cover-letter.patch and one for each commit. Edit the cover letter file to explain what your patch series does and why it's necessary.

Then send everything together:

git send-email --to=maintainer@project.org *.patch

Reviewers will receive your cover letter first and then each patch as a response to that thread. It keeps the conversation organized.

Option B: Email client

If for some reason you can't use send-email, you can do it manually:

  1. Generate the patch: git format-patch -1 HEAD --stdout > patch.txt
  2. Copy the content into a new email
  3. Send it in plain text, never in HTML

⚠️ Many clients modify whitespace and break the patch format.

Revised Versions

There's a good chance the maintainer will ask you for changes. It's part of the process!

When you need to send a corrected version, follow these steps:

1. Modify your code

Make the changes you need to make and add them to staging.

git add file.lisp

2. Modify the previous commit

To modify the previous commit, run:

git commit --amend

It will open the editor to modify the message.

If you don't want to do that, preserving the current message:

git commit --amend --no-edit

3. Create a new version of the patch

We'll create version 2 of the previous commit.

git format-patch -v2 -1 HEAD

4. Send the modified patch

Everything is ready to send it, although we'll add some modifications.

git send-email \
  --to=maintainer@project.org \
  --in-reply-to="<original-message-id>" \
  v2-*.patch

The -v2 flag adds a [PATCH v2] prefix to the email subject, making it clear it's a new version. And the --in-reply-to parameter makes your email appear as a response to the original thread, keeping all the context together.

Now you just have to wait.

Conclusions

Of course, it has a learning curve. Configuring SMTP, understanding format-patch, remembering to add -s in commits. But once you master it, it's as natural as using git locally. You don't depend on any platform or free tiers that dance to the whims of the wind. Email has been around since the 70s and will still be here when trendy platforms change. A workflow that allows thousands of developers to collaborate without saturating any centralized server. It's no coincidence that projects as important as the Linux kernel still use it.

I hope this small introduction helps you collaborate on Opensource projects that would otherwise seem unreachable.

This work is under a Attribution-NonCommercial-NoDerivatives 4.0 International license.

Will you buy me a coffee?

Comments

There are no comments yet.

Written by Andros Fenollosa

January 22, 2026

6 min of reading

You may also like

Visitors in real time

You are alone: 🐱