Carry a patch queue when you have a few small changes and want each upstream release to start clean. Keep a long-lived fork when your changes are many, deep or ongoing. The queue is easier to audit and to retire. The fork is easier to build on but harder to keep current.
Two ways to hold the same changes
Patch queue. You store your changes as a set of patch files, one per change, next to a script that applies them to a pristine copy of each upstream release. Git can produce such files from commits with the format-patch command, which prepares each commit as a message you can apply elsewhere.
Long-lived fork. You keep a repository that began as a copy of upstream. Your changes are commits on top. You sync upstream into it over time, by merge or rebase.
Side by side
| Question | Patch queue | Long-lived fork |
|---|---|---|
| How many changes suit it | A handful | Dozens or more |
| Audit trail | One file per change, easy to read | Commit history, harder to separate yours from upstream's |
| Taking a new upstream release | Reapply patches, see which break | Merge or rebase, resolve conflicts |
| Seeing what you changed | List the patch directory | Diff against upstream |
| Dropping a patch when upstream fixes it | Delete the file | Revert or let a sync absorb it |
| Risk of drift | Low, base is always pristine | Higher, history accumulates |
| Building new features | Awkward | Natural |
Security reasons to prefer the queue
A queue keeps your changes small and visible. A reviewer can read every patch in an afternoon. Each patch can carry a header naming the advisory it answers and the condition for removal. When upstream releases a fix, the failing patch is a signal, not a surprise buried in a merge.
The base stays a pristine upstream release, which makes it easy to check signatures and checksums on what you start from. See verifying upstream signed tags.
Security reasons to prefer the fork
When changes touch many files, patches rot fast, and a queue that fails on every release gets skipped. A fork tolerates that because Git helps merge. If you have your own roadmap for the code, a fork gives you history, branches and tests in one place. Just accept the duties: sync cadence, advisory tracking and an owner. See security responsibilities of maintaining a fork.
A rule to decide
- Count your changes and the lines they touch.
- If the patches apply cleanly across the last three upstream releases, a queue works.
- If they conflict on most releases, move to a fork, or better, reduce the changes by sending them upstream.
- Reassess every six months. Many forks begin as a queue that outgrew itself, and many forks could shrink back to a queue after upstream accepted most patches.
Headers worth writing in every patch
| Header line | Why |
|---|---|
| Reason or advisory ID | Explains why it exists |
| Upstream issue or pull request link | Tracks upstream status |
| Applies to versions | Prevents misuse on a wrong base |
| Remove when | Gives an exit |
Where Safeguard fits
Either way, the built result is what gets deployed and scanned. Safeguard's SBOM and dependency scanning covers the output of your build, and you can try a free scan at gold.safeguard.sh/scan.
Quick check
Which approach suits one or two small security patches?
A patch queue. It is easy to read, easy to review and easy to delete when upstream fixes the issue.
When does a queue stop working?
When patches fail to apply on most releases. At that point move to a fork or shrink the patches by sending them upstream.
Sources
Last reviewed: 19 October 2026.