Skip to content

Version control policy hardening

When to use: Audit or retrofit branch protection, merge methods, and push rules so main stays protected with a clean, linear history — and large binaries stay out of git.

Instructions

1. Orient before scanning

Ask the user (prefer AskQuestion when available):

  1. Scope — single repo (OWNER/REPO) or all repos in an org?
  2. Host — GitHub (default), Azure DevOps, or Bitbucket?
  3. Policy level — start repo-specific or apply at org/project level?
  4. Output — gap report only, or also apply fixes (requires explicit approval per change)?

If scope is unclear, default to one repo the user names, then offer an org roll-up after the first report.

2. Check tooling

GitHub (primary path): prefer GitHub CLI (gh).

gh --version
gh auth status

If gh is missing or unauthenticated:

  • See references/gh-cli-install.md for install on Windows, Git Bash, macOS, and Linux/WSL.
  • Quick paths: winget install --id GitHub.cli (Windows), brew install gh (macOS), sudo apt install gh (Ubuntu/WSL).
  • Run gh auth login.
  • If CLI is not an option, guide the user through Settings → Rules and Settings → General → Pull Requests in the GitHub UI and ask for screenshots of rulesets and merge settings.

Azure DevOps / Bitbucket: no single CLI covers policy audit well — use host UI paths in references/other-platforms.md and ask for screenshots or exported policy JSON where available.

3. Run the diagnostic

Follow references/diagnostic-prompt.md step by step. Use references/github-controls.md for exact gh commands and the WU golden-path controls.

Collect evidence before recommending changes. Do not change org or repo settings unless the user explicitly approves each action.

4. Produce the gap report

Use references/gap-report-template.md.

Rank findings P0 → P3. Typical P0 gaps:

  • main accepts direct pushes or merge commits
  • All merge methods enabled (squash causes ghost branches after merge)
  • No push rule blocking large files (>3 MB)
  • Head branches not auto-deleted after merge

5. Recommend remediation (retrofit order)

Apply in this order unless the user has a reason not to:

Step Control GitHub (repo-level start)
1 Protect main Ruleset: block deletion, block force-push, require linear history
2 Rebase-only merges Disable squash + merge commit; enable rebase; optional merge-method ruleset
3 Auto-delete head branches --delete-branch-on-merge=true
4 Allow update branch --allow-update-branch (helps rebase merge when PR is behind)
5 Large-file push block Ruleset: max file size (e.g. 3 MB) on push
6 Local dev hygiene Point to git-hygiene skill; .gitignore for local extracts; store binaries in object storage (R2/LFS)

Repo vs org: ask the user where to land policies.

  • Repo-first — pilot on one repo; lower blast radius; good for proving the workflow.
  • Org-level — consistent defaults (Protect Main, file-size push rule); repos inherit; harder to roll back.

Document trade-offs in the report; do not assume org access.

6. Local dev and history (when gaps involve large files or ghost branches)

Cross-reference the git-hygiene skill for day-to-day branch workflow.

Additional guidance:

  • Ghost "1 commit ahead" branches after squash merge — stale branch tip; not missing work. Fix: auto-delete head branches + rebase merge; delete or reset stale branches.
  • Large file already pushed — remove from tree, store in R2/LFS, rewrite branch history (git filter-repo preferred over filter-branch), force-push feature branch only after user approval. Scrubbing main requires org admin coordination.
  • Pre-commit — optional local gate (docs:validate, link checks) — complements but does not replace server-side push rules.

References

Related skills: git-hygiene, gap-analysis, commit-message-conventions


Troubleshooting

Symptom Likely cause Fix
gh: command not found CLI not installed gh-cli-install.md — Windows, Git Bash, macOS, Linux
Branch not protected (404) Protection via rulesets, not legacy API Use gh api repos/OWNER/REPO/rulesets
Rebase merge disabled on PR Branch behind base or conflicts Update branch or rebase locally; enable --allow-update-branch
Merge blocked despite repo settings Ruleset merge-method rule conflicts with disabled method Align repo merge flags with ruleset allowed methods
Org ruleset + repo ruleset stack Both apply Repo rules add constraints; document combined effect
required_linear_history but squash still allowed Linear history allows squash or rebase Disable squash at repo level or add merge-method ruleset for rebase-only
Large file blocked on push Push ruleset active Store artifact externally; link from docs; scrub history if already committed

Error: User wants rebase-only but org mandates squash for some repos
Cause: Org ruleset may allow multiple merge methods
Solution: Repo-level merge-method ruleset or repo settings override where permitted; escalate to org admin if blocked