Branch-flow git workflow commands for Claude Code: commit, push and open a PR; promote work along a protected chain; cut and tag a release.
The plugin knows the mechanics — branch guards, PR bodies, gate ordering, tag backfill. It learns the specifics — your branch names, your gate commands, your changelog format — from the project you run it in. One install works across every repo you open.
Beta — version 0.x. Things will still change: a release may rename or remove commands or
.claude/git.jsonkeys without warning, and the config file this plugin writes into your project can be lost or need rewriting on update. It ships as-is, with no warranty (see LICENSE).
/plugin marketplace add durchnull/claude-plugins
/plugin install git@durchnull
To take this plugin on its own, add its repo directly instead — it carries its own durchnull
marketplace definition:
/plugin marketplace add durchnull/git
/plugin install git@durchnull
Both routes register a marketplace named durchnull, and adding one replaces the other, so prefer
the catalog whenever you want more than one durchnull plugin at a time.
Then, once per project:
/git:init
| Command | Does |
|---|---|
/git:init | Interviews the repo and writes .claude/git.json. Idempotent; keeps values you already set. |
/git:ship | Stage → commit → push → open/update a PR, after running the project's quality gates. --split partitions a messy tree into several focused PRs. |
/git:promote | Opens a PR from the integration tier into the pre-production tier, updating the changelog on the way. |
/git:release | Stamps the version into the changelog, opens the release PR into production, then tags it. Three phases, auto-detected. |
/git:ship and /git:release work in any repo. /git:promote applies only to a chain that has a
pre-production tier; elsewhere it says so and points at /git:release.
Everything is optional. With no config file the commands infer what they can from the repo, and a
project that never configures anything still gets working commands. /git:init writes the file;
this section documents what it contains.
File:.claude/git.json, in your project, resolved relative to the working directory. The plugin
keeps no state of its own — one install is shared by every project you open, so everything it
remembers lives in the project it belongs to.
| Key | Default (inferred) |
|---|---|
tiers | The promotion chain, ordered integration → production, built from the branches that actually exist: develop/dev, then staging/preprod/uat, then the repo's default branch (main/master/production). A single-branch repo gets a single-tier chain. Never invents a tier. |
branchPrefixes | { feature: "feature/", fix: "fix/", chore: "chore/", hotfix: "hotfix/" } |
labels | { feature: "enhancement", fix: "bug", hotfix: "bug", chore: "chore" } |
mergeMethod | "merge" |
tagFormat | "v{version}" |
flowDocs | [] — where this project documents its git flow (["CONTRIBUTING.md#branching"]). Never inferred. The commands cite it when explaining the chain, and /git:init re-runs use it to catch config↔doc drift. |
lint | { run, fix } built from the lockfile's package manager + a lint / lint:fix script, when both exist; otherwise null (no lint gate). |
layers | []. Never inferred — guessing a project's build and test commands would silently run the wrong thing. No layers ⇒ only the lint gate runs. |
changelog | { path: "CHANGELOG.md", unreleasedHeading: "## Unreleased", categories: [...], visibilityMarkers: null } when a CHANGELOG.md exists, else null (changelog steps skipped entirely). |
deployNotes | {} — free text per tier, echoed verbatim into PR bodies and reports. |
shipReminders | [] — free-text correctness checks shown before every commit. |
codenames | null — set { enabled: true, scheme: "…" } to give each promotion PR a distinguishing name. |
promoteSteps | { beforePr: [], afterPr: [] } — project-specific work attached to a promotion. |
Every key is optional and every key is inferable, so a plugin update never hard-fails an existing
file. Stamp "configVersion": 1. Unknown keys are preserved and ignored rather than rejected.
layers scopes the gates to what a change actually touches, so /git:ship runs only the build,
typecheck and test commands the change reaches. promoteSteps attaches project-specific work to a
promotion without forking the command. Both take a worked example — see
docs/configuration.md. Complete config files for three project shapes are
in examples/.
The gate commands you configure — layers[].build/typecheck/test, lint.run/fix, and any
promoteSteps[].run — must be allowlisted in your project's.claude/settings.json. Without
that, Claude Code asks you to approve each one every time a gate runs.
/git:init prints the exact list to paste in, based on what you configured.
A plugin command's allowed-tools is fixed when the plugin is built, so it can never cover commands
only your project knows about. This is the one gap the plugin cannot close for you.
MIT © David Friedrich.
The license covers the code, not the name. It grants no right to use durchnull as the name of a derived or redistributed work — fork it freely, under a name of your own.