GitHub controls reference¶
Golden-path controls validated on WU repos (e.g. wiresuncrossed/hoen-assessment).
Use with diagnostic-prompt.md.
Concepts¶
| Mechanism | Purpose |
|---|---|
| Rulesets | Modern replacement for branch protection; org or repo scoped |
| Branch protection (legacy API) | May 404 when rulesets-only — use rulesets API |
| Repo merge settings | Which merge buttons appear on PRs |
| Merge method ruleset rule | Restrict PR merges to rebase / squash / merge commit |
| Push rulesets | Block pushes by file size, path, etc. |
Stacking: org rulesets + repo rulesets both apply. Repo settings must allow any merge method the ruleset requires.
Ghost branches and squash¶
Squash merge creates one new commit on main. The PR branch tip is not an
ancestor of that commit → GitHub shows "1 commit ahead" on stale branches.
Rebase merge replays commits onto main so branch tips become ancestors
(when branch is updated). Auto-delete head branches removes stale refs.
Scan commands¶
Install gh first if needed — see gh-cli-install.md
(Windows, Git Bash, macOS, Linux/WSL).
Single repo¶
OWNER=wiresuncrossed
REPO=hoen-assessment
gh repo view "$OWNER/$REPO" \
--json name,defaultBranchRef,mergeCommitAllowed,squashMergeAllowed,rebaseMergeAllowed,deleteBranchOnMerge
gh api "repos/$OWNER/$REPO/rulesets" \
--jq '.[] | {id, name, source_type, enforcement, target}'
# Detail for each ruleset ID
gh api "repos/$OWNER/$REPO/rulesets/16769475" \
--jq '{name, enforcement, conditions, rules}'
All org repos (summary loop)¶
ORG=wiresuncrossed
gh repo list "$ORG" --limit 200 --json name,isArchived \
--jq '.[] | select(.isArchived == false) | .name' | while read -r repo; do
echo "## $repo"
gh repo view "$ORG/$repo" \
--json mergeCommitAllowed,squashMergeAllowed,rebaseMergeAllowed,deleteBranchOnMerge \
--jq .
gh api "repos/$ORG/$repo/rulesets" --jq '.[].name' 2>/dev/null || echo "(none)"
echo
done
Org rulesets (requires org admin scope)¶
Golden-path — repo settings only¶
Pilot on one repo before org rollout:
gh repo edit "$OWNER/$REPO" \
--enable-merge-commit=false \
--enable-squash-merge=false \
--enable-rebase-merge=true \
--delete-branch-on-merge=true \
--allow-update-branch
Verify:
gh repo view "$OWNER/$REPO" \
--json mergeCommitAllowed,squashMergeAllowed,rebaseMergeAllowed,deleteBranchOnMerge
Golden-path — rulesets (UI)¶
Create at Settings → Rules → Rulesets → New branch ruleset (repo) or Organization settings → Rules → Rulesets (org).
Protect Main (branch ruleset)¶
| Rule | Setting |
|---|---|
| Target | Default branch / refs/heads/main |
| Restrict deletions | On |
| Block force pushes | On (non_fast_forward) |
| Require linear history | On |
| Require status checks to pass | On — see below (do not skip) |
Required status checks (merge gate)¶
Gap to catch: ruleset protects main (no force-push / linear history / PR
required) but does not list required checks → PRs can merge while CI is
pending or red. Workflows existing under .github/workflows/ is not enough.
| Step | Action |
|---|---|
| 1 | Confirm rule type REQUIRED_STATUS_CHECKS on the Protect Main ruleset (or legacy branch protection) |
| 2 | Discover exact check contexts from recent PRs + workflow job ids (GitHub’s reported name is usually the job id, not the workflow name:) |
| 3 | Require verify jobs (validate, test, lint, commitlint). Prefer not requiring deploy/preview jobs that need third-party secrets |
| 4 | Enable “require branch up to date” / strict checks when the team accepts rebase-before-merge friction |
| 5 | Ask the user to verify the proposed context list before applying — names vary by repo and rename when job ids change |
Discovery helpers:
# Job ids from workflow YAML (candidates for required contexts)
rg -n '^jobs:' -A 20 .github/workflows/*.yml
# Names GitHub actually reported on recent merged PRs — see diagnostic-prompt Phase 3b
Example (hoen-library): require validate and commitlint; leave
build-deploy optional (Cloudflare Pages deploy).
When recommending remediation, present the exact strings to add in the UI (Settings → Rules → Rulesets → Protect Main → Require status checks to pass) and wait for user confirmation.
Rebase merge only (branch ruleset)¶
Add rule: Pull request merge method → allow Rebase only.
Requires repo: allow_rebase_merge=true, squash and merge commit disabled.
No large files (push ruleset)¶
| Setting | Example |
|---|---|
| Target | Push |
| Max file size | 3 MB |
| Enforcement | Active |
Org-level example name: No large files (>3mb).
UI audit mode (no gh)¶
Ask the user for screenshots or values from:
- Settings → Rules → Rulesets — list names, enforcement, targets, rule types
- Open Protect Main (or equivalent) — confirm Require status checks to pass and list the named checks (empty list = gap)
- Settings → General → Pull Requests — merge commit / squash / rebase toggles; auto-delete head branches
- Settings → General — default branch name
- Branches page — behind/ahead on stale feature branches (ghost-branch check)
- A recent PR’s Checks tab — compare displayed job names to the ruleset list
Remediation — large file already in git¶
- Move artifact to R2 / release asset / LFS
- Update docs to link or download instructions (not a raw blob in repo)
- Remove from tree; add path to
.gitignore - Rewrite feature branch history:
# Prefer git-filter-repo (install separately)
git filter-repo --path "path/to/large.zip" --invert-paths --force
# Or filter-branch (built-in, slower)
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f \
--index-filter 'git rm --cached --ignore-unmatch "path/to/large.zip"' \
-- BRANCH_NAME
git push --force-with-lease origin BRANCH_NAME— user approval required- Rewriting
mainrequires org admin and team coordination