/ship
End-to-end "land this on main" workflow for Cotabby. The goal is a single linear
commit on main — squash merge, never a merge commit. Cotabby's main ruleset
rejects merge commits, so squashing is what keeps history clean; --admin bypasses
the required-status-check protection so the owner can merge directly.
$ARGUMENTS is optional:
- empty → branch off the latest
origin/mainwith a derived name - a branch name (e.g.
feat/foo) → use/create that branch instead of deriving one from <ref>→ base the new branch on<ref>instead oforigin/main
Steps
Establish the branch.
git fetch origin.- If the user is already on a feature branch that holds the work, keep it.
- Otherwise (on
main/detached, or a branch name was given), create the branch off the latest base:git checkout -b <name> origin/main(or thefrom <ref>base). Derive<name>from the change:feat/,fix/, orchore/+ a short kebab slug. Never do the work directly onmain.
Commit the work. Stage and commit anything pending. Follow the repo's GitHub rules in
.claude/CLAUDE.md: noCo-Authored-Bytrailers. Write a concise, real commit message.Validate before pushing. Run the narrowest useful checks, broaden if shared behavior changed:
swiftlint lint --quiet xcodebuild -project Cotabby.xcodeproj -scheme Cotabby -destination 'platform=macOS' buildFor test-affecting changes also run
build-for-testing. Localtestexecution often fails on a Team ID / signing mismatch — that's an environment issue, not a code failure; report it and rely onbuild-for-testingsucceeding.- XcodeGen:
project.ymlis the source of truth andCotabby.xcodeprojis generated. New files underCotabby/andCotabbyTests/are auto-discovered — no project edit needed. Only structural changes (targets, build settings, packages, scheme) require editingproject.ymlthenxcodegen generateand committing the regenerated project. Fix all lint/build errors before continuing.
- XcodeGen:
Push.
git push -u origin <branch>.Open the PR using the repo template. Read
.github/PULL_REQUEST_TEMPLATE.mdand fill in every section — Summary (what + why), Validation (what you actually ran and saw), Linked issues (Fixes #N/Refs #N), Risk / rollout notes. Do not invent a format. Use a heredoc body:gh pr create --base main --head <branch> --title "<title>" --body "$(cat <<'EOF' ## Summary ... EOF )"Confirm, then squash-merge with admin bypass. Merging to
mainis an irreversible outward action — show the PR URL and the one-line summary, and get an explicit go-ahead unless the user already said to merge in this turn. Then:gh pr merge <branch-or-#> --squash --admin --delete-branch--squashkeeps main linear (no merge commit → satisfies the ruleset);--adminbypasses required checks;--delete-branchcleans up the remote branch.Sync local main.
git checkout main && git pull --ff-only origin mainConfirm
mainnow contains the squashed commit and report the result.
Guardrails
- Never force-push
mainor rebase published history to "fix" merges. Iforigin/mainmoved while you worked, integrate it (rebase the branch onto the neworigin/main) and re-validate — don't clobber others' commits. - Never delete or overwrite work you didn't create without checking it first.
- If validation fails, stop and surface the failure — don't merge red.
- If the user named a target other than
main, ship there instead, but keep the squash-merge shape.