git-template-patcher
Keep long-lived projects aligned with a template repo without forcing risky git history tricks. git-template-patcher computes the template delta and applies it as reviewable, local changes on a fresh patch branch.
Why this exists (where plain git falls short)
Git is excellent at tracking a single repository history, but template maintenance is a different problem:
- A generated project usually diverges quickly, so merging or rebasing from the template is noisy and conflict-heavy.
- The template and active project often do not share a clean ancestor relationship that supports straightforward syncs.
- You usually want template updates only (not every repo-specific change), filtered by the template’s own ignore rules.
- Teams need a safe, reviewable update step instead of rewriting history or relying on brittle copy/paste sync scripts.
git-template-patcher addresses this by generating one consolidated patch from template baseline -> template latest (respecting template .gitignore) and applying it on a new branch so you can inspect, test, and commit intentionally.
Install (recommended)
Requires Go >= 1.22.
Install latest tagged version:
go install github.com/aegion-dynamic/git-template-patcher@latest
Install a specific version:
go install github.com/aegion-dynamic/git-template-patcher@v0.1.0
Verify:
git-template-patcher --help
Usage
Run from inside the active project directory:
cd /path/to/active-project
git-template-patcher --template /path/to/template-repo
Or pass the active project path explicitly:
git-template-patcher --template /path/to/template-repo --project /path/to/active-project
Workflow (Git commands)
flowchart TB
A["Start git-template-patcher"] --> B[Resolve active project dir]
B --> C[Baseline commit]
C --> C1["git rev-list --max-parents=0 HEAD"]
A --> D{Template is URL?}
D -->|yes| D1["git clone --no-tags --depth 1 <template-url> <clone-dir>"]
D -->|no| D2["Use local template repo path"]
D1 --> E[Template latest commit]
D2 --> E
E --> E1["git rev-parse --verify HEAD"]
E --> E2["git rev-parse HEAD"]
C1 --> F[Enumerate tracked paths]
E2 --> F
F --> F1["git ls-tree -r --format='%(objectmode)|%(objecttype)|%(path)' <commit>"]
F --> G[Filter via template .gitignore]
G --> G1["git check-ignore -z --stdin <candidate-paths>"]
G1 --> H{Any included paths?}
H -->|no| H0[Write audit milestones and exit]
H -->|yes| I[Generate consolidated patch]
I --> I1[Create temp patch repo]
I1 --> I2["git init && git config user.name/user.email"]
I2 --> I3["Materialize baseline paths via git cat-file -p <baseline>:<path>"]
I3 --> I4["git add -A && git commit -m 'baseline'"]
I4 --> I5["Materialize template-latest-filtered paths (and deletions)"]
I5 --> I6["git add -A && git commit -m 'template-latest-filtered'"]
I6 --> I7["git diff --binary <baselineOID>..<templateOID> > consolidated.patch"]
I7 --> J[Checkout patch branch]
J --> J1["Determine default branch tip (symbolic-ref/show-ref/rev-parse)"]
J1 --> J2["git checkout -b <branch> <defaultCommit>"]
J2 --> K[Apply patch]
K --> K1["git apply --whitespace=fix consolidated.patch"]
K1 --> K2["Stage intended paths (git add -- <paths>, git add -u -- <tracked-deletions>)"]
K2 --> L["Leave changes uncommitted for user review"]
L --> M[Write final audit milestone + print result]
Releases use semantic version tags in the vMAJOR.MINOR.PATCH format (for example v0.1.0).
This matters because go install github.com/aegion-dynamic/git-template-patcher@vX.Y.Z installs exactly the tagged version.
Homebrew (future)
This project is structured to be Homebrew-friendly by building/installing directly via go install from a GitHub tag.
Once you decide on a Homebrew formula/tap, it can typically:
-
Pin the build to a tag (e.g. v0.1.0)
-
Run something equivalent to:
go install github.com/aegion-dynamic/git-template-patcher@v0.1.0
-
Install the resulting git-template-patcher binary into Homebrew’s prefix.