fix(bin): print git switch instead of git checkout for branch commands - #3048
Open
joaodiniz99 wants to merge 2 commits into
Open
fix(bin): print git switch instead of git checkout for branch commands#3048joaodiniz99 wants to merge 2 commits into
joaodiniz99 wants to merge 2 commits into
Conversation
Confidence Score: 5/5The PR appears safe to merge with no actionable defects identified. The changed commands are semantically appropriate for branch creation and switching, output documentation and tests remain aligned, and no reachable regression or repository-rule conflict was established. Reviews (1): Last reviewed commit: "no-mistakes(document): align tangle docs..." | Re-trigger Greptile |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Replace every INSTRUCTION this repository prints that tells an agent to run 'git checkout' with the equivalent 'git switch' form. Scope: three confirmed printed-instruction sites - bin/fm-brief.sh's generated ship-brief setup step ('git checkout -b fm/$ID' -> 'git switch -c fm/$ID'), bin/fm-guard.sh's tangle remediation printf, and bin/fm-bootstrap.sh's TANGLE diagnostic remediation echo - plus every tracked prose site that quotes those printed commands (found: .agents/skills/bootstrap-diagnostics/SKILL.md) and every test assertion matching the old printed strings (found and updated: tests/fm-tangle-guard.test.sh, tests/fm-session-start.test.sh). Reason for the change, for the PR description: git permission policies commonly deny git checkout outright because its file-restoring forms discard uncommitted work, which would block the very first instruction this repo prints to an agent (git checkout -b) and stop all work; git switch -c / git switch are the purpose-built modern equivalents (Git 2.23+, 2019) and are strictly safer since they refuse rather than discard conflicting local modifications, with destructive behavior gated behind explicit --force/--discard-changes flags a permission policy can deny on its own - so this is the objectively correct command for what these lines do, not a workaround. Explicitly OUT of scope, left untouched on purpose: git checkout calls a script EXECUTES itself (never printed as an instruction to an agent) in bin/fm-teardown.sh:2682 and :2695 and bin/fm-remote-secondmate-control.sh:277, since those run inside a script process and are never subject to an agent permission layer; bin/fm-tangle-lib.sh's comment, which uses 'checkout' as a noun, not a command; and every 'git checkout' invocation inside tests/ that is test-fixture setup executing the command itself rather than asserting on printed output (e.g. tests/fm-bearings-snapshot.test.sh, tests/fm-fleet-sync.test.sh, tests/fm-crew-state.test.sh, tests/fm-tangle-guard.test.sh's own repo-state helpers). No renaming, no restructuring, no unrelated fixes - diff is exactly these 6 files, 12 changed lines. Verification already performed by me: ran tests/fm-tangle-guard.test.sh, tests/fm-session-start.test.sh, tests/fm-bootstrap.test.sh, and tests/fm-brief.test.sh individually and via bin/fm-test-run.sh (all pass, 0 failures); ran bin/fm-lint.sh with pinned ShellCheck 0.11.0 and actionlint 1.7.12 installed locally (clean, exit 0); ran bin/fm-doc-audience-check.sh (ok). This PR targets a fork (push remote https://github.com/joaodiniz99/firstmate.git, PR opens against upstream kunchenguid/firstmate) - the PR description must stand alone for a maintainer with none of this context, state the defect and the general git-switch-is-correct/safer argument, and must NOT mention any individual machine's permission configuration as the motivation.
What Changed
git switchform: the generated ship brief's first setup step (git switch -c fm/$IDinbin/fm-brief.sh), the tangle remediation banner inbin/fm-guard.sh, and theTANGLE:diagnostic remediation inbin/fm-bootstrap.sh(git -C <root> switch <default>)..agents/skills/bootstrap-diagnostics/SKILL.mdnow quotesgit -C <root> switch <default>, anddocs/configuration.mddescribes the omitted remediation as the "branch-restore command" rather than "the checkout command" (same wording fix in thebin/fm-bootstrap.shheader comment).tests/fm-tangle-guard.test.shandtests/fm-session-start.test.sh, including the brief guard that locates the branch step bygit switch -c fm/.git checkoutcalls that a script executes itself, and test-fixture setup that runs the command directly, are unchanged: only printed instructions moved.Risk Assessment
✅ Low: A mechanical, semantically equivalent 12-line substitution of
git checkoutwith the purpose-builtgit switchform in three printed-instruction sites plus their prose and test assertions, with no consumer coupled to the old strings and no behavioral difference reachable given how the default branch name is resolved.Testing
Ran the four targeted suites named in the intent (fm-tangle-guard, fm-session-start, fm-brief, fm-bootstrap) individually — all pass, zero failures — and then produced product-level evidence rather than relying on those assertions: I generated a real ship brief and executed its printed first action (git switch -c fm/switch-demo-e2e) verbatim inside a detached-HEAD worktree, and I stranded a temp primary on a feature branch to trigger both the fm-guard banner and the fm-bootstrap TANGLE diagnostic, then ran the printedgit -C <primary> switch mainand confirmed the primary was restored with the feature branch intact. A before/after run of the base-commit scripts against identical inputs shows all three sites moving fromcheckouttoswitch, and a small git demo backs the PR's safety argument by showinggit checkout -- <file>silently discards uncommitted work whilegit switchhas no such form. This change has no UI, HTML, or rendered surface — the end-user surface is CLI and generated-Markdown text, so the evidence is captured as command transcripts and the generated brief section. I also confirmed the intent's out-of-scope claim holds: every remaininggit checkoutin bin/ and tests/ is a command a script executes itself or test-fixture setup, never an instruction printed to an agent. The worktree is clean; all scratch repos were created under /tmp.Evidence: Generated ship brief: the Setup section a crewmate agent reads
Source: Generated ship brief: the Setup section a crewmate agent reads
# Setup You are in a disposable git worktree of alpha, at a detached HEAD on a clean default branch. Verify isolation before anything else. Runpwd -Pandgit rev-parse --show-toplevel; both must resolve to the disposable task worktree you were launched in... 1. First action: create your branch:git switch -c fm/switch-demo-e2e2. Runno-mistakes doctor; if it reports the repo is not initialized here, runno-mistakes init.Evidence: Agent follows the printed instruction verbatim (end-to-end)
Source: Agent follows the printed instruction verbatim (end-to-end)
$ disposable worktree state before the first action: ## HEAD (no branch) $ # command copied verbatim out of the generated brief $ git switch -c fm/switch-demo-e2e Switched to a new branch 'fm/switch-demo-e2e' $ git -C <worktree> status -sb ## fm/switch-demo-e2e RESULT: the first instruction the repo prints to an agent executes cleanly and creates the task branch.Evidence: Tangle remediation: fm-guard banner + fm-bootstrap diagnostic, then the printed command run
Source: Tangle remediation: fm-guard banner + fm-bootstrap diagnostic, then the printed command run
$ bin/fm-guard.sh # what the captain sees ● WORKTREE TANGLE - PRIMARY CHECKOUT IS ON A FEATURE BRANCH ● <primary> is on 'fm/readme-restructure-d3', not its default branch 'main'. ● The work is SAFE on the 'fm/readme-restructure-d3' ref. ● Restore the primary to 'main': ● git -C <primary> switch main ● then re-validate 'fm/readme-restructure-d3' in a proper isolated worktree. $ bin/fm-bootstrap.sh # the TANGLE diagnostic line TANGLE: primary checkout on feature branch 'fm/readme-restructure-d3' (expected 'main'); the work is safe on that ref - restore the primary with: git -C <primary> switch main, then re-validate the branch in a proper worktree $ # captain copies the printed restore command verbatim and runs it $ git -C <primary> switch main Switched to branch 'main' $ git -C <primary> branch --list fm/readme-restructure-d3 # the work is still there fm/readme-restructure-d3Evidence: Before/after on identical inputs (base 6a2cd6c vs this change)
Source: Before/after on identical inputs (base 6a2cd6c vs this change)
[BEFORE] ship brief, step 1: 1. First action: create your branch:git checkout -b fm/ba-demo-77[BEFORE] fm-guard.sh tangle banner: ● git -C <primary> checkout main [BEFORE] fm-bootstrap.sh TANGLE diagnostic: git -C <primary> checkout main [AFTER] ship brief, step 1: 1. First action: create your branch:git switch -c fm/ba-demo-77[AFTER] fm-guard.sh tangle banner: ● git -C <primary> switch main [AFTER] fm-bootstrap.sh TANGLE diagnostic: git -C <primary> switch mainEvidence: Why git switch is the correct command, demonstrated
Source: Why git switch is the correct command, demonstrated
git version 2.50.1 $ git -C <repo> checkout -- f.txt # the file-restoring form: silently destroys it exit=0 f.txt is now: committed <-- work gone, no prompt, no confirmation $ git -C <repo> switch -- f.txt # git switch has no such form at all fatal: invalid reference: f.txt exit=128 f.txt is still: UNCOMMITTED WORK <-- work intactPipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
docs/configuration.md:338- docs/configuration.md:338-339 still describe the TANGLE remediation as "the printed checkout remediation" and "omits the checkout command", but the printed command is nowgit -C <root> switch <default>. These lines describe the command rather than quoting it, so they fall outside the intent's stated prose scope ("every tracked prose site that quotes those printed commands") and the intent explicitly caps the diff at these 6 files. Noting only; no change recommended in this change.✅ **Test** - passed
✅ No issues found.
bash tests/fm-tangle-guard.test.sh(6 assertions, exit 0) - covers the guard banner, bootstrap TANGLE line, and brief branch-step orderingbash tests/fm-session-start.test.sh(49 assertions, exit 0) - covers the read-only bootstrap and --reemit restore-remediation assertionsbash tests/fm-brief.test.sh(exit 0) - full ship-brief scaffolding suitebash tests/fm-bootstrap.test.sh(28 assertions, exit 0)Manual E2E: generated a real brief viaFM_HOME=<tmp> bin/fm-brief.sh switch-demo-e2e alpha --mode no-mistakes, then ran its printed step 1 (git switch -c fm/switch-demo-e2e) verbatim inside a detached-HEAD linked worktree and confirmed the branch was createdManual E2E: stranded a temp primary onfm/readme-restructure-d3, ranFM_ROOT_OVERRIDE=<repo> bin/fm-guard.shandbin/fm-bootstrap.sh, then executed the printedgit -C <primary> switch mainand confirmed the primary was restored with the feature branch intactManual before/after: ran base-commit (6a2cd6c) copies of fm-brief.sh, fm-guard.sh and fm-bootstrap.sh against identical inputs and diffed the printed commands against the current versionsManual rationale check: demonstrated thatgit checkout -- <file>silently discards uncommitted work whilegit switch -- <file>refuses (exit 128, file intact)Scope sweep:grep -rn "git checkout"over bin/, .agents/, docs and tests to confirm every remaining occurrence is script-executed or test-fixture setup rather than a printed instructiondocs/configuration.md:338- Judgment call, left intentionally unchanged:docs/configuration.md:338("follow the printed checkout remediation"),AGENTS.md:168and:176("without a checkout repair command"), anddocs/configuration.md:655("suppress ... checkout repair commands") all use "checkout" as a noun meaning the primary working copy, matchingbin/fm-tangle-lib.sh's comment that the change deliberately left alone. They remain accurate and were not reworded. Only the two bare "the checkout command" phrasings, which read as naming thegit checkoutcommand itself, were corrected.🔧 Fix: no lint fixes needed; linter clean with pinned tools
1 warning still open:
✅ **Push** - passed
✅ No issues found.