Image of git format-patch | Create a patch in Git

ADVERTISEMENT

Table of Contents

Introduction

Most development teams sync commits directly between their local and remote repositories using the git push and git pull commands. When using these commands, Git uses either the SSH or HTTPS protocol to perform data transfers between the two endpoints.

However, some project maintainers - including major open source projects such as Linux and Git itself - prefer to work via email instead. Git has a set of subcommands that are specifically designed for distributed collaboration via email.

For commits to be relayed effectively over email, they need to be formatted as text entities in a standardized format. The git format-patch command assists with this process.

In this article, we explain how to use the git format-patch command to prepare one or more commits to be transferred by email.

What is a Git patch?

A patch in Git is a textual representation of the changes in a commit, formatted in a way that Git can reconstruct the commit and apply it on a branch in another repository.

Git patch format

Git creates each patch in a new file with a .patch extension in your current directory. Git patches have the following format:

From 21e6b1b3700970fdc2382e01d6da723e51b007b5 Mon Sep 17 00:00:00 2001
From: Jacob Stopak <jacob@initialcommit.io>
Date: Thu, 20 Oct 2022 22:12:00 -0700
Subject: [PATCH] Update filename

---
 filename | 1 +
 1 file changed, 1 insertion(+)

diff --git a/filename b/filename
index 01a9f34..b9022e5 100644
--- a/nf
+++ b/nf
@@ -1,3 +1,4 @@
 asdf
+asdf
-- 
2.38.0

This may look a bit complicated, but really it is just a way for Git to understand the following information directly from the patch itself:

  1. The commit id that the patch was derived from:
From 21e6b1b3700970fdc2382e01d6da723e51b007b5 ...
  1. The commit author and email (sender of the email patch):
From: Jacob Stopak <jacob@initialcommit.io>
  1. The date the patch was generated:
Date: Thu, 20 Oct 2022 22:12:00 -0700
  1. The subject line of the email, which is set to [PATCH] followed by the commit message:
Subject: [PATCH] Update filename
  1. A diffstat representing the changes between the commit and its parent:
---
 filename | 1 +
 1 file changed, 1 insertion(+)

diff --git a/filename b/filename
index 01a9f34..b9022e5 100644
--- a/nf
+++ b/nf
@@ -1,3 +1,4 @@
 asdf
+asdf
-- 
  1. The Git version that was used to generate the patch:
2.38.0

When this patch is sent to another developer over email, they can use Git on their end to reconstruct the commit and apply to a branch in their repository.

What is git format-patch?

git format-patch is a Git command that automatically generates patches between each commit and it's parent, for a given set of commits. These patches are formatted such that they can easily be shared over email, so that the recipient can apply those commits to their own repository.

How to create a Git patch?

Creating a patch is a simple as running git format-patch <commit> in your local Git repo.

You can specify the commit using it's commit id, any branch or tag name, or a variation of Git HEAD such as HEAD^ for the previous commit.

After running the command, you'll see one or more .patch files generated in your current directory containing the patch data. The file names are prefixed with a 4-digit number indicating their order in the patch series, followed by a hyphen-separated string created using the commit message. For the format used above, this would be:

0001-Update-nf-again.patch

What does format-patch do?

By default, running git format-patch will generate a patch for each commit starting with the specified commit, and ending with the currently checked-out commit.

One patch is generated per commit based on the diff between each commit and its parent.

Note that patches are not generated for merge commits, so ideally you should rebase your feature into a single line of history to generate a clean set of patches.

As mentioned, one .patch file is generated for each commit in your patch series.

git format-patch example

You can format Git patches for one commit at a time, or for multiple commits at once. We'll start with formatting patches for multiple commits since that is a more common scenario.

git-format patch multiple commits

By default, when you run the standard git format-patch <commit>, a patch will be created for each commit starting at the one you specified with <commit>, up until the current HEAD is reached. Therefore, you'll usually end up with more than 1 patch being created, unless you start generating at HEAD^ (aka HEAD~1), which is the commit previous to the currently checked out HEAD.

Note that this means no patches will be created for commits previous to the <commit> that you specified.

Alternatively, you can use the --root flag to instead create patches for all commits from beginning or your commit history, up until the specified <commit>.

Specifying multiple commits with Git revision range

Another way to generate multiple patches is to specify a range of revisions, as follows:

$ git format-patch <commit1>..<commit2>

This will create patches for all commits between <commit1> and <commit2>.

See Git's documentation on specifying revision ranges for more examples of valid revision range syntax.

git-format patch from single commit

Now let's move on to formatting patches for a single commit. You can generate exactly one patch for the specified commit by using the -1 flag:

$ git format-patch -1 <commit>

What is the format of a Git patch?

Earlier in this post, we showed a sample format for a email patch in Git. Let's expand on that. You can think of each patch file as being a message - and it really is since it's meant to be emailed as a message to another dev.

This message starts with an email header that includes the "From:", "Date:", and "Subject:" fields. Note that the subject field contains the first line from the commit message of the corresponding commit.

Next comes the remaining lines (if there are any) of the commit message. Our example format above does not include more lines in the commit log message.

After this, there is a 3-hyphen delimiter, separating the commit message from the patch content itself.

Lastly, we have the actual diffstat output, which represents the meat of the patch. This is actually the output of the diff -p --stat command. Feel free to check out our git diff article for more details.

When should I format a git patch?

You should format a patch in Git any time you want to send one or more commits to another person by email. This could simply be to get their input or review on your proposed code changes.

It could also be to share a commit with a project maintainer for them to integrate into their own branch.

How can I see my git patch?

You can see your patch files in your current directory by running the ls command in Linux or MacOS. In Windows you can use the dir command. Alternatively, you can see your patches listed in your file explorer in any operating system.

Keep in mind that if you are generating a long patch series with many patches, you may want to put them in their own subdirectory using the -o option:

$ git format-patch -o <new-feature-subdirectory> <commit>

The specified subdirectory will be created if it doesn't yet exist.

This can be useful for grouping together patches related to a specific feature, so you can make sure to only mail out those patches together and no others by accident.

How do I view a patch file?

Since Git patches are just text files with a .patch extension, you can view them with any text editor. This could be a command-line text editor like Vim or your favorite GUI editor.

git format-patch HEAD

You might notice that if you try to run git format-patch on its own or git format-patch HEAD, you won't get any output and no patch will be created.

That's because there are no differences between the specified patch (HEAD) and the current commit (which is also HEAD). So you are confused by this, just realize you need to specify a commit earlier on in the branch history.

Adding a cover letter

In addition to creating your patches, you can generate a Git cover letter which you can email as an overarching summary of your patch series.

The cover letter is also a .patch file created with filename 0000-cover-letter.patch by default.

It contains the following information:

  • Custom description of the patch series
  • The git shortlog output
  • The full patch series diffstat
  • The Git version used to generate the cover letter

Here is an example cover letter, for which you can fill in the fields with asterisks:

$ git format-patch --cover-letter HEAD~2
0000-cover-letter.patch
0001-Revert-Revert-Add-qwer.patch
0002-Revert-Add-qwer.patch

$ cat 0000-cover-letter.patch
From c1033c71d0a6f136dab2abeaea4eae9c200dae6d Mon Sep 17 00:00:00 2001
From: Jacob Stopak <jacob@initialcommit.io>
Date: Wed, 26 Oct 2022 09:30:39 -0700
Subject: [PATCH 0/2] *** SUBJECT HERE ***

*** BLURB HERE ***

Jacob Stopak (2):
  Revert "Revert "Add qwer""
  Revert "Add qwer"


-- 
2.38.0

Summary

In this article, we described the purpose Git's format patch command and explained how it works.

We learned how to format a Git patch and when to do so. We saw that a patch in Git is just a textual representation of a diff between a commit and its parent. These diffs are formatted in a standardized way that makes them convenient to send over email.

If you've never tried Git email collaboration, why not give it a try and see if it suits your team's workflow?

Next Steps

If you're interested in learning more about how Git works under the hood, check out our Decoding Git Guidebook for Developers, which dives into Git's code in an accessible way. We wrote it for curious developers to learn how Git works at the code level. To do this, we documented the first version of Git's code and discuss it in detail.

We hope you enjoyed this post! Feel free to shoot me an email at jacob@initialcommit.io with any questions or comments.

References

  1. Git SCM Specifying Revision Ranges - https://git-scm.com/docs/gitrevisions#_specifying_ranges
  2. Git SCM format-patch command - https://git-scm.com/docs/git-format-patch

Final Notes