Git Patches
A Git patch is a plain-text file that describes one or more sets of changes. It combines a unified diff (the actual code changes) with metadata — commit message, author, date — formatted so it can be emailed, reviewed on paper, or applied to a repository that has no network connection to the original. Patches are the oldest collaboration primitive in distributed version control and remain a first-class workflow in projects like the Linux kernel.
Two patch formats in Git
Format | Command | Includes commit metadata? | Apply with |
|---|---|---|---|
Unified diff |
| No — just the raw diff |
|
Mailbox (mbox) |
| Yes — author, date, subject, message |
|
Creating a patch with git format-patch
git format-patch generates one .patch file per commit. Each file is formatted as an email-ready mbox message containing the full commit metadata plus the diff.
# Generate a patch for the most recent commit git format-patch -1 HEAD # Generate a patch for a specific commit git format-patch -1 a1b2c3d # Generate patches for all commits on current branch not in main git format-patch main # Generate patches for a range git format-patch main..feature/new-auth # Output to a specific directory git format-patch main -o /tmp/patches/
Files created
0001-feat-add-OAuth2-login-flow.patch 0002-fix-handle-empty-user-list.patch 0003-docs-update-API-reference.patch
The files are numbered in order and named from the commit subject — perfect for attaching to an email thread in order.
Anatomy of a format-patch file
0001-feat-add-OAuth2-login-flow.patch
From a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0 Mon Sep 17 00:00:00 2001
From: Alice <alice@example.com>
Date: Tue, 20 May 2026 14:32:00 +0000
Subject: [PATCH 1/3] feat: add OAuth2 login flow
Add support for Google and GitHub OAuth2 providers.
Tokens are stored in httpOnly cookies.
---
src/auth/oauth.ts | 54 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
create mode 100644 src/auth/oauth.ts
diff --git a/src/auth/oauth.ts b/src/auth/oauth.ts
new file mode 100644
index 0000000..1a2b3c4
--- /dev/null
+++ b/src/auth/oauth.ts
@@ -0,0 +1,54 @@
+import { createOAuthHandler } from './base'
+
+export const googleOAuth = createOAuthHandler({
...
--
2.44.0The --- divider separates the commit message body from the diff stats. The -- at the end marks the end of the email and shows the Git version that generated the patch.
Useful format-patch flags
Flag | Effect |
|---|---|
| Generate patches for the last N commits. |
| Write patch files to the specified output directory. |
| Print all patches to stdout (one combined mbox) instead of separate files. |
| Change the subject prefix from the default |
| Generate a |
| Always include [N/M] numbering even for a single patch. |
| Record the base commit for easier cherry-pick on the recipient side. |
| Add |
Cover letters for patch series
For a series of patches (more than one commit), always include a cover letter that explains the overall intent of the series.
git format-patch main --cover-letter -o /tmp/patches/
Generated files with cover letter
0000-cover-letter.patch ← fill in Subject: and body 0001-feat-add-OAuth2-login-flow.patch 0002-fix-handle-empty-user-list.patch
0000-cover-letter.patch (fill in manually)
From: Alice <alice@example.com> Subject: [PATCH 0/2] Add OAuth2 authentication *** SUBJECT HERE *** *** BLURB HERE *** Alice (2): feat: add OAuth2 login flow fix: handle empty user list src/auth/oauth.ts | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/auth/session.ts | 8 ++++---- 2 files changed, 58 insertions(+), 4 deletions(-)
Applying patches with git am
git am ("apply mailbox") applies one or more format-patch files, preserving the original author name, email, date, and commit message. It creates real commits, not just working tree changes.
# Apply a single patch git am 0001-feat-add-OAuth2-login-flow.patch # Apply all patches in a directory (in order) git am /tmp/patches/*.patch # Apply from stdin cat *.patch | git am # Apply and add a Signed-off-by trailer git am --signoff 0001-feat-add-OAuth2-login-flow.patch
Successful apply output
Applying: feat: add OAuth2 login flow Applying: fix: handle empty user list
Handling conflicts in git am
Failed apply output
Applying: feat: add OAuth2 login flow error: patch failed: src/auth/oauth.ts:12 error: src/auth/oauth.ts: patch does not apply Patch failed at 0001 feat: add OAuth2 login flow hint: Use 'git am --show-current-patch' to see the failed patch hint: When you have resolved this problem, run "git am --continue". hint: If you prefer to skip this patch, run "git am --skip". hint: To restore the original branch and stop patching, run "git am --abort".
# See which patch failed git am --show-current-patch # Option 1 — Resolve manually git apply --reject 0001-feat-add-OAuth2-login-flow.patch # Edit the .rej file contents into the target file vim src/auth/oauth.ts git add src/auth/oauth.ts git am --continue # Option 2 — Skip this patch and move to the next git am --skip # Option 3 — Abort and restore the branch git am --abort # Use 3-way merge to resolve conflicts automatically where possible git am -3 0001-feat-add-OAuth2-login-flow.patch
git apply vs git am
Aspect |
|
|
|---|---|---|
Input format | Unified diff (from | Mbox format (from |
Creates a commit | No — stages or applies to working tree only | Yes — creates a commit with original metadata |
Preserves author/date | No | Yes |
Conflict handling |
|
|
Use case | Quick local patches, testing diffs | Applying submitted patches to a project |
Creating and applying unified diffs
# Create a diff of all unstaged changes git diff > my-changes.patch # Create a diff of all staged changes git diff --cached > staged.patch # Create a diff of a specific commit range git diff v1.0..v1.1 > v1.0-to-v1.1.patch # Apply a raw diff to the working tree (no commit) git apply my-changes.patch # Apply and immediately stage git apply --cached my-changes.patch # Check if a patch will apply cleanly without actually applying git apply --check my-changes.patch # Apply even if whitespace differences exist git apply --whitespace=fix my-changes.patch
Inspecting patches before applying
# See what a patch will do without applying it git apply --stat 0001-feat-add-OAuth2-login-flow.patch git apply --check 0001-feat-add-OAuth2-login-flow.patch # Read the commit metadata from a format-patch file git mailinfo /tmp/msg /tmp/diff < 0001-feat-add-OAuth2-login-flow.patch cat /tmp/msg # author, date, subject cat /tmp/diff # the actual diff
The Linux kernel patch workflow
The Linux kernel does not use GitHub pull requests. Contributions are sent as patches via email to mailing lists, reviewed by maintainers, and applied with git am. This workflow scales to thousands of contributors without centralised infrastructure.
Fork the kernel tree and create your changes on a branch.
Run
git format-patch --cover-letter -v1 -o patches/ linus/master..HEAD.Edit the cover letter to describe the series.
Send the patches to the appropriate subsystem mailing list with
git send-email.Maintainers review the patches inline in email.
After revisions, send
v2patches:git format-patch --subject-prefix="PATCH v2".A maintainer applies accepted patches:
git am patches/*.patch.The maintainer's tree is pulled up the tree toward Linus's tree.
git send-email overview
git send-email sends format-patch files directly from the command line as emails. It is the standard tool for kernel-style email-based patch submission.
# Install: on Ubuntu/Debian sudo apt-get install git-email # Configure your SMTP server once 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 your@gmail.com
# Generate patches git format-patch -3 --cover-letter -o /tmp/patches/ # Dry run — see what would be sent without actually sending git send-email --dry-run /tmp/patches/ # Send to a mailing list git send-email --to="linux-kernel@vger.kernel.org" --cc="maintainer@example.com" /tmp/patches/
send-email interactive prompts
Who should the emails appear to be from? [Alice <alice@example.com>] Who should the emails be sent to? linux-kernel@vger.kernel.org Message-ID to be used as In-Reply-To for the first email? (sending cover letter) OK. Log says: Sendmail: /usr/sbin/sendmail -oi -f alice@example.com ... From: Alice <alice@example.com> To: linux-kernel@vger.kernel.org Subject: [PATCH 0/3] feat: add power management hooks ...
When to use patches
No shared remote: applying changes to a server with no network access, by copying a
.patchfile via SSH or USB.Email-based review: sending a change for review without requiring the reviewer to clone your repo or use a hosted platform.
Offline collaboration: exchanging changes on air-gapped systems.
Preserving authorship: applying someone else's change and keeping their name as the author (
git amvsgit apply).Backporting: generating a patch from one release branch and applying it cleanly to an older one.
Archiving a specific change: a self-contained
.patchfile that can be stored with a bug report.
Common errors
Error | Cause | Fix |
|---|---|---|
| The file has changed since the patch was generated — context lines do not match. | Use |
| The commit you tried to format has no diff (empty commit). | Use |
| Trying to apply a patch to an unborn branch. | Create an initial commit first. |
| The patch file was mangled (e.g., email client wrapped lines or converted line endings). | Use |