A patch often arrives at an awkward moment: the fix is ready, but the other repository cannot pull your branch, or the reviewer needs a change that can travel through email, a ticket, or an isolated network. You are not merely moving lines. You are handing someone a small piece of project history and hoping it lands cleanly.
For one ordinary, non-merge commit, git format-patch -1 <commit> is the dependable choice. It writes an email-style patch containing the commit message, author identity, and diff. The -1 matters: it limits the output to the named commit instead of selecting a wider history range.
Look at the commit before you package it
git show --stat --summary <commit>
git show --format=fuller --no-ext-diff <commit>This is the moment to catch the wrong hash
Replace
<commit>with a commit ID, tag, or other revision that resolves to exactly the commit you intend to share.--stat --summarygives a compact view of affected paths, modes, renames, and commit metadata.The second command shows the patch while
--no-ext-diffprevents a configured external diff driver from changing what you review.Search the diff for credentials, tokens, private hostnames, generated files, and customer data. A patch is plain text and is easy to forward.
These commands only inspect repository objects; they do not modify the working tree or history.
Put exactly one commit in a deliberate directory
mkdir -p outgoing-patches
git format-patch -1 <commit> -o outgoing-patchesoutgoing-patches/0001-Describe-the-change.patchThe filename is helpful, but the commit is the source of truth
-1is short for--max-count=1; it selects the named commit only.-o outgoing-patchescontrols the destination directory. Git creates a numbered filename from the commit subject.The displayed filename is illustrative because the real subject determines it.
format-patchincludes the commit message, author information, and a diff suitable forgit am.This exact one-commit behavior and output naming were reproduced with Git 2.43.0 in a disposable two-commit repository.
When a pipeline truly needs standard output
git format-patch -1 <commit> --stdout > change.patchRisk level: caution. Review the command before running it.
Redirection changes who owns the filename
--stdoutsends patch content to standard output instead of creating Git’s numbered file.The shell truncates
change.patchbefore Git writes it. Choose a new path or inspect an existing one first.This form is useful for compression, encryption, or a transport pipeline, but
-ois clearer for ordinary local files.Do not paste terminal diagnostics into the redirected stream; a mail patch must remain byte-for-byte parseable.
Inspect the parcel from the receiver’s side
git apply --stat outgoing-patches/0001-Describe-the-change.patch
git apply --check outgoing-patches/0001-Describe-the-change.patch notes.txt | 1 +
1 file changed, 1 insertion(+)A successful check is evidence, not a reservation
git apply --statreports the patch summary without applying changes.git apply --checktests the diff against the current files and exits nonzero when context or paths do not match.The shown statistic and a successful check were produced locally on the parent of a two-commit test repository using Git 2.43.0.
Run the check again immediately before applying if the branch moves; another edit can invalidate an earlier result.
git apply --checkchecks the diff, not the authorship, commit message, build, tests, or safety of the code.
Recreate the commit with git am
git status --short
git switch -c receive-fix
git am --3way outgoing-patches/0001-Describe-the-change.patchApplying: Describe the changeRisk level: caution. Review the command before running it.
Why this is different from applying a plain diff
Start from the intended base and a clean working tree;
git status --shortshould show nothing you might confuse with patch changes.git switch -ccreates a reviewable topic branch without rewriting the source branch.git amreads mail headers and creates a new commit with the patch’s author and message; the committer and commit object ID will normally differ.--3waylets Git attempt a three-way merge when the patch records usable blob identities and direct application fails.The shown flow was executed with Git 2.43.0 in a disposable receiver repository; it preserved the test author and subject while creating the receiving commit.
If a conflict interrupts the handoff
git am --show-current-patch=diff
# Resolve the conflicted files, then stage only the resolutions.
git add <resolved-paths>
git am --continueRisk level: caution. Review the command before running it.
Keep the resolution narrow and observable
--show-current-patch=diffdisplays the diff for the mail message currently being applied.Replace
<resolved-paths>with reviewed paths; avoidgit add .when unrelated files may be present.git am --continuecreates the commit after conflicts are resolved and indexed.Run the project’s relevant tests before publishing the resulting branch.
These are documented recovery commands; no conflict was manufactured for the local verification run.
Abandon the attempt without abandoning your branch
git am --abortRisk level: caution. Review the command before running it.
Abort is for the active am session
Use this when the conflict is wrong for the target branch or needs a fresh patch from the sender.
--abortstops the entire currentamoperation rather than skipping only one mail message.Inspect
git statusafterward and retain any unrelated work according to your team’s workflow.This recovery behavior is validated against the official
git amdocumentation rather than exercised against valuable project history.
Use a plain diff when history is deliberately out of scope
git diff --binary <commit>^ <commit> > content-only.patch
git apply --check content-only.patch
git apply content-only.patchThis moves content, not the original commit envelope
<commit>^names the first parent, so the diff describes the transition from that parent to the commit.--binaryincludes binary changes in a formgit applycan consume; it also preserves full-index information.git applychanges the working tree without creating a commit or preserving the original message and author.The parent expression fails for a root commit and is ambiguous as a storytelling device for merges.
Review and commit the resulting changes separately if a content-only handoff is what the receiver requested.
Root commits need an explicit boundary
root_commit=$(git rev-list --max-parents=0 <commit>)
git format-patch --root -1 "$root_commit" -o outgoing-patchesoutgoing-patches/0001-Initial-commit.patchRoot is a special case because there is no parent
git rev-list --max-parents=0finds root commits reachable from the supplied revision; unusual histories can have more than one, so inspect the result.--rootallows the root commit to be emitted as a patch against an empty tree.-1still limits the selection to one commit.This syntax produced one root-commit patch with Git 2.43.0 in the local disposable repository.
Do not use command substitution blindly when multiple roots can be returned; select and verify the intended object first.
A series is ordered history, not a bag of files
git format-patch <base>..<tip> -o outgoing-patchesRead the two dots as a selection rule
<base>..<tip>selects commits reachable fromtipthat are not reachable frombase.Git numbers the resulting files in the order they should normally be fed to
git am.The base commit itself is excluded. Confirm the set with
git log --oneline <base>..<tip>before sharing.Merge commits are normally omitted because an email patch represents a change relative to one parent, not the topology and conflict decisions of a merge.
For a branch already visible to the receiver, sharing the ref and using
cherry-pickor merging may communicate intent better than flattening it into patches.
Things a clean-looking patch can still miss
Merge commits:
format-patchdoes not preserve merge topology or conflict-resolution intent. Share the branch, cherry-pick an appropriate non-merge commit, or choose a bundle.Binary files:
format-patchsupports Git binary patches, but review size and receiver limits. A plaingit diffneeds--binaryfor an applicable binary representation.Renames and file modes: Git records content and mode changes; rename reporting is similarity detection, so inspect the resulting patch rather than relying on a label.
Submodules: the patch changes the recorded gitlink commit, not the nested repository’s objects. The receiver must obtain those objects separately.
Git LFS: a normal patch carries the small pointer file, not the large object. The receiver also needs access to LFS storage.
Untracked files: commits do not contain them, so
format-patchcannot include them. Add and commit intended files before generating the patch.Whitespace damage: chat tools and rich-text email clients can wrap or alter a patch. Transfer it as a file and use
git amwhitespace diagnostics when appropriate.Wrong base:
git apply --checkorgit am --3waymay expose the mismatch, but neither can prove the resulting behavior is correct. Build and test on the receiving branch.
The handoff I would send to a teammate
Name the commit and intended base branch in the message.
Attach the reviewed
.patchfile instead of pasting its contents into formatted chat.Say whether the receiver should use
git amto preserve commit metadata orgit applyfor content only.Include the tests you ran and any required submodule or LFS access.
Keep the source branch until the receiver confirms the patch applied and behaved correctly.
That small amount of context is kindness disguised as process. The receiver should not have to reverse-engineer whether your patch is one commit, one file, or one half of a larger change.
Comments and corrections