Applying a patch in Git is a fundamental skill for developers collaborating outside of standard pull request workflows, contributing to open-source projects via mailing lists, or sharing specific changes without granting direct repository access. Plus, a patch file—typically ending in . patch or .diff—contains a textual representation of differences between two sets of files. Think about it: mastering the git apply and git am commands allows you to integrate these changes cleanly, preserving commit history or staging modifications for review. This guide covers the complete workflow, from inspecting a patch to resolving conflicts and automating the process Small thing, real impact..
Understanding Patch Formats and Tools
Before running commands, it is crucial to identify the type of patch you are handling. Git primarily deals with two formats, and using the wrong tool for a specific format leads to errors or lost metadata.
Unified Diff (Standard Patch)
This is the raw output of git diff or the standard Unix diff -u command. It contains only the code changes (lines added/removed) and context lines. It does not contain commit metadata such as author name, email, commit message, or timestamps The details matter here..
- Tool:
git apply - Use case: Applying changes from a contributor who sent a raw diff, applying a hotfix from a file, or testing changes locally before committing.
Git Formatted Patch (Mailbox Format / mbox)
Generated by git format-patch, this format wraps the diff in an email-like header structure. It includes the commit hash, author information, date, commit message (subject and body), and the diff itself. It can represent a single commit or a series of commits.
- Tool:
git am(Apply Mailbox) - Use case: Accepting contributions via email (common in Linux kernel workflow), moving commits between repositories without a remote connection, or preserving exact commit history.
Inspecting a Patch Before Application
Never apply a patch blindly. On top of that, malformed patches, whitespace errors, or changes targeting the wrong file paths can corrupt your working directory. Always inspect first.
Check Patch Validity and Statistics
Run a dry-run to verify the patch applies cleanly without modifying your files. This is the single most important safety step.
git apply --check example.patch
- Exit code 0: The patch applies cleanly.
- Non-zero exit code: Errors are printed to stderr (e.g., "patch does not apply," "whitespace errors," "file not found").
To see a summary of what files will change without applying:
git apply --stat example.In real terms, patch
Output example:
src/main. c | 10 ++++++----
tests/test_main.
### View the Actual Diff
To read the code changes in the terminal:
```bash
git apply --stat example.patch && cat example.patch
Or use git show if it is a formatted patch (mbox):
git show 0001-fix-typo-in-readme.patch
Applying a Standard Diff with git apply
Use git apply for raw unified diffs. By default, it modifies files in your working directory and stages the changes (index) automatically Small thing, real impact..
Basic Application
git apply feature.patch
If successful, your working directory reflects the changes, and git status shows them as "staged for commit."
Apply to Working Directory Only (Unstaged)
If you prefer to review changes manually before staging, use the --index flag explicitly or --cached for index-only (rare), but the standard workflow for "unstaged" is actually slightly nuanced. git apply updates both by default. To keep changes only in the working directory (unstaged), you technically cannot do this directly with git apply alone in modern Git versions without a workaround, but the standard behavior (staged) is usually preferred Not complicated — just consistent..
Correction/Refinement: Actually, git apply updates the working tree and the index by default. There is no direct flag to only update the working tree and leave the index untouched in a single atomic command for standard diffs. On the flip side, you can apply to index only (--cached) or both (default).
Handling Whitespace Errors
Patches generated on different operating systems or editors often have trailing whitespace or mixed tabs/spaces. Git rejects these by default That's the part that actually makes a difference..
- Warn only:
git apply --whitespace=warn example.patch(Applies but prints warnings). - Fix automatically:
git apply --whitespace=fix example.patch(Strips trailing whitespace, fixes indentation). - Ignore completely:
git apply --whitespace=nowarn example.patch(Silently applies, keeps errors in your codebase—not recommended).
Applying with a Path Prefix (Directory Stripping)
Patches often contain paths like a/project/src/file.c and b/project/src/file.c. If you are inside project/, the project/ prefix causes "file not found" errors. Use -p (strip prefix) or --directory It's one of those things that adds up..
- Strip one level (
a/andb/):git apply -p1 < example.patch(Standard for most Git-generated patches). - Strip two levels (
a/project/):git apply -p2 < example.patch. - Apply from subdirectory:
git apply --directory=subdir example.patch.
Creating a Commit Immediately
While git apply stages changes, it does not create a commit. You must commit manually:
git apply feature.patch
git commit -m "Apply feature patch from contributor"
Applying Formatted Patches with git am
Use git am (Apply Mailbox) for patches created with git format-patch. This command reads the email headers, creates a new commit object for each patch, and applies it to your current branch. This preserves the original author, date, and commit message.
Basic Application (Single or Series)
git am 0001-fix-bug.patch
Or apply a whole series (numbered sequentially):
git am 0001-*.patch
You can also pipe an mbox file directly:
git am < patches.mbox
The Three-Way Merge (-3 Flag)
This is the most powerful flag for git am. If the patch does not apply cleanly because your branch has diverged (e.g., the base commit is old), standard git am fails and stops. With -3, Git attempts a 3-way merge using the index information recorded in the patch header (the parent commit hash).
git am -3 0001-fix-bug.patch
- Success: Commit created, merge resolved automatically.
- Conflict: Stops at the conflicting patch. Files show conflict markers (
<<<<<<<). You resolve them manually, stage withgit add, and rungit am --continue.
Interactive Mode (-i)
For a series of patches, interactive mode lets you decide the fate of each commit individually (apply, skip, edit message, edit diff) It's one of those things that adds up..
git am -i 0001-*.patch
Prompt options:
y/a(apply this / apply all remaining)n/s(skip this / skip all remaining)e(edit the commit message)v(view the patch diff)m(view the commit message/log)
Editing Commit Metadata
If you need to change the author name/email or the commit message before finalizing (common when accepting external patches), use --interactive or specific flags:
-
**Sign off (Developer Certificate of
-
Sign off (Developer Certificate of Origin): adding
-sor--signoffappends aSigned-off-by:line to the commit, which is often required for projects that enforce the DCO And that's really what it comes down to.. -
Whitespace handling: flags such as
--ignore-whitespace,--whitespace=nowarn, or--whitespace=fixlet you control how Git treats trailing spaces or indentation differences when applying a patch Simple, but easy to overlook. That alone is useful.. -
Line‑ending control:
--keep-crpreserves carriage‑return characters in the working tree, useful when dealing with patches generated on Windows. -
Reject handling: if a patch cannot be applied,
--rejectleaves the unsuccessful hunks in.rejfiles while still creating the commit for the parts that did apply, letting you inspect and manually finish the work later. -
Abort and skip:
git am --abortrestores the branch to the state before the currentgit amsession began.git am --skipdiscards the problematic patch and moves on to the next one in the series (useful when you know a patch is obsolete).
-
Binary patches: the
--binaryflag tells Git to apply patches that add or remove binary files, which ordinary textual diffs cannot represent That's the part that actually makes a difference. Turns out it matters.. -
Keeping metadata:
--keeppreserves the original author timestamp and avoids updating the committer date when the patch is reapplied, while--keep-non-patchretains any non‑patch content (e.g., extra email headers) in the commit message Took long enough.. -
Applying from a mailbox: besides piping an mbox file, you can point
git amdirectly at a Maildir or MH folder withgit am <path/to/maildir>; Git will scan each file for a valid patch.
When to Choose git apply vs. git am
- Use
git applywhen you only need to stage changes (e.g., testing a patch, preparing a diff for review) and you do not want to create a commit yet. - Use
git amwhen you want to preserve the original authorship, date, and commit message—ideal for integrating contributions that arrived via email or as a series of formatted patches.
Best‑Practice Checklist
- Inspect the patch first (
git apply --statorgit apply --check) to gauge its impact. - Choose the correct prefix depth (
-pvalue) or--directoryto match your working tree layout. - Decide whether you need a commit: if yes, reach for
git am; if not,git applyfollowed by a manualgit commitsuffices. - use
-3for patches that may conflict due to divergent histories; it often saves a manual three‑way merge. - Use interactive mode (
-i) for large series to selectively edit, skip, or reword commits. - Sign off (
-s) when the project requires a DCO compliance line. - Handle failures gracefully:
--abortto reset,--skipto drop a bad patch, or--rejectto salvage partially applied changes. - Verify the result with
git diff --check,git show, or running the test suite before pushing.
By matching the command to the nature of the patch and the desired outcome—whether a clean stage‑only apply or a fully attributed commit—you keep your workflow efficient and your history clean.
*In short, git apply is the lightweight tool for staging changes, while git am is the full‑featured importer that turns
email‑delivered patches into proper commits with all provenance intact It's one of those things that adds up..
Advanced Tips and Integration Scenarios
Combining with git rebase
When working with a series of patches received via email, it’s common to first apply them with git am and then refine the resulting commit history using git rebase. This allows developers to clean up commit messages, squash related changes, or reorder commits before merging into the main branch. For example:
git am ~/patches/*.patch
git rebase -i HEAD~n # Interactively edit the last n commits
This workflow ensures that while the original authorship is preserved during import, the final history remains clean and coherent.
Handling Large Series
For projects that regularly receive large patch sets—such as kernel development or other high‑volume open‑source efforts—git am supports reading patches from standard input. This makes it easy to integrate with automated systems or scripts:
cat series_of_patches.mbox | git am
Additionally, tools like git format-patch can generate these mbox files directly from existing commits, enabling seamless round‑tripping between repositories:
git format-patch origin/main
These formatted patches retain full commit metadata and can be applied elsewhere using git am.
Conflict Resolution Workflow
While git apply provides basic conflict resolution through .rej files, git am offers more sophisticated handling via its built-in merge capabilities. When conflicts arise during git am, Git pauses the process and highlights unmerged paths. Developers can resolve conflicts manually, stage the resolved files, and continue:
# After resolving conflicts
git add
git am --continue
This mechanism preserves context better than starting over and supports iterative refinement.
Automation and CI Integration
In continuous integration pipelines, git apply is often preferred for quick validation of incoming changes without creating permanent history. It enables lightweight testing workflows where patches are applied temporarily, tested, and discarded if they fail. Conversely, git am might be reserved for trusted contributors whose patches have already passed preliminary checks.
By understanding both commands’ strengths and limitations, teams can design reliable processes suited to their specific needs—from rapid prototyping to formal contribution management.
Conclusion
Choosing between git apply and git am hinges on intent: whether the goal is temporary staging or durable integration. With careful attention to flags like --check, -3, and --signoff, along with strategic use of abort/skip mechanisms, developers can confidently work through even complex patch scenarios. Whether importing community contributions or refining local changes, mastering these tools enhances productivity and maintains repository integrity Not complicated — just consistent..
Worth pausing on this one.