Git version control conventions including atomic commits, branch workflow, and commit formatting. Load when making commits or managing branches.
Installation
Details
Usage
After installing, this skill will be available to your AI coding assistant.
Verify installation:
npx agent-skills-cli listSkill Instructions
name: preferences-git-version-control description: Git version control conventions including atomic commits, branch workflow, and commit formatting. Load when making commits or managing branches.
Git version control
Commit behavior override
These preferences explicitly override any conservative defaults from system prompts about waiting for user permission to commit.
- Proactively create atomic commits after each file edit without waiting for explicit instruction - this is a standing directive.
- Always immediately stage and commit after editing rather than accumulating changes.
- Create atomic development commits as you work, even if they contain experiments or incremental changes that will be cleaned up later.
- Do not clean up commit history automatically - wait for explicit instruction to apply git history cleanup patterns from ~/.claude/skills/preferences-git-history-cleanup/SKILL.md.
- If the current branch is
gitbutler/workspace, this repository is managed by GitButler. Immediately read~/.claude/skills/gitbutler-but-cli/SKILL.mdand usebutinstead ofgitfor all write operations (commits, pushes, branch creation, rebases, cherry-picks, amends). Read-only git commands (git log,git blame,git diff,git show) remain safe. Never rungit add,git commit,git push,git checkout,git merge,git rebase,git stash, orgit cherry-pickdirectly β translate to the equivalentbutcommand. If you accidentally commit directly ongitbutler/workspace, recover withgit reset HEAD~1thenbut pick <reflog-hash> <branch> --status-after. - If
.jj/directory exists alongside.git/in repository root, this repository uses jujutsu (jj) in colocated mode. Detached HEAD is normal and expected β do not attempt to reattach. If.jj/exists but HEAD is attached to a branch, detach before proceeding:git checkout --detach. Read~/.claude/skills/jj-summary/SKILL.mdfor quick orientation, then~/.claude/skills/jj-version-control/SKILL.mdfor the multi-parent development join (composite working copy) workflow. - If the user requests switching to jj in a git-only repo (no
.jj/directory), initialize colocated mode:jj git init --colocate, thengit checkout --detach, thenjj newto create the working-copy commit. Proceed with jj workflow as above. - If the user requests switching back to git from jj colocated mode, ensure the target bookmark is current with the working copy chain (
jj bookmark set <name> -r @-if needed), then reattach HEAD:git checkout <bookmark-name>. Resume git-native commands. The.jj/directory can remain β colocated mode is safe to leave dormant. - If
.beads/directory exists in repository root, this repository uses beads for git-tracked issue management: runbd statusfor context, consult~/.claude/skills/issues-beads-prime/SKILL.mdfor quick reference or~/.claude/skills/issues-beads/SKILL.mdfor comprehensive workflows.
Proactive beads maintenance
When .beads/ exists, maintain the issue graph alongside git commits:
- Orient with
bd statusat session start - Mark issues
in_progresswhen starting work; update descriptions when assumptions prove incorrect - Create issues discovered during work and wire with
bd dep add <new> <current> --type discovered-from - Close with implementation context:
bd close <id> --reason "Implemented in $(git rev-parse --short HEAD)" - Check what's unblocked after completion; consider updating newly-ready issues with helpful context
- After completing a batch of mutations, push to the dolt remote for backup:
bd dolt push
For beads usage conventions (epic structure, status management, closure policy), see the conventions section of issues-beads-prime.
Consult ~/.claude/skills/issues-beads-prime/SKILL.md for command quick reference.
VCS terminology glossary
This glossary defines abstract terms for version control operations that remain stable across tools. Each abstract term maps to concrete equivalents in the four VCS tools used across this repository's skill set.
| Abstract term | Git | GitButler | Jujutsu (jj) | Gerrit |
|---|---|---|---|---|
| Branch stack | Feature branch (single) or graphite stack | Stack (chain of stacked branches sharing one linear history) | Bookmark chain | Topic (group of related changes) |
| Branch boundary | N/A (one branch = one unit) | Branch name within a stack, inserted via but branch new -a | Change boundary (each change is a boundary) | Change boundary |
| Change set | Commits on a branch between two merge points | Commits within one branch segment of a stack | Single change (jj's atomic unit) | Patchset (version of a change) |
| Working branch | Checked-out branch (git checkout) | Applied branch (multiple coexist in workspace) | Current change (@); multi-parent @ for development join | Checked-out change |
| Integrate to main | Fast-forward merge (git merge --ff-only) | Fast-forward merge of stack tip | jj git push + bookmark advance | Submit (merge to target) |
| Isolate work | git worktree add or git checkout -b | but branch new (independent stack) or but branch new -a (stacked segment) | jj new (new change) | New change |
| Reorder history | git rebase -i | but move (within stack), but squash, but reword | jj rebase, jj squash | Amend patchset |
| Shelf/stash | git stash | but unapply (removes branch from workspace, preserves commits) | jj new (just start new work, old change preserved) | N/A |
All skills in this repository use the abstract terms from the left column when describing VCS operations.
The git-preferences skill translates these to concrete commands based on the active VCS mode: git-native (default), GitButler (when gitbutler/workspace is checked out), or jj (when .jj/ exists).
Skills that need VCS operations should delegate to git-preferences rather than embedding tool-specific commands.
This decoupling ensures skills remain correct across all three modes without conditional logic of their own.
Naming modes for branch stacks
When a beads epic is active (.beads/ exists and an epic is in progress), branch stacks correspond to epics and branch boundaries correspond to issues:
- Stack name:
{epic-ID}-descriptor(e.g.,nix-f85-gitbutler-adoption) - Branch name at each boundary:
{issue-ID}-descriptor(e.g.,nix-f85-1-terminology-glossary)
When working ad hoc (no beads, or outside an epic), stacks and boundaries are named descriptively:
- Stack name: descriptive (e.g.,
gitbutler-skill) - Branch name at each boundary: descriptive (e.g.,
fix-gitbutler-version)
Both modes use identical mechanical operations.
The difference is purely in naming conventions and whether bd lifecycle commands accompany the VCS operations.
Escape hatches
Do not commit if:
- Current directory is not a git repository
- User explicitly requests discussion or experimentation without committing
Branch workflow
File edits on main/master are blocked by the enforce-branch-before-edit hook.
Before attempting to edit any files, create a working branch to which you will commit your changes.
If you haven't already, invoke /issues-beads-prime for beads command reference before proceeding with any editing.
In jj mode, this hook is unnecessary.
Anonymous chains are first-class and never garbage-collected.
Create bookmarks when initiating a second chain or when working on beads epics β see the bookmark creation threshold in ~/.claude/skills/jj-version-control/SKILL.md.
Whenever you are working on a beads issue or epic, check the current branch name first. If it does not correspond to the issue you're working on, pause to ask the user whether to create or switch to a matching branch before proceeding.
Branch naming follows the pattern ID-descriptor in lowercase kebab-case, where ID references the issue tracker:
- Beads repos (
.beads/exists): Use the beads issue ID with dots replaced by dashes. Examples:nix-pxj-ntfy-server(epic),nix-pxj-4-deploy-validate(task under epic),nix-i37-fix-flake-lock(standalone issue). - GitHub-only repos: Use the issue or PR number.
Examples:
42-refactor-auth,1337-add-feature.
Never use forward slashes in branch names as they break compatibility with URLs, docker image tags, and other tooling that embeds branch names.
Create a new working branch when your next commits won't match the current branch's ID-descriptor:
- Example: current branch is
nix-pxj-4-deploy-validatebut you discover issuenix-di8needs fixing first β createnix-di8-fix-dependency - When the unit of work is complete and tests pass, offer to integrate to main
To isolate work in a new branch:
- Git-native mode:
git checkout -b ID-descriptorto branch off current HEAD, orgit worktree addfor bead-tracked isolation (see working branch isolation below). - GitButler mode:
but branch new ID-descriptorto create a new independent stack, orbut branch new ID-descriptor -a <commit>to split an existing stack at a branch boundary. - jj mode:
jj new <base>to create a new change from a single base, orjj new bookmark-a bookmark-bto create a development join with multiple bookmarks merged in one working tree.
Default bias: if in doubt whether work is related, create a new branch β branches are cheap, tangled history is expensive.
Working branch isolation
Implementation work uses isolated working contexts to prevent tangled history. The mechanism differs by VCS mode.
Git-native mode
Bead implementation work uses worktrees rooted in .worktrees/ at the repository root.
This directory must be listed in .gitignore.
The worktree model has two tiers: epic worktrees for coordination and issue worktrees for implementation.
Epic branches
Each active epic gets its own branch.
The focus epic β the primary epic being actively coordinated β is checked out in the repo root.
This keeps orientation commands (bd status, bd epic status) and code-level context aligned with the active work.
Create a focus epic branch when starting work on an epic:
git checkout -b {epic-ID}-descriptor main
Secondary epics being worked in parallel get worktrees in .worktrees/:
git worktree add .worktrees/{epic-ID}-descriptor -b {epic-ID}-descriptor main
When one epic depends on another, stack it on the parent epic's branch rather than main:
# nix-pxj depends on nix-1kj, so stack it
git checkout -b nix-pxj-ntfy-server nix-1kj-stigmergic-tooling
# or as a secondary worktree:
git worktree add .worktrees/nix-pxj-ntfy-server -b nix-pxj-ntfy-server nix-1kj-stigmergic-tooling
An epic branch accumulates all commits from its child issue worktrees via fast-forward merges. When the epic is complete, it contains the full linearized commit history for review, validation, and merge to main.
Switching focus
To promote a secondary epic to focus (and optionally demote the current focus):
# Remove the secondary epic's worktree
git worktree remove .worktrees/{new-focus-epic}-descriptor
# Optionally preserve the old focus as a secondary worktree
git worktree add .worktrees/{old-focus-epic}-descriptor {old-focus-epic}-descriptor
# Check out the new focus epic in repo root
git checkout {new-focus-epic}-descriptor
When no epic is active, the repo root returns to the default branch.
Issue worktrees
Each issue within an epic gets its own worktree, branching from the parent epic's branch. The working agent creates the issue worktree as its first action before any implementation begins.
git worktree add .worktrees/{issue-ID}-descriptor -b {issue-ID}-descriptor {epic-ID}-descriptor
When issue work is complete, rebase onto the epic branch and fast-forward merge back into it:
cd .worktrees/{issue-ID}-descriptor
git rebase {epic-ID}-descriptor
cd ../..
# merge into the epic branch (from repo root if it's the focus epic):
git merge --ff-only {issue-ID}-descriptor
# or from the epic worktree if it's a secondary epic:
git -C .worktrees/{epic-ID}-descriptor merge --ff-only {issue-ID}-descriptor
Then clean up the issue worktree:
git worktree remove .worktrees/{issue-ID}-descriptor
git branch -d {issue-ID}-descriptor
General rules
Always specify an explicit start-point when creating branches or worktrees.
Epic branches start from main (or from another epic's branch when stacking).
Issue worktrees branch from their parent epic's branch.
Without a start-point, git branches from whatever happens to be checked out, which may not be the intended base.
Use worktrees for bead-tracked work; use plain branches (git checkout -b) for non-bead or quick-fix work.
Direnv initialization in worktrees
Worktrees do not inherit the repository root's direnv environment.
If the repository uses direnv with a nix devshell (indicated by an .envrc file), the devshell creates ephemeral files like .pre-commit-config.yaml that are not checked into git.
After creating a worktree, initialize its environment before any git operations that trigger hooks:
cd .worktrees/{ID}-descriptor
direnv allow
For git commits and other hook-triggering operations, use direnv exec . to ensure the nix devshell is active:
direnv exec . git commit -m "message"
This is not needed for read-only git operations (git log, git status, git diff) which do not trigger hooks.
When the epic is complete and merged to main, clean up:
# If it was a secondary epic worktree:
git worktree remove .worktrees/{epic-ID}-descriptor
# Delete the branch:
git branch -d {epic-ID}-descriptor
GitButler mode
All branches coexist in a single workspace β no worktrees are needed. Isolation comes from branch boundaries within and across stacks rather than filesystem separation.
Branch stacks as epics
Each active epic corresponds to a branch stack. Create a new stack for a new epic:
but branch new {epic-ID}-descriptor
When one epic depends on another, stack it on the parent epic's branch:
but branch move {epic-ID}-descriptor {parent-epic-ID}-descriptor
Issue branches within a stack
Each issue within an epic becomes a branch boundary within the epic's stack. Insert a branch boundary at the commit where the issue's work begins:
but branch new {issue-ID}-descriptor -a <anchor-commit>
The anchor commit and everything below it become the new branch.
Everything above the anchor stays with the original branch.
See the "Split a branch at a commit boundary" recipe in ~/.claude/skills/gitbutler-but-cli/SKILL.md for details.
When issue work is complete, commits are already part of the stack's linear history. No rebase or merge step is needed β the stack tip integrates all segments at once when merged to main.
Switching focus
To shelve work on a stack and focus on another, use but unapply and but apply:
# Shelve the current stack
but unapply {branch-name}
# Apply a different stack
but apply {other-branch-name}
Unapplied stacks retain their commits and can be reapplied at any time.
Cross-stack commit reorganization
Move a commit from one branch to another within or across stacks:
but move <source-commit-id> <target-commit-id> --status-after
Commit IDs come from but status -fv or but show <branch-id>.
No direnv initialization needed
GitButler operates in a single working tree, so the repository root's direnv environment applies to all branches.
jj mode
jj provides a development join (multi-parent working copy) that achieves the same simultaneous multi-branch editing as GitButler's applied-branches model. All bookmarks coexist in a single working tree β no worktrees are needed.
Creating a multi-parent working copy
Create a development join with multiple parent bookmarks:
jj new bookmark-a bookmark-b bookmark-c
The resulting @ is a development join whose working tree merges all parent bookmarks.
Edits made in @ can be routed (route elements to their chain) to any chain.
Change routing
Route changes from the development join @ to the appropriate chain:
# Manual: squash specific changes into a named chain element
jj squash --into <parent-bookmark> -u -- <path>
# Automatic: distribute changes based on blame ancestry
jj absorb
The -u (--use-destination-message) flag prevents the description merge editor from opening and preserves the target chain element's existing description.
jj absorb analyzes which ancestor last touched each modified line and routes changes automatically.
Use jj squash --into when changes belong to a specific chain element that blame cannot determine.
Adding and removing parents
Modify the set of chains in the development join:
# Add a chain
jj rebase -r @ -d 'all:(@- | new-bookmark)'
# Remove a chain
jj rebase -r @ -d 'all:(@- ~ removed-bookmark)'
The all: prefix ensures the revset resolves to multiple parents rather than a single ancestor.
Auto-rebase behavior
When a chain advances (via commits on that bookmark from another workspace or collaborator), jj automatically rebases @ onto the updated parents.
This keeps the development join current without manual intervention.
Epic and issue mapping
Bookmarks correspond to epics or independent work streams. Changes within each bookmark's chain correspond to issues. This mapping parallels the git-native worktree model and the GitButler stack model, but without filesystem separation.
Create a bookmark per active epic following the standard naming convention:
jj bookmark create {epic-ID}-descriptor
Build changes as a chain descending from each bookmark. Each change in the chain corresponds to an issue within the epic:
# Start work on an issue within the epic
jj new {epic-ID}-descriptor
jj describe -m "feat: implement issue description"
# edit files...
jj new # freeze and start next issue
When working across multiple epics simultaneously, create a development join over the active epic bookmarks:
jj new {epic-a}-descriptor {epic-b}-descriptor
Route changes from the development join @ to the appropriate chain:
# Automatic: distribute changes by blame ancestry
jj absorb
# Manual: route specific changes to a named epic chain
jj squash --into {epic-b}-descriptor -u -- <path>
Subagent dispatch in jj mode
In jj mode, subagents do not create bookmarks or worktrees.
All agents β including parallel agents β edit files directly in the shared @ working copy.
The orchestrator routes changes to the correct chain via jj absorb or jj squash --into <target> -u -- <path> after each subagent completes.
When working in the development join, use a join + wip structure (two-commit pattern).
The development join integrates all parent bookmarks and has a description to prevent auto-abandonment.
The wip commit (@) sits on top for active edits.
jj absorb and jj squash --into <target> -u -- <path> route changes from wip to chains without disrupting the development join.
Coordination protocol: atomic one-file changes, periodic jj log review, prompt routing to keep @ clean.
Subagent dispatch prompts specify which files to edit and the target chain context but do not include jj routing commands.
See the parallel agent coordination protocol in ~/.claude/skills/jj-version-control/SKILL.md for the full model.
Completing issues and epics
When an issue is complete, close the bead:
bd close {issue-ID} --reason "Implemented in $(jj log -r '{epic-ID}-descriptor' --no-graph -T 'commit_id.short(8)')"
To merge a completed epic to main, advance the main bookmark:
jj new
jj bookmark set main -r @-
jj git push --bookmark main
jj bookmark delete {epic-ID}-descriptor
No direnv initialization needed
jj development joins operate in a single working tree, so the repository root's direnv environment applies to all chains.
GitButler equivalence mapping
| GitButler | jj development join |
|---|---|
| Applied branches | Chains in development join @ |
gitbutler/workspace commit | Development join @ commit |
but commit --changes | jj squash --into <target> -u -- <path> or jj absorb |
but unapply | Remove chain from join via jj rebase -r @ -d 'all:(@- ~ bookmark)' |
but apply | Add chain to join via `jj rebase -r @ -d 'all:(@- |
| Branch stacks | Bookmark chains (linear descendant sequences) |
but move (cross-stack) | jj squash --from <src> --into <dst> |
Diamond workflow
When .beads/ exists and an epic is active, the epic's issue dependency graph determines the jj bookmark chain topology.
Independent issues form an antichain of parallel bookmark chains.
Dependent issues produce chain stacking (one bookmark branching from another's tip), reflecting the covering relation in the issue partial order.
The diamond pattern proceeds through four phases.
The diverge phase decomposes the epic into bookmark chains based on bd epic status.
The develop phase creates an N-way development join (composite working copy) over all active chains using the join + wip structure, enabling concurrent development with continuous integration feedback.
The converge phase validates the integrated development join via testing and QA.
The serialize phase dissolves the development join and rebases each chain sequentially onto main as a linear extension of the dependency partial order, producing purely linear history with no merge commits.
The pattern generalizes conceptually beyond jj (GitButler's applied-branches model and git-native worktrees achieve analogous isolation), but the mechanical implementation leverages jj's multi-parent working copy.
For the full treatment including theoretical foundations, beads-to-jj mapping, and mechanical recipe, see ~/.claude/skills/jj-version-control/diamond-workflow.md.
Fast-forward-only merge policy
All merges to main must be fast-forward.
This preserves linear history, making bisect, revert, and log traversal straightforward.
The git config merge.ff only guardrail rejects non-fast-forward merges automatically in both modes, serving as a safety net.
In git-native mode, rebase the branch onto main before merging:
git checkout {branch}
git rebase main
# resolve any conflicts, then:
git checkout main
git merge --ff-only {branch}
Never use git merge without --ff-only on main.
If a branch has diverged and rebase produces conflicts, resolve them during the rebase rather than creating a merge commit.
In GitButler mode, stacked branches are already linear by construction.
Fast-forward merge of the stack tip integrates all stacked segments at once.
Exit GitButler before merging to main: but teardown, then git merge --ff-only, then but setup.
Do not use but merge for this β it always creates merge commits and has no fast-forward mode.
See the "Stacked PRs with single fast-forward merge" and "Merging multiple independent stacks" recipes in ~/.claude/skills/gitbutler-but-cli/SKILL.md for the full workflow.
In jj mode, integration uses sequential rebase linearization: rebase each chain onto main in dependency order, producing a purely linear history with no merge commits.
Fast-forward main to the linearized tip via jj bookmark set main -r <chain-tip>.
See the integration strategies section in ~/.claude/skills/jj-version-control/SKILL.md for the full completion workflow.
Stack management
Branch stacks mirror beads issue dependencies: when issues form a dependency chain (e.g., nix-pxj.2 blocks nix-pxj.3), the corresponding branches should form a stack with matching parent-child relationships.
If you identify a reason to modify beads dependencies while working, evaluate and present a plan to reorder the branches associated with previously completed work in the stack, handling any conflicts that arise.
In git-native mode, use the graphite CLI (invoke as graphite, not gt as shown in official documentation) to manage stacks:
graphite logβ view branch stack relationshipsgraphite trackβ register an existing branch with graphite, selecting its parentgraphite create -m "message"β create a new branch stacked on current, with initial commit
In GitButler mode, native stack operations replace graphite entirely.
but branch new -a, but branch move, and but move provide all stack management without an external tool.
See ~/.claude/skills/gitbutler-but-cli/SKILL.md for the full command reference.
Merge strategy selection
Two strategies exist for integrating branches into main. The choice depends on whether the project benefits from CI validation or historical change visibility for a given unit of work.
Fast-forward merge to main is the default.
Branch from main, work in atomic commits, rebase onto main, then git merge --ff-only and clean up the branch.
This suits new projects, straightforward changes, and early-stage repositories where the overhead of a pull request adds no value.
The fast-forward-only merge policy described above applies in all cases regardless of strategy.
The GitHub PR workflow is preferred when change visibility matters. Mature repositories, public-facing changes, and collaborative projects benefit from PRs because the full changeset is referenceable as a single unit with discussion history. PRs are also the appropriate path when CI workflow validation via PR checks provides meaningful confidence in the change, beyond what local testing alone offers. Follow the PR creation protocol documented below when using this strategy.
When uncertain which strategy to use, ask the user. The user can always override in either direction on a per-change basis.
File state verification
Before editing any file, check for uncommitted changes:
- Related to current task: commit them first with appropriate message
- Unrelated or unclear: pause and propose commit message asking user for confirmation
In git-native mode, run git status --short [file] and git diff [file].
In GitButler mode, but status -fv provides richer state including branch assignment and CLI IDs for each changed file.
In jj mode, jj status and jj diff show working copy state. There is no staging area β all tracked file changes are the commit.
Atomic commit workflow
Atomic commits in this workflow mean one commit per file with exactly one logical change. Each commit is the smallest meaningful unit that can be independently reverted, cherry-picked, or bisected. This is not atomic in the database sense of bundling multiple operations together, but atomic as the finest practical granularity for version control.
Make one logical edit per file (even when using MultiEdit to edit multiple files in parallel), then commit each file separately. This eliminates mixed hunks by construction.
In git-native mode: edit file, git add [file], verify with git diff --cached [file], then git commit -m "msg".
In GitButler mode: edit file, run but status -fv to get the file's CLI ID, then but commit <branch> -m "msg" --changes <id> --status-after.
The --changes flag provides explicit file selection equivalent to staging one file at a time.
In jj single-chain mode: edit one file, then immediately jj describe -m "msg" followed by jj new to freeze the change and start a new empty @.
This is the jj equivalent of git add [file] && git commit β the describe + new cycle is the atomic commit boundary.
Without jj new, the next edit accumulates into the same change, breaking atomicity.
If multiple files were edited before freezing, use jj split <path> -m "msg" to separate them into atomic changes after the fact.
In jj development join mode (multi-parent composite): edit one file, then route it to the correct chain. Two routing patterns exist:
- Amend existing chain commit:
jj squash --into <target-parent> -u -- <path>routes the file into the existing commit. Use when the chain commit already exists and the change belongs in it. - Extend chain with new commit: use the route-and-extend pattern from
~/.claude/skills/jj-version-control/SKILL.md. Use when the change is a logically separate commit that should extend the chain. - Auto-route by blame:
jj absorbdistributes changes to appropriate ancestors automatically.
After any routing operation, if @ was described, clear it: jj describe -m "".
jj squash --into and jj absorb move file content but do NOT clear @'s description.
Do not use jj new (without -A) in development join mode β it creates a new change descending from the development join @ rather than routing to a chain.
jj new -A <bookmark> --no-edit is safe because it inserts after the specified bookmark without moving @.
See the edit-route cycle in ~/.claude/skills/jj-version-control/SKILL.md for the full workflow.
Handling pre-existing mixed changes
If you encounter a file with multiple distinct logical changes already present:
- Preferred: inform the user that the file contains mixed changes and pause for them to stage interactively with
git add -p [file](this is a human-delegated action; the AI does not execute interactive staging) - Alternative: construct patch files manually using
git diff [file]andgit apply --cached [patch], but only when hunks have clear boundaries, are semantically distinct, and you can confidently construct valid unified diff format
Commit formatting
- Succinct conventional commit messages for semantic versioning
- Test locally before committing when reasonable
- Never use emojis or multiple authors in commit messages
- Never @-mention usernames or reference issues/PRs (#NNN, URLs) in commit messages - causes unwanted notifications and immutable backlinks
- Fixup commits: prefix with "fixup! " followed by exact subject from commit being revised (use only once, not repeated)
- Stage one file per commit after verifying exactly one logical change.
In git-native mode:
git add [file]. In GitButler mode: use--changes <id>onbut committo select specific files by CLI ID. - In git-native mode, never use
git add .,git add -A, or interactive staging (git add -p,git add -i,git add -e) β interactive commands hang in AI tool execution (the human may rungit add -pwhen delegated; see "Handling pre-existing mixed changes"). In GitButler mode, this concern does not apply βbut commitrequires explicit--changesselection by design. In jj mode, there is no staging area β all working copy changes are the commit. Usejj split <paths> -m "msg"to separate concerns within a single change when multiple logical edits accumulate in@.
History investigation with pickaxe
When searching for when/why code changed, use git pickaxe options strategically to avoid context pollution:
Default search strategy (focused):
- Use
-G"pattern"to find commits where lines matching pattern were added/removed - Use
-S"string"to find commits where the occurrence count of string changed (not in-file moves) - Examine specific files:
git show <hash> -- <file>orgit diff <base>..<hash> -- <file>
Avoid --pickaxe-all by default:
- Without
--pickaxe-all: shows only files matching the search (optimal for AI context) - With
--pickaxe-all: shows entire changeset if any file matches (causes information overload) - Only use
--pickaxe-allwhen broader context is explicitly needed to understand why a change was made
Key differences:
-S"numpy"finds commits where "numpy" was added/removed (count changed)-G"numpy"finds commits where lines containing "numpy" were modified-Smisses refactors that move text without changing occurrence count-Gis more expensive but catches structural changes
Practical examples:
git log -G"dependencies" --onelinethengit show <hash> -- <file>(targeted)git log -S"function_name" --pickaxe-regex --oneline(exact occurrences)- Avoid
git log -S"pattern" --pickaxe-all -punless user needs full changeset context
Session commit summary
After creating commits, provide a git command listing session commits: git log --oneline <start-hash>..<end-hash> using the commit hash from gitStatus context as start and git rev-parse HEAD as end. Use explicit hashes, not symbolic references, to ensure command remains valid after subsequent commits.
In jj mode: jj log --no-graph -r 'main@origin..main' -T 'separate(" ", change_id.short(8), description.first_line()) ++ "\n"'
GitHub PR and Issue creation safety
GitHub's immutability policies require careful workflow to avoid permanent unwanted records:
- PR and Issue titles and descriptions cannot be edited after creation
- GitHub will not delete PRs or Issues without proof of sensitive data
Always use placeholder content in immutable fields, then update mutable fields after human review.
PR creation protocol
Create PRs in draft mode with generic placeholder content:
gh pr create \
-d \
-a "@me" \
-B main \
-t "[conventional commits-formatted terse PR title]" \
-b ""
After creation, provide follow-up commands for human review:
- Update PR title using
gh pr edit <number> --title "conventional: commits format" - Add actual description as second comment using
gh pr comment <number> --body "markdown description" - Never edit the immutable PR description field created at PR creation time
- Wait for user approval before executing
Issue creation protocol
Apply identical safety patterns to gh issue create:
- Create with placeholder title and "empty" body
- Provide follow-up commands for title update and comment-based description
- Never edit the immutable Issue description field
Cross-reference safety
Include www in GitHub URLs to prevent automatic backlinking:
- Use:
https://www.github.com/org/repo/issues/123 - Avoid:
https://github.com/org/repo/issues/123(creates immediate backlink) - User removes
wwwafter confirming reference is intentional
Uncertainty protocol
When uncertain about any aspect of PR or Issue creation:
- Pause execution
- Present proposed creation command with placeholders
- Show intended title and description separately
- Provide follow-up commands for mutable field updates
- Await user confirmation
This ensures immutable GitHub records stay generic while preserving user control over deletable content.
More by cameronraysmith
View allCollaborative modeling techniques including EventStorming and Domain Storytelling. Load when facilitating discovery workshops or modeling domain processes.
Railway-oriented programming with Result types and workflow composition for error handling. Load when designing error handling pipelines or composing fallible operations.
Minimal quick reference for beads commands when context is constrained.
name: github-browse
