Updated October 31, 2026
The original article was published September 21, 2013. Correction: --stdout puts a Git patch series in one file; it doesn’t squash the commits.
In 2013, I wrote this Git patch guide while contributing to open-source projects that asked for patch files instead of merge requests. My original explanation called a single --stdout file a squash. That was wrong: the file still contains separate commit patches.1
Use git format-patch --stdout when the recipient wants the individual commits, and git diff --binary when they only want the final changes. For the last three commits on a linear branch:1,2
# One file containing three commit patches, for git am
git format-patch --stdout -3 HEAD > ../series.patch
# One combined diff, including binary changes, for git apply
git diff --binary HEAD~3 HEAD > ../combined.patch
Both commands write one file. The first keeps a message and patch for each commit. The second compares the starting and ending snapshots, with no commit messages or authorship. Neither changes your branch history.1,2
Check which commits you’re exporting
These examples assume three ordinary commits after a shared base, with no merges. Run them from the repository root. The files go in its parent directory so they don’t become untracked files inside the repository. Choose unused output names: shell redirection overwrites an existing file.
First, inspect your working tree and the selected commits:
git status --short
git log --reverse --oneline HEAD~3..HEAD
HEAD~3 follows the first parent three times. In a commit range, A..B selects commits reachable from B but not A, so the starting commit is excluded. Here that’s the three commits after the base.3
The export commands above read committed history. They don’t include your uncommitted edits or untracked files. Save that work separately if the recipient needs it, and check that the log lists exactly what you intend to send.1,2
If your work is on a branch called feature and the recipient’s base is main, inspect that range instead:
git log --reverse --oneline main..feature
git format-patch --stdout main..feature > ../branch-series.patch
That exports non-merge commits reachable from feature but not main. Don’t assume it means "the last three commits" if the branches have diverged. To include the first wanted commit in a linear range, start from its parent. Here first and last stand for your actual commit IDs or existing refs:1,3
git log --reverse --oneline first^..last
git format-patch --stdout first^..last > ../range-series.patch
This form requires first to have a parent. format-patch omits merge commits, so use this guide for a linear series rather than as a way to transfer merge history.1
Three commits in one attachment
If the recipient wants separate patch files, export them to a directory:
git format-patch -3 HEAD -o ../patches
For the simple history above, Git writes three numbered patch files. Each contains the commit’s author, message and changes. With --stdout, those messages go into one mailbox-style stream instead:1
git format-patch --stdout -3 HEAD > ../series.patch
The recipient can apply that entire file with one command. There’s no need to apply each message manually.
On the receiving side, start at the agreed base, with series.patch in the parent directory of that checkout. Run the commands below one at a time:
- Check the working tree and index with
git status --short. If it prints anything, stop and save that work before continuing. - Create a review branch with
git switch -c review-series. - Apply the series with
git am ../series.patch. - Inspect the new commits with
git log --oneline -3.
git status --short
git switch -c review-series
git am ../series.patch
git log --oneline -3
For an example series with these commit subjects, the application prints:
Applying: Add first change
Applying: Update message
Applying: Update binary and revert transient
git am creates commits using the authorship and message parsed from each email. Review the resulting messages: Git strips trailing whitespace, and patch-like text in a message can change where parsing stops. It doesn’t guarantee the original commit IDs: the new commits have their own committer information and may have a different parent.4
There isn’t a git am dry-run option. A disposable review branch or scratch clone lets you check the series without moving your normal working branch.4
When a series stops on a conflict
If a patch no longer fits the recipient’s files, git am stops. Inspect the status and the failing patch:
git status
git am --show-current-patch=diff
Resolve the affected file in your editor. If the conflict is in message.txt, stage that resolved file and continue:
git add message.txt
git am --continue
Or abandon the whole application and return to the pre-application state:
git am --abort
Continue and abort are alternatives. Only run them during an active git am operation. If an earlier patch succeeded before a later one failed, abort also removes those earlier commits from this application.4
For a base that has moved, you can try three-way application from the start:
git am --3way ../series.patch
This needs the original blobs identified by the patch to be available locally. It can help when context has changed, but it can still leave conflicts for you to resolve.4
One combined Git patch from the base to the final tree
If the recipient only needs the final changes, compare the base snapshot with the final commit:
git diff --binary HEAD~3 HEAD > ../combined.patch
Here git diff compares two endpoints. Changes made and then undone between them won’t appear in the result. --binary includes an applicable binary patch, rather than only reporting that binary files differ.2
For a branch comparison, choose the base deliberately. Comparing main directly with feature uses their current tips. If main has unrelated work, that can include changes you didn’t mean to send. Git’s three-dot diff compares the merge base with the feature tip instead:2
git diff --binary main...feature > ../feature-combined.patch
This three-dot meaning applies to git diff; git log uses three dots differently.2,3
On the receiving side, start at the matching base, with combined.patch in the parent directory. Read the patch before applying it, and run these commands one at a time:
- Check the working tree and index with
git status --short. If it prints anything, stop and save that work before continuing. - Inspect the change summary with
git apply --stat ../combined.patch. - Check applicability with
git apply --check --index ../combined.patch. Stop if the check fails. - Stage the patch with
git apply --index ../combined.patch. - Review the staged changes with
git diff --cached.
git status --short
git apply --stat ../combined.patch
git apply --check --index ../combined.patch
git apply --index ../combined.patch
git diff --cached
The check command doesn’t apply the patch. With --index, the check also tests whether it can update both the working tree and index. The application stages the changes but creates no commit. Review them, run the project’s tests, then make your own commit:5
git commit -m "Apply combined changes"
A failed check is a reason to investigate the base and patch, not to force it through. A successful check only establishes that Git can apply it; it doesn’t establish that the code is safe or correct. Read patches from other people before applying them.
The old guide also claimed the generated patches worked with Subversion. That blanket claim has been removed. These examples cover a linear Git patch series and a combined Git diff. They don’t validate an SVN workflow or preserve merge history.
If you’re sending patches
Before sending the patch, agree on the base with the recipient and check the selected commits. Apply an unfamiliar patch on a review branch first.
The Git introduction from 2012 gives the broader background on distributed repositories.
Sources
- 1 https://git-scm.com/docs/git-format-patch a b c d e f g
- 2 https://git-scm.com/docs/git-diff a b c d e fSource 2 https://git-scm.com/docs/git-diff
- 3 https://git-scm.com/docs/gitrevisions a b c
- 4 https://git-scm.com/docs/git-am a b c dSource 4 https://git-scm.com/docs/git-am
- 5 https://git-scm.com/docs/git-apply ↑Source 5 https://git-scm.com/docs/git-apply
