git-pr-workflow
This skill should be used when committing, pushing, branching, or merging in the brepjs repository — when a task involves "pre-commit hook failed" (which tier ran, how to bypass), "commit rejected by commitlint", "subject may not be empty", the pre-push knip tier firing, "create a branch", "set up a worktree", "open a PR", "arm auto-merge", or deciding whether a commit needs a `!` breaking marker. Covers hook anatomy and tiers, conventional-commit message format, branching, worktrees, and the PR/merge process. For diagnosing a specific gate or lint error see quality-gates; for a red CI job see ci-triage.
Works with
--- name: git-pr-workflow description: This skill should be used when committing, pushing, branching, or merging in the brepjs repository — when a task involves "pre-commit hook failed" (which tier ran, how to bypass), "commit rejected by commitlint", "subject may not be empty", the pre-push knip tier firing, "create a branch", "set up a worktree", "open a PR", "arm auto-merge", or deciding whether a commit needs a `!` breaking marker. Covers hook anatomy and tiers, conventional-commit message format, branching, worktrees, and the PR/merge process. For diagnosing a specific gate or lint error see quality-gates; for a red CI job see ci-triage. license: Apache-2.0 --- # Git hooks, commits, and PR flow Hooks are managed by husky (`core.hooksPath` → `.husky/_`, installed by the `prepare` script in `package.json`). The repo `CLAUDE.md` "Git hooks" section summarizes the tiers; this skill covers what to do when a gate fires and the traps around commits, worktrees, and merging. ## Quick map | Concern | Where it lives | | -------------------- | ---------------------------------------------------------------------------- | | Hook scripts | `.husky/pre-commit`, `.husky/pre-push`, `.husky/commit-msg` | | lint-staged config | `.lintstagedrc.json` (NOT in `package.json`) | | Commit message rules | `commitlint.config.js` (`@commitlint/config-conventional`) | | Local full gate | `npm run validate` (`scripts/validate-change.sh`) | | CI gate for merge | `ci-pass` job in `.github/workflows/ci.yml` — the only required status check | | PR template | `.github/pull_request_template.md` | | Merge method | Squash only; branch auto-deleted on merge | ## Pre-commit anatomy `.husky/pre-commit` runs three tiers; a `trap` prints `scripts/pre-commit-help.sh` on any failure. **Tier 1 (parallel):** - `npx lint-staged` — per `.lintstagedrc.json`: `src/**/*.ts` gets `eslint --fix` + `prettier --write` + the pattern checker (`scripts/check-patterns.ts`); `tests/**/*.ts` gets eslint + prettier only; `*.config.ts` and `*.md` get prettier only. The pattern checker runs only on `src/` files. - `npm run typecheck` - `npm run check:boundaries:staged` — the staged variant (`scripts/check-layer-boundaries.sh --staged`), not plain `check:boundaries`. On failure, see the architecture-navigation skill. **Tier 2:** `npm run test` — changed-file tests on the occt-wasm kernel, no coverage thresholds (`vitest run --project occt-wasm --changed`). Set `FULL_TESTS=1` to run `npm run test:full` (full suite with coverage) instead. Test failures: see the writing-tests skill. **Tier 3 (non-blocking, always exit 0):** - `npm run check:readme-reminders` — lists READMEs adjacent to staged `.ts` files that may need updating. - `bash scripts/check-function-lookup.sh` — fires when a staged path matches `src/**Fns.ts` (any depth) or an `index.ts` at one directory level (`src/index.ts` or `src/<dir>/index.ts`) without `docs/function-lookup.md`. Act on this one: run `npm run docs:generate-lookup` and stage the result. The local reminder is soft and its `index.ts` match is shallow (a deeper `src/kernel/occt/index.ts` won't trip it), but CI's `build` job is the authoritative gate at any depth — it regenerates, prettier-normalizes, and `git diff --exit-code`s the file. Before committing multi-file changes, prefer `npm run validate` (typecheck → lint → boundaries → format:check → changed tests) and read its output — do not commit on a partially green tree. Bypass with `git commit --no-verify` only as a last resort; CI runs strictly more than the hook, so a bypassed failure just moves to the PR. Note: `scripts/pre-commit-help.sh` and `CONTRIBUTING.md` still say coverage thresholds are enforced "at push time" / "in pre-commit hooks". That is stale — coverage thresholds run only in the main-branch-only, non-blocking `coverage` CI job. Locally they run only via `npm run test:full`. ## commit-msg and pre-push - `.husky/commit-msg` runs `commitlint --edit` with `@commitlint/config-conventional`. A rejected message means the format is wrong, not the content — fix the `type(scope): subject` shape. - `.husky/pre-push` runs **only** `npm run knip` (unused-code detection, ~2 seconds). The full test suite is intentionally not re-run on push; CI's sharded `test` job is the full gate. If knip fails, either use the newly-flagged export or remove it — do not add it to `knip.config.ts` without cause. - If a push looked odd (interrupted terminal, unusual delay), verify it landed: `git ls-remote origin <branch>`. ## Commits Format: `type(scope): subject`. Types and examples: `CONTRIBUTING.md` "Commit Conventions" (feat, fix, docs, style, refactor, perf, test, chore). **The `!` breaking-marker trap.** In `release-please-config.json`, the root `brepjs` package excludes only `apps`, `packages/brepjs-cad`, `packages/brepjs-viewer`, and `packages/brepjs-voxel`. Everything else at the repo root — including `docs/`, `scripts/`, and CI config — feeds the root release. Any commit with `!` (or a `BREAKING CHANGE:` footer) touching those paths major-bumps the published `brepjs` library. Never put `!` on site, docs, or tooling commits. When a change genuinely is breaking, confirm it touches the library surface before marking it. Full release pipeline: release-publishing skill. ## Branches and worktrees - Branch naming: `<type>/<kebab-description>` where type is the conventional-commit type of the work — `feat/judge-graded-reference-verdict`, `fix/memory-leak`, `docs/api-examples`. (`CONTRIBUTING.md` shows an older `feature/` prefix; current practice uses the commit type.) - Worktrees for parallel branches go under `.worktrees/<branch>` inside the repo — gitignored (`.gitignore`) and excluded from the root vitest suite (`vitest.config.ts` excludes `.worktrees/**` and `.claude/worktrees/**`, because a stale worktree copy without WASM set up would otherwise fail the root suite): ```bash git worktree add .worktrees/feat-my-change feat/my-change ``` - Run `gh pr merge` from the main repo path, never from inside the worktree — deleting the branch while its worktree has it checked out fails. - After merge: `git worktree remove .worktrees/<branch>`, then in the main tree `git checkout main && git pull`. The repo deletes branches on merge, so the local branch goes `[gone]`; prune with `git fetch --prune`. ## PR flow 1. Push the branch and open a PR filling `.github/pull_request_template.md` (what/how-to-test/checklist). 2. CI runs the jobs feeding `ci-pass`: typecheck, lint (eslint + `format:check`), quality (`check:boundaries` + `check:patterns` + `knip`), build (including the `docs/function-lookup.md` staleness diff), playground-build, per-package jobs (viewer/verify/sheetmetal/bim), voxel-wasm-rust, the 4-way-sharded `test` job, size, and benchmark. The `coverage` job runs on main only, `continue-on-error`, and is not part of `ci-pass`. CI failures: see the ci-triage skill. 3. The benchmark job posts a PR comment comparing against main with a 25% regression threshold. 4. **Reviews:** branch protection on `main` requires only the `ci-pass` status check — zero required approvals. Two AI reviewers (Greptile, configured in `.greptile/config.json`, and cubic) review every PR but are not required checks. **Wait for both AI reviews to land before arming `gh pr merge --auto`** — auto-merge armed early merges the moment `ci-pass` goes green, and real defects have been caught in reviews that arrived post-merge. 5. Merge is squash-only; the squash commit title becomes the release-please changelog entry, so make the PR title a valid conventional commit. 6. After merge: checkout main and pull immediately (the remote branch is auto-deleted). **Release PRs** (`release-please--*` head refs) skip the code-CI path and are auto-merged by `.github/workflows/release-please.yml` with strict ordering: the root `brepjs` release PR merges first; leaf release PRs (cad/bim/sheetmetal) are held while root is open, because the node-workspace plugin pins leaves to the pending root version — merging a leaf early leaves main pinned to an unpublished version and breaks `npm ci` with ETARGET. `brepjs-opencascade` is permanently held for manual merge. Do not manually merge release PRs out of this order. ## Symptom → cause → fix | Symptom | Cause | Fix | | ------------------------------------------------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | Pre-commit fails with layer VIOLATION | Upward import across layers | architecture-navigation skill; `npm run check:boundaries` for the full report | | Pre-commit fails in `check-patterns` | New pattern violation in staged `src/` file | See quality-gates (fix vs. baseline) | | Every open PR fails `quality`/`check:patterns` | Unbaselined violation reached main (CI checks the PR merged with main) | See quality-gates (baseline-bump-first recovery) | | CI `build` fails on `git diff --exit-code docs/function-lookup.md` | Stale generated lookup after `*Fns.ts` change | See adding-operations (function-lookup gate) | | Commit rejected: "subject may not be empty" / "type must be one of" | Message not `type(scope): subject` | Rewrite per `CONTRIBUTING.md` commit types | | Published `brepjs` unexpectedly major-bumped | `!` or `BREAKING CHANGE:` on a docs/tooling commit | Never mark non-library commits breaking; `docs/` is not in root `exclude-paths` | | P1 review comment appears after merge | Auto-merge armed before AI reviews landed | Wait for Greptile + cubic before `gh pr merge --auto` | | `npm ci` fails ETARGET after a release merge | Leaf release PR merged while root `brepjs` release was open | Merge root first; let the workflow regenerate leaf PRs | | `git worktree remove` or branch delete fails | Branch checked out in a worktree / merge run from inside it | Operate from the main repo path; remove the worktree first | | Local branch shows `[gone]` after merge | `delete_branch_on_merge` removed the remote branch | `git checkout main && git pull && git fetch --prune`, delete the local branch | ## Additional resources - `CLAUDE.md` — "Git hooks" and "Commits" sections (concise summary of the above) - `CONTRIBUTING.md` — Development Workflow, Commit Conventions, Pull Request Process - `.claude/commands/verify.md` — wraps `npm run validate` + the function-lookup reminder - Sibling skills: `architecture-navigation` (boundary failures), `writing-tests` (test failures), `quality-gates` (lint/pattern/knip details), `ci-triage` (CI job debugging), `release-publishing` (release-please pipeline)
More Git Workflows skills
git-commit
github/awesome-copilot
Execute git commit with conventional commit message analysis, intelligent staging, and message generation. Use when user asks to commit changes, create a git commit, or mentions "/commit". Supports: (1) Auto-detecting type and scope from changes, (2) Generating conventional commit messages from diff, (3) Interactive commit with optional type/scope/description overrides, (4) Intelligent file staging for logical grouping
git-workflow-and-versioning
addyosmani/agent-skills
Structures git workflow practices. Use when making any code change. Use when committing, branching, resolving conflicts, or when you need to organize work across multiple parallel streams. Use when cutting a release, choosing a semantic version bump, tagging, or writing a changelog.
resolve-merge-conflicts
warpdotdev/common-skills
Resolve Git merge conflicts by extracting only unresolved paths, conflict hunks, and compact diffs instead of loading whole files into context. Use when a merge, rebase, cherry-pick, or stash pop stops on conflicts, when `git status` shows unmerged paths, or when files contain conflict markers.

