restructure-commits
Skill551 starsChanged 6 months agoApache-2.0View on GitHub
Restructure branch commits into logical component-based commits for HyperShift PRs
- Deletes or force-pushes
- Commits and pushes
In this repository26 other files it gives its agents.
- AGENTS.mdAGENTS.md
- api/AGENTS.mdAGENTS.md
- control-plane-operator/AGENTS.mdAGENTS.md
- .cursor/rules/100-go-mistakes.mdcCursor rule
- .cursor/rules/code-formatting.mdcCursor rule
- .cursor/rules/code-review.mdcCursor rule
- .cursor/rules/create-jira-items.mdcCursor rule
- .cursor/rules/debug-aro-hcp-e2e.mdcCursor rule
- .cursor/rules/git-commit-format.mdcCursor rule
- .cursor/rules/restructure-commits.mdcCursor rule
- create-cpo-overrideSkill
- Debug ClusterSkill
- e2e-analyzeSkill
- Effective GoSkill
- feature-developmentSkill
- fix-hypershift-repo-robot-prSkill
- Git Commit FormatSkill
- konflux-buildSkill
- Konflux Archived PipelineRunsSkill
- pr-reportSkill
- restructure-commitsSkill
- test-tag-pipelineSkill
- triage-leaked-infraSkill
- update-konflux-tasksSkill
- validate-pr-override-imagesSkill
- Git Commit FormatSkill
The file
We split this skill into the rules it gives an agent
8 rules. About 0 are common, 2 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 23
Commit groups in this order and skip groups with no changes:
- Very specific: line 48
Only test/, api//*_test.go, and CRD envtest suites go to E2E.
- Very specific: line 81
If the remote branch has commits that are not in local HEAD (review suggestions, "Update branch", a collaborator's push), stop and ask the …
- Very specific: line 84
Finish background work: Wait for running generators, formatters, make update, or tests that write files.
- Very specific: line 85
Handle existing work explicitly: If git status --porcelain --untracked-files=all is not empty, stop and ask whether to commit it to the …
- Distinctive: line 88
Never use git reset --hard, git checkout -- ., git clean, or drop stashes or branches.
- Very specific: line 148
Read and follow skills/git-commit-format/SKILL.md directly (harnesses with native skill support may load it as the git-commit-format skill).
- Very specific: line 151
Use the group's prefix from the table.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Restructure Commits by Component
Rewrite a feature branch into one commit per architectural group (API, Dependencies, Vendor, CLI, HO, CPO, E2E, Docs, Tooling) without changing the branch's final file content.
This is the canonical, model-neutral procedure. Any coding agent or human can follow it with git, python3
(standard library only), make, and optionally gh. All paths are relative to the repository root.
When to Use
- The user asks to "redo", "restructure", "squash by component", or "organize" commits
- Preparing a branch for PR review, or cleaning history after addressing review comments
Ownership
ownership.json maps every path to a group; commit_layout.py applies it. Both the file and the table below are
generated by generate_ownership.py (make ownership-rules, also run by make update); never edit them by hand.
Commit groups in this order and skip groups with no changes:
<!-- BEGIN GENERATED: python3 skills/restructure-commits/generate_ownership.py -->| Order | Group | Commit prefix | Allowed <type> | Owns |
| 1 | API | <type>(api) | feat, fix, build, refactor | API types, markers, and the api/ module definition (api/go.mod and api/go.sum stay together) |
| 2 | Dependencies | build(deps) | fixed | Root, tools, and workspace module definitions; never mixed with generated vendor trees |
| 3 | Vendor | chore(api) | fixed | Generated output: vendor trees, clients, zz_generated files, generated CRD manifests, and other files marked as generated |
| 4 | CLI | <type>(cli) | feat, fix, refactor, test | hypershift and hcp CLIs, with their tests, testdata, and fixtures |
| 5 | HO | <type>(hypershift-operator) | feat, fix, refactor, perf, test | hypershift-operator binaries and Go code shared by binaries of more than one group |
| 6 | CPO | <type>(control-plane-operator) | feat, fix, refactor, perf, test | control-plane-operator binaries and the Go code only they use, such as control plane sidecars |
| 7 | E2E | test(e2e) | fixed | E2E, integration, and envtest suites, including API validation tests |
| 8 | Docs | docs | fixed | User and contributor documentation and agent guidance files |
| 9 | Tooling | <type>(<scope>) | build, ci, chore, docs | Everything else: build system, CI configuration, scripts, container builds, helper modules, AI agent tooling |
<!-- END GENERATED -->- Derived, not curated. Each binary built by
make buildbelongs to the group in the generator's policy, and other top-level Go directories follow the binaries that import them (several groups: HO; none: Tooling). Files marked as generated, Makefile output directories, and vendor trees go to Vendor; hand-written files inside them keep their component's group. - First match wins. Specific exceptions are listed before broad directories;
ownership.jsonlists the rules in precedence order with the reason for each. - Modules vs generated trees:
api/go.modandapi/go.sumstay in API; root, tools, and workspace module files go in Dependencies; every vendor tree goes in Vendor. A commit must never mix module definitions with vendor output. - Tests and fixtures: component tests,
testdata/, andzz_fixture_*files stay with their owning component. Onlytest/,api/**/*_test.go, and CRD envtest suites go to E2E. - No silent defaults: an unclassified path blocks the rewrite. Run
make ownership-rules, which gives every path in the checkout a group, and commit the result before the snapshot. If a derived group is wrong, agree the right one with the user and change the generator's policy (see Maintenance). - Several consecutive commits in the same group are allowed; groups must never interleave or appear out of order.
Procedure
TOOL=skills/restructure-commits/commit_layout.py1. Preflight (read-only except for the backup branch)
Resolve the real target. Determine the PR base repository and branch, for example from
gh pr view --json url,baseRefName; ask the user when there is no PR. Pick the remote whose URL points at that base repository and the remote that hosts the PR branch. Do not assume remote names, do not assumemain(release branches are valid targets), and do not rebase unless the user asks for it.BRANCH=$(git symbolic-ref --short HEAD) TARGET_REMOTE=<remote for the PR base repository> TARGET_BRANCH=<PR base branch, e.g. main or release-4.18> PUSH_REMOTE=<remote that hosts $BRANCH> git fetch "$TARGET_REMOTE" "refs/heads/$TARGET_BRANCH" MERGE_BASE=$(git merge-base FETCH_HEAD HEAD) PUSHED_SHA=$(git ls-remote "$PUSH_REMOTE" "refs/heads/$BRANCH" | cut -f1) # empty if never pushed if [ -n "$PUSHED_SHA" ]; then git fetch "$PUSH_REMOTE" "refs/heads/$BRANCH" git merge-base --is-ancestor "$PUSHED_SHA" HEAD || echo "STOP: remote $BRANCH has commits not in HEAD" fiIf the remote branch has commits that are not in local
HEAD(review suggestions, "Update branch", a collaborator's push), stop and ask the user to integrate them first; the rewrite would otherwise discard them.- Finish background work. Wait for running generators, formatters,
make update, or tests that write files. - Handle existing work explicitly. If
git status --porcelain --untracked-files=allis not empty, stop and ask whether to commit it to the branch first, stash it withgit stash push --include-untracked -m "restructure-commits: preserved work"(restore it at the end), or abort. Never usegit reset --hard,git checkout -- .,git clean, or drop stashes or branches. Record the snapshot and create a backup branch. Report these values to the user.
ORIG_HEAD_SHA=$(git rev-parse HEAD) ORIG_TREE=$(git rev-parse "HEAD^{tree}") BACKUP="backup/restructure/$BRANCH-$(date +%Y%m%d%H%M%S)" git branch "$BACKUP" "$ORIG_HEAD_SHA"Show the complete plan. Resolve every unclassified path, then present the file-to-commit plan with the proposed commit subjects and get the user's approval before rewriting.
python3 "$TOOL" plan --base "$MERGE_BASE" --head "$ORIG_HEAD_SHA"
2. Rewrite history (lossless)
git reset --soft "$MERGE_BASE" && git reset -q # index = merge base; working tree still equals $ORIG_TREEFor each non-empty group, in table order:
python3 "$TOOL" stage --base "$MERGE_BASE" --head "$ORIG_HEAD_SHA" --group <GROUP>
git commit -s # message rules belowstage copies exactly that group's paths (including deletions and paths with spaces) from the snapshot into the
index and fails if anything else is staged.
3. Verify (required before declaring completion)
python3 "$TOOL" verify --base "$MERGE_BASE" --head HEAD --expect-tree "$ORIG_TREE"
make run-gitlint PULL_BASE_SHA="$MERGE_BASE" PULL_PULL_SHA=HEAD # message syntax only, not file grouping
git status --porcelain --untracked-files=all # must be emptymake verify-commit-layout BASE="$MERGE_BASE" EXPECT_TREE="$ORIG_TREE" is equivalent to the first command. Without
make, run gitlint --commits "$MERGE_BASE..HEAD" instead. The layout check verifies that every commit in the range
touches a single group, that groups are in order, and that no path is unclassified, and confirms the final tree
equals the snapshot. If it fails, do not push: fix the commits and re-run, or show
git diff "$ORIG_TREE" HEAD and, with the user's agreement, return to the snapshot with git reset --keep "$BACKUP".
Restore any stash from preflight with git stash pop.
4. Push (only after explicit user confirmation)
git push --force-with-lease="refs/heads/$BRANCH:$PUSHED_SHA" "$PUSH_REMOTE" "HEAD:refs/heads/$BRANCH"The lease protects against remote updates made after preflight (earlier ones were checked in preflight). If it is
rejected, stop and ask. Keep $BACKUP until the user agrees to
delete it.
Commit Messages
Read and follow skills/git-commit-format/SKILL.md directly (harnesses with native skill support may load it as
the git-commit-format skill). Validate with gitlint as shown above.
- Use the group's prefix from the table. Where it contains
<type>, pick the allowed type that describes the change (featnew behavior,fixbug fix,builddependency or build change,refactorrestructuring or removal,perfperformance,testtest or fixture-only change); for Tooling also choose a fitting scope such asci(envtest). Fixed prefixes are used as-is; Docs isdocs:without a scope. - Subject: imperative mood, describes the purpose (for example
build(deps): bump Kubernetes dependencies to 1.37). - Body: what changed and why, bullets for distinct changes; title at most 120 and body lines at most 140 characters.
Maintenance
- Change ownership: edit the POLICY section of
generate_ownership.py(groups, binary groups, conventions), then runmake ownership-rulesandmake test-commit-layout. Becausemake updateregenerates the rules,make verifyfails when a PR leavesownership.jsonor this table stale. - Practice or demonstrate:
python3 skills/restructure-commits/sample_branch.py <empty-dir>builds a repository whose branch reproduces the PR #9568 module/vendor mistake; follow this procedure in<empty-dir>/work. - Enforcement scope: the layout check is a required gate of this workflow only; it is not enforced repository-wide
by pre-push hooks or CI. Gitlint remains the repository-wide message check. The tool's own tests run in the
path-filtered
Unit Tests (Restructure Commits)GitHub workflow. - Adapters: harness-specific entry points (
.claude/skills/restructure-commits/SKILL.md,.cursor/rules/restructure-commits.mdc) only point here. Replace personal copies (such as a user-installedrestructure-hypershift-commitsskill) with a pointer to this file instead of maintaining separate rules.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

