git create patch means turning a set of code changes into a portable file — a git
patch file — that someone else can apply to their own working tree without cloning your repo, seeing
your branch, or touching your commit history at all. Two commands cover the whole job: redirect
git diff to a file for a quick git diff patch, or run git format-patch when
you want each commit to carry its own author, date, and message. This guide covers both ways to
generate a patch file — the ones git developers actually reach for — how to apply a git patch with
git apply or git am, how to grab a github patch straight off a pull request
URL, and — the part most patch tutorials skip entirely — how to actually read an untrusted patch
before you let it touch your working tree. For the diff format itself, line by line, see
the guide to unified diff format; this one is about turning
that format into a file you can generate, share, inspect, and apply.
The Fast Answer: Creating a Git Patch in Two Commands
To create a patch, redirect a diff to a file; to apply it, hand that file to git apply. That's the entire operation when you just need to move a change from one working tree to another.
# Create a patch from whatever's changed in your working tree
git diff > my-changes.patch
# Apply it — on this machine, another clone, or someone else's
git apply my-changes.patch Whatever you call the process — git patch, git create patch, git generate patch, git make patch, or on GitHub specifically github generate patch — the mechanics reduce to two steps: make the patch, then apply it. How to apply a git patch you didn't create yourself is exactly as short, once you have the file in hand and you've confirmed it's safe (covered in read the patch before you apply it further down):
# A .patch file downloaded from a GitHub PR, applied straight in
curl -L https://github.com/owner/repo/pull/123.patch | git am A git diff patch and a format-patch patch look almost identical on the inside — both are unified diffs — but they carry different metadata and get applied with different commands. Create patch file git, apply github patch, github patch file — these phrasings all point at the same handful of commands; the sections below work through each one in full, then cover generating, reading, applying, reversing, and troubleshooting a git patch file end to end.
What a Git Patch File Actually Is
A patch file is plain text describing how to turn one version of a file into another — nothing more. It isn't a binary format, it isn't git-specific at the byte level, and you can open one in any text editor and read exactly what it does before running anything against it.
diff --git a/src/config.ts b/src/config.ts
index 3b4c5d6..f4a9c21 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -12,3 +12,5 @@ export const config = {
timeout: 3000,
retries: 3,
+ backoff: 500,
+ maxBackoff: 5000,
};
Reading it top to bottom: diff --git a/... b/... names the file on each side (git always
uses a/ and b/ prefixes here, regardless of your actual directory names);
index records the before/after blob hashes and the file mode; --- and
+++ repeat the file paths in the format the hunks below reference; and each
@@ -12,3 +12,5 @@ line is a hunk header — the numbers are starting line and line count
for the old and new versions of that region. Lines starting with a space are unchanged context,
- is a removed line, + is an added one. This is the unified diff format at
its core; the dedicated guide covers every header variant and
edge case if you want the full spec rather than the working summary.
What makes it a git patch file specifically, rather than a plain POSIX diff, is mostly the
header — the diff --git line, the index line, and (when generated with
git format-patch) an email-style header block above the diff carrying commit metadata.
The underlying hunk syntax traces back to the classic Unix diff and patch
tools; if you've never worked with those directly, the
guide to the Unix diff command is useful background — git's patch format is a superset of the
same idea, not a replacement for it.
git diff vs git format-patch: Two Ways to Make a Patch
Both commands produce a patch. Which one to reach for depends on a single question: does the person
applying it need to know who wrote this and why, or just what changed? The table below breaks down
exactly when a plain git diff patch is enough and when format-patch's extra metadata earns its keep,
including how GitHub's own .patch URL suffix fits into the same picture.
| Aspect | git diff | git format-patch | GitHub .patch URL |
|---|---|---|---|
| Output | Raw unified diff, content only, no metadata | One mbox-format file per commit, with metadata | Same mbox format as format-patch, per commit |
| Filename | Whatever you choose | Auto-numbered, e.g. 0001-subject.patch | pr-number.patch or sha.patch |
| Author/date/message preserved? | No | Yes — author, date, subject, full message | Yes, since it's format-patch under the hood |
| Applied with | git apply | git am | git am |
| Creates a commit on apply? | No — working tree (and index, with a flag) only | Yes, replays as a real commit | Yes, same as format-patch |
| Best for | One-off local diffs, WIP snapshots, non-git targets | Sharing commits with authorship intact | Pulling a specific PR or commit without cloning |
GitHub also serves a .diff suffix on the same URLs — a single combined diff with no
commit metadata, the GitHub-hosted equivalent of plain git diff output, applied with
git apply instead of git am. Both suffixes are covered in full in
the GitHub section below.
How to Create a Patch File with git diff
Call it create patch file git, git create patch from diff, or make patch from git diff — however it gets phrased, this is the rawest form: no metadata, just the change itself, redirected to a file.
# Uncommitted changes in the working tree (vs the index)
git diff > my-changes.patch
# Staged changes only (vs the last commit)
git diff --cached > staged.patch
# Between two commits
git diff abc123 def456 > range.patch
# Between two branches
git diff main feature-branch > branch.patch
# A single file only
git diff -- src/config.ts > config.patch
Every one of these is a git create patch operation with the same shape: git diff with
whatever comparison arguments you'd normally use, piped into a file instead of your terminal. If the
change touches binary files — images, compiled assets, lockfile-adjacent binaries — add
--binary so the patch embeds the binary content instead of silently skipping it:
git diff --binary > with-binaries.patch
Every flag that controls what git diff compares and how it formats the output — ignoring
whitespace, word-level diffs, context line counts, path filters — applies identically when the output
is headed to a file instead of stdout;
the full flag reference covers those in depth. The
one thing a plain git diff patch can never carry is commit identity, since there's no
commit involved at all — that's exactly the gap git format-patch fills next.
How to Generate a Patch with git format-patch
git format-patch is the tool when generating a patch needs to preserve who wrote a change
and why, not just show what it did. It writes one file per commit, in mbox format — the same
format email clients use for a single message — with From, Date, and
Subject headers above the diff — a shape inherited from the Linux kernel's
patches-over-email workflow, which is why
git's official
git-format-patch documentation still describes the output in terms of what you would send to a
mailing list. git generate patch, git make patch, github generate patch — whichever term brought you
here, format-patch is the command behind all three whenever commit metadata matters, not just the
diff content.
# One file per commit, comparing your branch against main
git format-patch main
# Just the most recent commit
git format-patch -1 HEAD
# The last three commits
git format-patch -3
# Everything since a specific commit, up to HEAD
git format-patch abc123..HEAD
# All commits combined into a single file instead of one-per-commit
git format-patch --stdout main > series.patch git format-patch main against a three-commit branch produces three separate files, named
and numbered automatically:
0001-Add-retry-logic-to-api-client.patch
0002-Fix-timeout-default.patch
0003-Add-backoff-config.patch
The numbering preserves commit order, which matters because git am replays them in that
order later. Each filename is derived from its commit's subject line, sanitized into something
filesystem-safe — useful on its own for skimming what a series contains before opening any of the
files. This one-file-per-commit shape is also why format-patch pairs naturally with a cleaned-up,
linear branch: if your commits still need reordering or combining first,
squashing them or rebasing the
branch beforehand keeps the resulting patch series from mirroring a messy work-in-progress
history.
Grabbing a Patch from GitHub: the .patch and .diff URL Suffixes
GitHub serves both formats directly from any pull request or commit URL — append .patch
or .diff and the same page returns plain text instead of rendered HTML. No API token, no
cloning, no extra tooling.
# format-patch style: per-commit, with author/date/message
https://github.com/owner/repo/pull/123.patch
# Single combined diff: content only, no metadata
https://github.com/owner/repo/pull/123.diff
# Same trick works on a single commit URL
https://github.com/owner/repo/commit/abc123def.patch
Grabbing a github patch or a github patch file this way — sometimes phrased as apply github patch,
since the download and the apply usually happen back to back — needs nothing but curl
and the right suffix:
# Download, then apply as a real commit with original authorship
curl -L https://github.com/owner/repo/pull/123.patch -o pr-123.patch
git am pr-123.patch
# Or pipe straight through, no intermediate file
curl -L https://github.com/owner/repo/pull/123.patch | git am
# .diff instead: single diff, no commit metadata, apply with git apply
curl -L https://github.com/owner/repo/pull/123.diff | git apply
Note which command pairs with which suffix: .patch is mbox format, so it goes to
git am; .diff is a bare unified diff, so it goes to git apply.
Feeding a .diff file to git am fails outright — there's no mbox header for
it to parse — and that mismatch is one of the most common "why won't this patch apply" reports for
anyone new to pulling patches from GitHub directly.
Read the Patch Before You Apply It
Every guide above this line in most git patch tutorials stops at "apply it." A patch you wrote
yourself, sure — go ahead. A patch that showed up in a bug report, a Slack message, or a PR from
someone outside your org is a different situation: it's arbitrary file content about to be written
into your working tree, and git apply will do exactly what it's told, no questions
asked.
The command-line half of that discipline is two flags already covered above:
git apply --check confirms it applies cleanly without touching a file, and
git apply --stat shows the diffstat — which files, how many lines each. Neither one
tells you whether the change is what it claims to be. For that, you need to actually read the diff,
and a patch file full of @@ hunks and +/- markers is a rough
read in a terminal once it's more than a few dozen lines.
Diff Checker — the free Chrome extension this site is built around, also usable directly at
diffchecker.pro — doesn't know what a commit is and has no git integration; it's a Monaco-based
editor that renders a live comparison between whatever text sits in its two panes, with a
Split/Unified view toggle and three compare methods (Smart Diff, Ignore Whitespace, and
Classic (LCS)). Set expectations correctly on one point: language highlighting is auto-detected
from the content, and a .patch file isn't a language it recognises, so patch text lands
as plain text rather than coloured syntax. That's a plain-text tool, not a patch parser — but it's
exactly the right shape for two workflows a patch tutorial should cover and usually doesn't.
Workflow one: read the patch itself, before running anything. Put the
.patch text in one pane and the current version of the file it targets in the other.
Both panes are directly editable, so pasting into each one by hand works; the toolbar's Paste button
is the shortcut, though note it fills the first empty pane rather than letting you choose, and falls
back to overwriting the left one when both already hold text — so paste the patch first, then the
file. Reading the two side by side is the point: you can see at a glance whether the context lines a
hunk expects still exist in that file, or whether the file has drifted out from under the patch,
which is exactly the situation covered next in
when a patch won't apply.
Workflow two: verify what the patch actually did, after applying it. On a scratch
branch — stash or commit anything already in progress first so
there's nothing to lose — copy the target file's current contents into the left pane, run
git apply for real, then copy the modified file into the right pane. This is where Show
Diff Only earns its keep — collapsing every unchanged run down to a context window of 0, 1, 2, 3, or
5 lines turns the result into a short, readable list of exactly what changed, independent of whatever
the patch's authors claimed it does in a commit message or PR description. If the result looks wrong,
discarding the local changes resets the scratch
branch cleanly for another attempt.
What to actually look for while reading an untrusted patch, specifically: files touched that have
nothing to do with the patch's stated purpose, any change to CI configuration, build scripts, or
lockfiles, anything in a postinstall or similar hook, and hunks in files far from what the
description mentions. A patch that claims to "fix a typo in the README" and also edits
package.json's scripts block is worth reading twice before it touches your machine —
exactly the kind of thing that's obvious in a side-by-side view and easy to miss scanning
+/- lines in a terminal.
Worth being precise about what this workflow is not: Diff Checker has no unified-diff parser and no
hunk-header awareness, so it renders patch text as plain text rather than understanding it as a
patch — it won't apply anything for you. Its file picker doesn't list .patch or
.diff among the extensions it offers either, so either switch the dialog to All Files,
rename a local copy to .txt, or just paste the text, which is faster anyway. That's a
deliberate, honest limitation, not a missing feature to route around — the two workflows above only
ever need plain-text comparison, which is precisely what the tool does well.
How to Apply a Git Patch with git apply
How to apply a git patch with the most direct tool available: git apply reads a unified
diff and writes the described changes straight into your working tree. Whether it's phrased as git
apply diff, git apply diff patch, or git apply diff patch file, the command underneath is identical —
point it at the file and it does the rest.
# Apply to the working tree only — no commit, no index change
git apply my-changes.patch
# Apply to the working tree *and* stage the result in the index
git apply --index my-changes.patch
# Apply into the index only, leave the working tree files untouched
git apply --cached my-changes.patch
The default behavior is worth internalizing precisely: plain git apply never
creates a commit and never touches the index unless you tell it to with --index
or --cached. That makes it an all-or-nothing, working-tree-level operation by default —
exactly the right tool for the git apply diff use case where you just want the file contents changed
and you'll decide separately whether and how to commit them.
git apply vs git am: Which One and When
git apply and git am both take a patch and change your working tree, but
they answer different questions: "change these files" versus "replay this commit."
| Aspect | git apply | git am |
|---|---|---|
| Expects | Any unified diff — from git diff, another VCS, or hand-written | An mbox-format file, one commit's email-style header plus diff |
| Creates a commit? | Never, on its own | Yes — one commit per file/message in the mbox stream |
| Preserves authorship? | No — there's no commit to attach it to | Yes — original author name, email, and date |
| Multi-file series | Apply each file separately, or concatenate them first | Feed a whole directory of NNNN-*.patch files in one call |
| Conflict recovery | --reject writes .rej files; no continue/skip/abort | --continue, --skip, --abort |
| Typical source | git diff, a GitHub .diff URL | git format-patch, a GitHub .patch URL, a mailing list |
If you have direct access to the source repository and branch — rather than just a patch file someone
handed you — moving a specific commit across branches is often better served by
cherry-picking it directly, since
that skips the export/import step entirely and still preserves authorship the same way
git am does. Patches earn their keep specifically when you don't have that access, or
when the target isn't a git repository the sender can push to at all.
Mid-series, git am also gives you a direct look at whatever commit is currently causing
trouble: git am --show-current-patch=diff prints the diff of the patch that's paused the
apply, without leaving the conflict state, which is often the fastest way to see exactly what a
failing hunk was trying to do before deciding whether to fix it, skip it, or abort the whole series.
Flags That Save You: --check, --stat, --3way, --whitespace, --reject
A handful of flags turn git apply from all-or-nothing into something more forgiving —
or, in the case of the first two, into a way to inspect before committing to anything. The full list
is in git's official
git-apply documentation; these are the ones that actually come up.
# Dry run — confirms it would apply cleanly, touches nothing
git apply --check my-changes.patch
# Diffstat only — files and line counts, no content
git apply --stat my-changes.patch
# File mode changes and detected renames, without applying
git apply --summary my-changes.patch --check exits non-zero and prints the specific hunks that would fail, which makes it the
first thing worth running on any patch you didn't write yourself — cheap, safe, and it tells you
immediately whether the rest of this section even applies.
# Fall back to a three-way merge using the blobs referenced
# in the patch's index line, instead of failing outright
git apply --3way my-changes.patch --3way is the flag most worth knowing about and least often used. A plain
git apply is strictly all-or-nothing: if the context around a hunk doesn't match, the
whole patch fails. --3way instead looks up the blob hashes recorded in the patch's
index line, and if your repository has those blobs (usually because the patch came from
a commit in your own history), it performs a real three-way merge — which can succeed where a direct
apply would fail, but can also leave <<<<<<< conflict markers in
the working tree for you to resolve by hand, unlike plain apply, which never leaves
partial results behind.
# Whitespace-only mismatches: fix, warn, error, or ignore
git apply --whitespace=fix my-changes.patch
git apply --whitespace=warn my-changes.patch
git apply --whitespace=error my-changes.patch
git apply --whitespace=nowarn my-changes.patch
# Apply what you can, write .rej files for the hunks that fail
git apply --reject my-changes.patch --whitespace=fix corrects trailing whitespace and indentation-only mismatches instead
of treating them as apply failures — useful when a patch was generated on a machine with different
editor settings. It isn't quiet about it: each offending line is echoed, followed by
warning: 1 line applied after fixing whitespace errors., so you can still see what it
touched. --reject is the opposite philosophy from --3way:
rather than trying harder to make everything apply, it applies whatever hunks succeed cleanly and
writes the rest out as <filename>.rej files, so you can inspect and hand-apply just
the parts that didn't go in automatically.
When a Patch Won't Apply: Conflicts and Fixes
$ git apply my-changes.patch
error: patch failed: src/config.ts:12
error: src/config.ts: patch does not apply
The root cause is almost always the same: git apply matches a hunk by its
context lines and content, not by line number. If the target file has changed since the
patch was generated — even a few lines added or removed elsewhere in the file — the context a hunk
expects to find at "line 12" may no longer be there, and the whole hunk fails even though the actual
change it's trying to make might still make perfect sense.
The fix ladder, roughly in order of how often each one resolves it:
- Confirm the target file, not the patch, is the problem.
git apply --check my-changes.patchfirst — if it fails the same way, the file really has drifted. - Try a three-way merge instead of a direct apply.
git apply --3way my-changes.patch— if the referenced blobs exist locally, this often succeeds where a direct apply fails, leaving conflict markers to resolve by hand if it can't fully reconcile. - Check the path-stripping level. A patch generated from a different directory
depth (a subdirectory, a differently named clone) has paths that don't line up with yours.
-p<n>stripsnleading path components before matching, and--directory=<dir>prepends a directory instead — trygit apply -p2 my-changes.patchor similar if the default-p1isn't matching your layout. - Rule out whitespace as the actual cause.
git apply --whitespace=fix my-changes.patch— line-ending or trailing-space differences between the machine that generated the patch and yours are a common, easy-to-miss culprit. - Take what you can get.
git apply --reject my-changes.patchapplies every hunk that matches cleanly and writes.rejfiles for the rest, so you can manually merge just the parts that didn't go in.
For a patch applied through git am instead, the same underlying mismatch shows up as a
paused series rather than a flat failure — git am --show-current-patch=diff shows what
the stuck commit was trying to do, then git am --continue resumes after you've resolved
it by hand and staged the result, git am --skip drops the current commit from the series
entirely, and git am --abort unwinds the whole thing back to where you started. If
nothing here resolves it and you'd rather start clean,
discarding local changes and re-applying from
scratch is often faster than untangling a half-applied patch by hand.
Reversing a Patch with git apply -R
A patch applied with plain git apply never became a commit, so there's nothing to
revert in the commit-history sense — but the same patch file can undo its own change, using
-R (or --reverse) to run every hunk backward.
# Undo a patch applied with git apply
git apply -R my-changes.patch
# Equivalent long form
git apply --reverse my-changes.patch
# Dry-run the reversal first, same as any other apply
git apply -R --check my-changes.patch
This only works cleanly if the working tree still looks like it did right after the patch went in —
the same context-matching rules from the
conflicts section apply in reverse. If the patch instead went in through git am and
became a real commit, reversing at the file level isn't the right layer — git revert
<commit> is, since it creates a new commit that undoes the change while keeping the
original in history, rather than rewriting or dropping anything that's already shared.
Binary Files, Renames, and Other Edge Cases
A few situations don't fit the plain-text hunk model cleanly and need their own handling.
Binary files. A normal git diff carries no binary content at all. It
says so rather than failing quietly — the whole diff for a changed image is one line reading
Binary files a/logo.png and b/logo.png differ, with no hunks under it. Generating a patch
that actually carries the change requires --binary at creation time, and applying one
that contains binary hunks needs git apply --binary to write that content back out.
# Generate, including binary content
git diff --binary > with-binaries.patch
# Apply, writing binary hunks back to disk
git apply --binary with-binaries.patch Renames. Git detects renames heuristically when generating a diff (a file that
disappeared and a near-identical one that appeared nearby), and both git diff and
git format-patch represent a detected rename as its own diff header rather than a
delete-plus-add pair. git apply --summary lists exactly which files a patch renames or
changes the mode of, without applying anything — worth running on an unfamiliar patch alongside
--stat, since a rename can be easy to miss scanning hunks alone.
Path mismatches. -p<n> strips n leading path
components from each file path in the patch before matching against your working tree —
-p1 (stripping the a/ / b/ prefix) is the default and what
both git diff and format-patch produce, so you rarely need to touch it for
patches generated by git itself. It matters more for patches from other tools, or ones generated a
directory level off from where you're applying them. --directory=<dir> does the
opposite — it prepends a directory to every path instead of stripping one, useful when applying a
patch generated for a subdirectory against the repository root.
Quick Reference: Every Patch Command in One Table
Every command from every section above, in one place — from the plain git diff redirect
through git apply diff patch file handling and the full git am conflict
loop.
| Command | What It Does |
|---|---|
git diff > file.patch | Create a raw patch from uncommitted changes |
git diff --cached > file.patch | Create a patch from staged changes only |
git diff --binary > file.patch | Create a patch that includes binary file content |
git format-patch main | Generate one metadata-rich patch file per commit since main |
git format-patch -1 HEAD | Generate a patch for just the most recent commit |
git format-patch --stdout > series.patch | Combine a whole series into one file |
git apply file.patch | Apply a patch to the working tree only |
git apply --index file.patch | Apply and stage the result in the index |
git apply --cached file.patch | Apply into the index only, skip the working tree |
git apply --check file.patch | Dry run — confirm it applies, touch nothing |
git apply --stat file.patch | Show the diffstat without applying |
git apply --summary file.patch | Show mode changes and renames without applying |
git apply --3way file.patch | Fall back to a three-way merge instead of failing outright |
git apply --reject file.patch | Apply what matches, write .rej files for the rest |
git apply --whitespace=fix file.patch | Auto-correct whitespace-only mismatches |
git apply -R file.patch | Reverse an already-applied patch |
git apply -p2 file.patch | Strip two leading path components before matching |
git apply --binary file.patch | Apply a patch containing binary hunks |
git am file.patch | Apply an mbox patch as a real commit, authorship preserved |
git am --continue | Resume an am series after resolving a conflict |
git am --skip | Drop the current commit from an am series |
git am --abort | Unwind the whole am series back to the start |
git am --show-current-patch=diff | Show the diff of the commit currently paused |
curl -L url.patch | git am | Download and apply a GitHub PR/commit patch in one step |
Frequently Asked Questions
How do I apply a patch file in git?
Run git apply <patchfile> for a working-tree-only apply — no commit gets
created, and the index isn't touched unless you add --index or --cached.
If the file came from git format-patch or a GitHub .patch URL, use
git am <patchfile> instead — it replays the patch as a real commit with the
original author, date, and message intact. When you're not sure a patch will apply cleanly, run
git apply --check first.
What's the difference between git format-patch and git diff?
git diff > file.patch produces a raw unified diff with no metadata — content
only — applied with git apply, and it never becomes a commit by itself.
git format-patch produces one file per commit in mbox format, complete with author,
date, subject line, and commit message, applied with git am, which replays each file
as a genuine commit with the original authorship preserved.
How do I check if a patch applies without applying it?
git apply --check <patchfile> runs a dry run — it exits non-zero and prints
exactly which hunks would fail, without touching a single file in your working tree. Pair it with
git apply --stat to see the diffstat and git apply --summary to see
file mode changes and detected renames before you commit to the real apply.
How do I reverse a git patch?
git apply -R <patchfile> (or the long form --reverse) undoes a
patch that was applied with git apply, as long as your working tree still matches
the post-apply state closely enough for the reversed hunks to find their context. If the patch
was applied with git am and became a real commit, git revert
<commit> is the right tool instead, since it reverses at the commit level rather than
the file level.
What's the difference between git apply and git am?
git apply takes any unified diff and applies it to the working tree — and the index,
with --index — without ever creating a commit. git am is built
specifically for format-patch-style mbox files: it applies the diff and creates a commit,
preserving the original author and message, and it gives you --continue,
--skip, and --abort for handling conflicts mid-series, none of which
exist for plain git apply.