Git Workflow Gotchas
Prerequisites: @smith-principles/SKILL.md, @smith-standards/SKILL.md
CRITICAL
- Use
git mvfor renames (preserves history) - GPG sign all commits:
git commit -S -m "..." - Keep branches linear (prefer rebase over merge) - essential for stacked PRs, see
@smith-gh-pr/SKILL.mdStacked PRs - Verify the current branch (
git branch --show-current) beforegit commit,git push, orgit rebase— confirm it matches the branch you intend to modify - Create a dedicated branch (+worktree in background sessions, see
@smith-worktree/SKILL.md) before the first edit of any repo-file-modifying task — even when no commit is requested. Never start edits on the default branch or on an unrelated dirty branch. Mechanical backstop: thebranch-guardPreToolUse hook (smith-git/scripts/hooks/branch-guard.mjs, registered user-globally) blocks Edit/Write/NotebookEdit and Serena write tools on non-gitignored files while the repo is onmain/master/develop(or itsorigin/HEADdefault); per-repo opt-out is.claude/branch-guard.disabled. - Reserve force-push for personal branches only — never main or shared branches.
- Commit only to feature branches, never directly to main.
- Rebase only personal feature branches, never shared branches.
- Let git hooks run — skip
--no-verify. - Keep GPG signing enabled — skip
--no-gpg-sign.
Operation Boundaries
- Match action to request: list=list, create=create — treating "list", "check", or "show" as permission to create or modify is out of scope
- Create only the branches/tags that were actually requested, nothing beyond it
- State planned operations before multi-step workflows
- For scope/approval rules, see @smith-guidance/SKILL.md
- For PR creation rules, see
@smith-gh-pr/SKILL.md
Worktree Safety
- Before write operations (commits, pushes, dev servers, tests): verify
git rev-parse --show-toplevelmatches your intended working directory - If multiple worktrees exist, use
git worktree listto identify the correct one - If in wrong worktree: stop,
cdto the correct one before proceeding
Worktree Patterns
Git worktree basics:
git worktree add ../feature-branch feat/feature
git worktree list
git worktree remove ../feature-branch
Parallel branch work:
- Each worktree = independent working directory
- Share same
.git— branches, stash, reflog shared - Useful for: hotfix while mid-feature, parallel reviews
Claude Code integration:
-
isolation: "worktree"in Agent tool — auto-creates worktree for subagent, cleaned up when done -
For
EnterWorktree/ExitWorktree,bgIsolation,worktree.baseRef, and the squash-merge sync protocol see@smith-worktree/SKILL.md -
Worktree lifecycle hooks (create/remove) fire on worktree operations for custom automation
-
Agent worktrees auto-cleanup; persistent ones need manual
git worktree remove -
ALWAYS verify worktree path before write operations
-
NEVER leave orphaned worktrees (check
git worktree list) -
Clean up persistent worktrees after branch is merged
-
NEVER
git checkout «other-branch»in the PRIMARY working dir to inspect or test another branch — it tramples IDE/dev-server/test state in place. Use a worktree (git worktree add/EnterWorktree), which fails loudly if the branch is already checked out elsewhere.
Branch Naming
Pattern: type/description (Conventional Branch spec) — type MUST match
commit type, description is lowercase hyphen-separated words, e.g.
feat/auth-login. Full rules in @smith-style/SKILL.md Branch Names.
Commit Standards
Format: See @smith-style/SKILL.md for conventional commits.
Atomic commits: One logical change per commit, passes tests, reversible.
Attribution: AI-assisted commits carry an Assisted-by: trailer; the agent
never adds Signed-off-by: (only humans certify the DCO) — see
@smith-style/SKILL.md "Assisted-by attribution" for the rule and the
draft-file recipe. The Claude Code adapter for commits is
smith-ctx-claude/scripts/attribution-guard.mjs (one adapter for commits,
pull-request text and Slack drafts; smith-ctx-claude/references/HOOKS.md
"attribution-model-stamp"). A git commit, merge, pull, revert or
commit-tree is allowed only when it matches a signature declared in
smith-style/scripts/attribution-signatures.json:
git commit -F «absolute path»(or--file), run as a command of its own, whose file passes the rule.-m, the editor, a short flag cluster such as-aF,-s, a relative or expanded path, and a git global option other than-Cand--no-pagerare blocked.- A reused message passes:
--amend --no-edit,-C «commit»,--fixup,--squash;cherry-pick,rebaseandamare not covered. - A message git generates is blocked:
git mergewithout--ff-only,--squash,--no-commitor-F «absolute path»;git pullwithout--ff-onlyor--rebase;git revertwithout--no-commit(revert with--no-commit, then commit with-F);git commit-tree.
The adapter checks the agent, not git: commits made outside the agent's tool
calls, a git invocation hidden from the scanner (a program name built by
expansion, a git alias, git configuration set through GIT_CONFIG_*
environment variables, a git nested in another program's argument such as
rebase -x or find -exec) are not checked. Options that change the
message after it is written (--cleanup, a comment character) are blocked
on the command line but not read from config files.
Non-Obvious Flags
-u: Use on first push to set upstream tracking--force-with-lease: Safe force push for personal branches - required for stacked PRs after rebase, see@smith-gh-pr/SKILL.mdStacked PRs--no-ff: Preserve merge commit for feature branches (maintains history)-S: GPG sign commits
Status Output Semantics
??ingit status --shortmeans untracked AND NOT ignored. Ignored files do not appear ingit statusoutput at all. Reading??as "gitignored" inverts the meaning, and an all-??listing then looks like proof that a glob covers only disposable files when it proves the opposite.- Before deleting by glob, run
git ls-files <glob>to list the tracked files that glob covers, andgit check-ignore -v <path>to see which rule (if any) actually matches. Any output fromgit ls-filesis a stop signal — narrow the glob or handle those tracked paths explicitly before deleting. A directory full of untracked data files can still hold tracked ones under the same naming pattern, and deleting those is silent until a latergit statusshows aDentry. - Recover such a deletion with
git restore <path>, which restores the file's last committed (or staged) content — any uncommitted edits made before the delete are still lost. An untracked file deleted the same way cannot be recovered by git at all, so establish tracked-ness before the delete, not after.
Claude Code Plugin Integration
When commit-commands plugin is available:
/commit: Auto-generates commit message, stages files, creates commit before the message is shown; the user typing it accepts that, but an agent never runs it in place of showing the message for a yes/clean_gone: Cleans up branches deleted from remote (including worktrees)
Manual commands still needed for:
- GPG signing (
-Sflag) - Interactive rebase
- Force push with lease
Ralph Loop Commit Strategy
Atomic commits mark iteration boundaries. Include iteration number; enables git bisect for regressions.
See @smith-ralph/SKILL.md for full commit patterns.
Git Enforcement Hooks
smith-git owns all git operation enforcement hooks. These PreToolUse hooks enforce git-level rules deterministically via Claude Code's hook system.
Available hooks (smith-git/scripts/hooks/):
-
branch-guard.mjs — enforces branch-first rule (@smith-git CRITICAL)
- Matchers: Edit, Write, NotebookEdit, Serena write tools
- Blocks edits on default branch (main/master/develop)
- Per-repo opt-out:
.claude/branch-guard.disabled
-
branch-name-guard.mjs — enforces Conventional Branch naming (@smith-style)
- Matchers: Bash (git commands + git push), EnterWorktree
- Blocks: git branch/checkout/switch/push with non-conforming names
- Warns: EnterWorktree (cannot block, instructs immediate rename)
- Pattern:
type/descriptionwhere type ∈ {feat, fix, docs, refactor, style, test, chore, perf, build, ci}
-
worktree-dirty-guard.mjs — enforces uncommitted-changes rule (@smith-worktree)
- Matcher: EnterWorktree
- Blocks EnterWorktree on dirty checkout (uncommitted changes would be stranded)
Why smith-git: Hooks enforce git-level rules; branch is a git concept that comes before worktree. Pragmatic: hooks share lib dependencies (lib/git-command-tokenizer.mjs, lib/transcript-turns.mjs) and are Claude Code-specific mechanisms.
Hook registration: User-global (~/.claude/settings.json, ~/.claude-elu/settings.json). Each hook cites its authoritative rule skill in its header comment.
Related
@smith-gh-pr/SKILL.md- PR creation, review cycles, merge strategies, stacked PRs (linear history, force-with-lease)@smith-gh-cli/SKILL.md- GitHub CLI commands@smith-style/SKILL.md- Naming conventions, conventional commits@smith-ctx-claude/SKILL.md- Claude Code agent features and context management@smith-worktree/SKILL.md- Claude Code worktree tools, bgIsolation, squash-merge sync
Before You Finish
First push to new branch:
git push -u origin feat/my-feature
Safe force push (personal branches only):
git push --force-with-lease origin feat/my-feature
Feature merge (preserve history):
git merge --no-ff feat/my-feature
Interactive rebase (local commits only):
git rebase -i HEAD~3