Skip to main content

commit

Splits working-tree changes into logical, self-consistent commits (ordering so nothing dangles, stepping files that straddle commits through intermediate states), writes conventional-commit messages (feat/fix/docs/refactor/chore) with motivation in the body, stages explicit paths only, uses git mv for renames, never pushes/amends/skips hooks unless explicitly asked, and ends by reporting the resulting hashes against a clean tree. Includes pre-commit checks for Fabric Git-synced repos (core.autocrlf, .gitattributes, whitespace-only portal diffs). In a working tree another session is editing at the same time, gates the commit on the branch and on the index exactly as read, so nothing of theirs is swept in and nothing lands on a branch a peer switched to.

Informations de source

Dépôt
wardawgmalvicious/agent-config
Dernière activité de la source
17 octobre 2026 à 05:26
Langue détectée de SKILL.md
anglais
Étoiles
1
Forks
0

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Explorateur de fichiers
4 fichiers

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
commit
effort
xhigh
disable-model-invocation
false
description
Splits working-tree changes into logical, self-consistent commits (ordering so nothing dangles, stepping files that straddle commits through intermediate states), writes conventional-commit messages (feat/fix/docs/refactor/chore) with motivation in the body, stages explicit paths only, uses git mv for renames, never pushes/amends/skips hooks unless explicitly asked, and ends by reporting the resulting hashes against a clean tree. Includes pre-commit checks for Fabric Git-synced repos (core.autocrlf, .gitattributes, whitespace-only portal diffs). In a working tree another session is editing at the same time, gates the commit on the branch and on the index exactly as read, so nothing of theirs is swept in and nothing lands on a branch a peer switched to.
when_to_use
Use when asked to commit changes — /commit, 'commit this', 'make the commits', 'commit these split logically' — and when the commit has to be made in a tree another session is working in: 'another session is live in this tree', 'commit mine without touching theirs'. Also use it unasked, on the user's standing word, once a unit of work is finished while another live session shares the working tree, where uncommitted work can vanish.
# Commit workflow Turn the current working-tree changes into one or more well-formed commits. Committing only — pushing, amending, rebasing, and tagging happen only when explicitly requested, never as follow-through. ## Survey first 1. `git status --short` — full picture of modified, renamed, untracked. Note anything **already staged that you did not stage**. 2. `git log --oneline -10` — calibrate message style against this repo's actual history, not assumptions. 3. Read the diffs (`git diff`, `git diff --stat`, plus untracked files) well enough to explain *why* each change exists, not just what it touches. Never commit content you haven't looked at. 4. **On `main`? Branch when the work is more than one commit, or an intermediate state would break while deployed** — the trigger and the name are `~/.claude/CLAUDE.md` § "Branch naming"'s — and from the first commit when it is bound for `land`, which refuses to start from `main`. Work in a repo that lands by pull request is bound for `land`: a pull-request rule on `main` (`land` step 7 has the two reads), or `(#<n>)` and `Merge pull request` subjects in the log above; a fast-forward landing leaves none. A repo's own committed convention wins, in its `CONTRIBUTING.md` or agent instructions: one that commits straight to `main` answers *no*, and then you commit where you stand. Say which way you went. In a shared tree `git switch -c` moves HEAD for everyone — see [below](#when-another-session-shares-this-tree). **An empty `git status --short` is the whole answer.** Report that there is nothing to commit and stop; don't work through the diffs to confirm it. `git diff --stat` prints nothing on a clean tree, and reading that silence as a failed command rather than as the answer is a real failure mode — observed 2026-09-09, three tool calls spent re-asking the same question. ## Splitting into commits - **One logical unit per commit.** A rename, a new feature, and a docs catch-up are three commits even when they touch the same file. Test: could each commit's subject line be written without "and"? - **Review grouping is not a commit boundary.** Parts approved together in one review are still separate commits when each stands on its own in history — independently revertible, citable, worth landing alone. Bundle only when the parts are mutually dependent for meaning: a claim and the caveat qualifying it, a rename and its call sites. Tiebreak for a docs batch — which shape would you rather read in `git log` a year from now? - **Every commit must be self-consistent.** No commit may reference a name, file, or skill that doesn't exist yet at that point in history, and none may leave the repo in a broken intermediate state. Order accordingly (e.g. a rename lands before anything citing the new name). - **When one file straddles commits**, reach for interactive `git add -p` where your harness offers it. Some do not: an agent shell with no interactive stdin cannot drive it, and the prompt either hangs or reads EOF. Where it is unavailable, **stage through the index**: [scripts/stage-part.py](scripts/stage-part.py) builds the next commit's version of the file from the changed blocks a regex picks and writes it straight into the index, leaving the working tree at its final state. Read the `TAKE` and `skip` line it prints for each block, then `git diff --cached`, before each commit; an empty `git status --short` after the last commit proves the commits add up to the file on disk. Usage, limits, and the blob built by hand for changes no unchanged line separates: [references/index-staging.md](references/index-staging.md). Stepping the file through intermediate states on disk is the fallback — edit it down to the first commit's portion, commit, restore the next portion, commit again — and rewrites the working tree, so verify the final state matches the intended end state exactly. **Stepping assumes you own the whole file.** If another session has uncommitted work in it, stepping rewrites their in-flight text — commit only what is yours and leave the rest with a note. - **Stage explicit paths only.** No `git add -A` / `git add .` — they silently sweep in untracked or unrelated files. - **Verify the index before each commit.** `git diff --cached -- <paths>` must show your change and nothing else. The diff you read in the survey is not what `git add` staged: the file can change in between, and `git add <path>` takes every hunk in the file, not the hunk you meant. `--stat` is not enough — a foreign hunk in a file you also edited has a stat line that looks exactly right. This is the last point at which a swept-in change is free to fix — and in a shared tree it has to *gate* the commit rather than precede it; see [below](#when-another-session-shares-this-tree). - **Renames go through `git mv`** (or are staged so git detects the rename) so history follows the file. ## Messages - Subject: `<type>(<scope>): <imperative summary>`, with the scope where the log uses one. `<type>` is one of the conventional-commit types `~/.claude/CLAUDE.md` § "Branch naming" lists, `perf`, `build` and `ci` among them. Lowercase after the colon, no trailing period. - Body: explain **motivation and non-obvious decisions** — why the change exists, what prompted it, provenance ("derived from X, now deleted"), and any ordering or scoping rationale. Never restate the diff. Wrap near 72 columns. Trivial single-file changes may skip the body. - Multi-line messages: from PowerShell, a single-quoted here-string (`@'` ... `'@`, closing delimiter at column 0) handed to `-m`, never to `-F -`, which reads stdin and leaves git the here-string as a pathspec: `error: pathspec '<subject>…' did not match any file(s) known to git`, exit 1, nothing committed (2026-10-09). From Bash, prefer `git commit -F -` fed by a quoted heredoc over `-m`, which sidesteps the quoting entirely. **Crossing the two exits 0** — a PowerShell here-string handed to `-m` in the Bash tool commits `@` as the subject with the delimiters in the body, and neither the hooks nor the exit code says so. Confirm with `git log -1 --format=%B --stat` before reporting the commit — one call gives both the message actually recorded and the files actually in it. ## Safety rails - Never push, amend, force, rebase, or tag unless the user asked for that in this conversation. Commit, report, stop. - Never `--no-verify` / skip hooks; if a hook fails, fix the cause. - If a change looks accidental or unrelated to the stated work, leave it uncommitted and flag it rather than sweeping it in. - **Scan for identity strings — in the diff *and* in the message you are about to write.** An organization's account names (`AzureAD\…`, Entra accounts), tenant names and internal hostnames get genericized before the commit, whatever the repo's visibility, in every repo but that organization's own: the client roots the denylist below exempts (2026-10-16). Hardcoded `C:\Users\<name>` profile paths get genericized in every repo. gitleaks does not cover this: it matches secrets, not identities, and the pre-commit hook only sees *staged content*, so the message is unguarded entirely. The trap is that a commit documenting machine- or tenant-specific behaviour is exactly where real account names read as the subject matter — and a message, unlike a file, cannot be fixed forward. **Assume nothing catches this for you.** A hook can: an `identity-guard` reading a local denylist blocks a commit whose staged diff adds a listed term, hands back a message that carries one, and blocks the push. But it is a *local* hook reading a *local* list — the list is itself the leak, so it lives in no repo and travels with no clone. Unless you installed both on this machine, nothing above is checked for you and the scan is entirely yours. Even where it does run it knows only what is on the list, so a name it has never seen is yours to catch, and then to add. ## When another session shares this tree Two sessions in one working tree share every file, **the index and HEAD**, so neither staging nor a branch isolates you — only a commit does, and only if it lands on the branch you meant. Suspect it when the survey shows a path you never touched, when something is already staged that you did not stage, when `git diff --cached` holds a hunk you cannot account for from this conversation, when HEAD is not on the branch you left it on, or when the user says so. **Rule out the two innocent explanations first**: your own stepping edits, and a hook that rewrites files, which leaves its rewrite *unstaged*. Neither is contention. A linked worktree is a tree of its own: git keeps its index and HEAD under `.git/worktrees/<name>/`, so a session alone in one has nothing to suspect and commits with the plain commands. The `EnterWorktree` guard refuses the chained form below there as too complex to verify (2026-10-06, 2.1.289), and a worktree needs none of it. **Commit each finished unit unasked while a peer shares the tree**: the user's standing word since 2026-10-09. Held for their review, it can vanish under a peer's stash, checkout or pre-commit run before they look, and nothing reports it; a commit they did not want costs a revert. A peer is any live `ListAgents` row that `bash ~/.claude/skills/land/scripts/placed-elsewhere.sh <name>` does not place elsewhere, idle or never prompted alike, since the user can prompt it at any moment. The script places a row by its session's working directory, which a name set by `/rename`, `--name` or a hook does not give, and keeps in this tree a row it cannot place: `land` step 1 has why. Finished means the hooks pass and nothing in it dangles; work in progress stays out, and the report says it is at risk. Only the user's word in this conversation holds a finished unit back. Run the whole procedure, but on `main` where step 4 would branch, ask instead, since `git switch -c` moves the peer's HEAD too. Open the report with the commit and why it was made unasked. - **Ask them.** `ListAgents` names every live session by its `/rename` or `--name` name, or one a hook set, else `<cwd-basename>-<hash>` — its working directory, not its repo — and `SendMessage` reaches one. **Read every row rather than filtering by repo name**: a peer sitting in a subdirectory of this tree is both the likeliest contender and invisible to a prefix match (measured 2026-09-17). A peer is the only source for what is in its working tree and not in `HEAD`, so ask it — "are you editing `<path>` right now?" — before cutting a patch, not after a collision. What they say about *committed* state is as old as their session, so check that yourself. **Skip a session that was never prompted**, for which `bash ~/.claude/skills/land/scripts/never-prompted.sh <name>` exits 0: it holds nothing in this tree, and a message would prompt it, making it a peer `land` then has to count (2026-09-30). - **Stage and read in one chained command, commit in a second, and read the branch inside both** — with `git write-tree` carrying the index you read into the commit. The gap between reading a diff and running `git add` is where their hunk gets swept in, and HEAD is shared the same way: a peer's `git switch` moves the branch your commit lands on, with no error on either side. `git status` cannot show it — it reports files relative to HEAD, so a clean tree after someone moved HEAD reads exactly like one before, and "the tree is clean, so nothing is at risk" has been said and been wrong. One chain from `add` to `commit` closes that gap by dropping the index check: nothing can be read between two `&&`, and a `git diff --cached` printed mid-chain exits 0 and gates nothing (measured 2026-09-23: 3 of 3 probes on that form never verified the index). ```bash [[ "$(git branch --show-current)" == "<branch>" ]] \ && git add <paths> && git diff --cached && git write-tree # read the diff -- your hunks and nothing else -- and note the tree id [[ "$(git branch --show-current)" == "<branch>" \ && "$(git write-tree)" == "<tree>" ]] && git commit -F - <<'MSG' … MSG ``` `git write-tree` hashes the whole index, so the second chain refuses if anything reached it since you read — their hunk in your file, a file of theirs — and ignores what they left unstaged, which `commit` would not take either (all four cases measured 2026-09-23). From PowerShell both tests have to be an `if`: pwsh's `&&` runs its right side whenever the left side *ran*, true or false, so a literal port never refuses (measured 2026-09-23, pwsh 7.6). ```powershell if ((git branch --show-current) -eq '<branch>') { git add <paths> && git diff --cached && git write-tree } if ((git branch --show-current) -eq '<branch>' -and (git write-tree) -eq '<tree>') { git commit … } ``` A mismatch means someone moved HEAD: stop, `ListAgents`, ask — switching back is a HEAD move for them too. Recorded 2026-09-22, and `land` step 1 has the other seat: a peer's `git switch main` landed between this session's `switch -c` and its `git add`, and the commit went to `main` unnoticed for over an hour. If it already happened, propose the repair rather than run it — the stray commit onto `<branch>`, the wrong branch back to `<sha>^` — since both move refs a peer may be standing on, and resetting to the upstream instead would drop anything unpushed. - **Don't route around a staged file with `git commit -- <path>`.** With `core.filemode` false, the Windows default, a pathspec commit ignores the index's mode: a new script lands 100644 though `git add --chmod=+x` staged 100755, a tracked one keeps HEAD's mode, and the index keeps 100755 staged as `M` for the next plain commit, whoever makes it. It exits 0 (git 2.55.0.windows.3, 2026-10-01). With a peer's file staged, ask them to commit or unstage it first. - **`fatal: Unable to create '.git/index.lock': File exists` is their git command in flight**, not a stale lock. Wait and retry; never delete it. - **`[ERROR] Your pre-commit configuration is unstaged.` is their edit** when you never touched `.pre-commit-config.yaml`: pre-commit refuses every commit in the tree while that file has unstaged changes, whoever made them. Don't run the `git add` it suggests, which commits their half-made config under your message; ask them to finish or revert it. A config edit of yours blocks them the same way: make it last, and stage it in the chain that commits it (pre-commit 4.6.2, 2026-10-06). - **`[WARNING] Unstaged files detected.` on your commit is pre-commit taking their edits off disk.** It saves every unstaged change in the tree, theirs included, as a patch, runs `git checkout -- .`, runs the hooks, and applies the patch back, so for the hooks' seconds their files read as `HEAD`. A write of theirs in that window fails the commit as `files were modified by this hook` under whichever hook was running, though the hook passed; one that makes the patch conflict is discarded by a second `git checkout -- .`, under `Stashed changes conflicted with hook auto-fixes`, which names nothing of theirs. With a peer busy in the tree, commit from a throwaway worktree, whose index, HEAD and files are yours alone, and fast-forward the shared tree, where no hook runs. Stage the path first: `--ff-only` refuses an unstaged file as `Your local changes to the following files would be overwritten by merge`, even one already identical, and refuses once a peer's commit has moved `main`: branch again from the new `main` in the worktree and redo each commit, `git -C <wt> cherry-pick -n <sha>`, `git diff --cached`, then `commit -C <sha>`. Never `checkout <sha> -- <path>` there: that is your commit's whole file, built on the old `main`, so where their commit touched the same path, as one stamp manifest, it reverts their change and the fast-forward takes it (2026-10-13, read off its blob). The cherry-pick was run twice that day: the manifest auto-merged, and every peer stamp survived. When the shared copy also holds a peer's uncommitted edit beside yours, as one manifest several testers stamp at once does, `git diff --quiet` exits 1 with no output, and `git add` takes their edit too, which `--ff-only` refuses as above. Stage your commit's blob alone, `git update-index --cacheinfo <mode>,<blob>,<path>` with both read off `git ls-tree <branch> -- <path>`: an index already at the target lets the fast-forward through and leaves their edit on disk, unstaged. Tell this from their stash window by `git diff <branch> -- <path>`, which adds only their lines here and removes yours there (2026-10-13, git 2.55.0.windows.3, then both ways in a scratch repo). Copy nothing from the shared tree while a peer commits: a `cp` inside their stash window takes `HEAD`'s version, and the worktree's staged diff comes back empty, so write the edit into the worktree's copy instead, or carry one already made as a blob, from `git hash-object -w <path>` or, for one commit's share of a split file, the blob `stage-part.py` staged, `git rev-parse :<path>`. A blob equal to `HEAD:<path>`'s was read inside their window: take it again (six commits through two worktrees, 2026-10-13). The `git diff --quiet` before the fast-forward is the shared side's check: it refuses while their stash has your file reading as `HEAD`, the moment a fast-forward would fail their restore twice and leave their edits in the patch file alone. The work itself never leaves the main checkout (pre-commit 4.6.2 `staged_files_only.py`; the spurious failure, the clean restore, the empty copy and both refusals measured 2026-10-08, git 2.55.0.windows.3; the rollback and the failed restore read, not run). ```bash git worktree add -b <branch> <scratch>/wt HEAD # then write your edit into <scratch>/wt/<path> git -C <scratch>/wt cat-file blob <sha> > <scratch>/wt/<path> # or carry it as a blob, <sha> from git hash-object -w <path> git -C <scratch>/wt add <path> && git -C <scratch>/wt diff --cached # your hunk alone; commit there git diff --quiet <branch> -- <path> && git add <path> && git merge --ff-only <branch> # refuses mid-stash: retry git update-index --cacheinfo <mode>,<blob>,<path> && git merge --ff-only <branch> # a peer's edit beside yours; <mode>,<blob> from git ls-tree git -C <scratch>/wt switch -c <branch>-2 main && git -C <scratch>/wt cherry-pick -n <sha> # main moved: redo each commit, then commit -C <sha> git worktree remove <scratch>/wt && git branch -d <branch> # a superseded <branch> takes -D ``` - **Record what you left.** Commit only what is yours, and name the deferred piece in the commit message so `git log` carries it rather than this conversation. Staging one hunk out of a file they are also writing: [references/concurrent-sessions.md](references/concurrent-sessions.md). ## Fabric Git-synced repos Before the first commit in a repo containing `*.{ItemType}` folders: check `git config core.autocrlf` and whether `.gitattributes` pins the item folders (per `~/.claude/rules/fabric-git-serialization.md`). Whitespace-only diffs (EOF newline, CR-stripping) in portal-owned files are translation artifacts — do not commit them as "cleanup"; flag them and fix the `.gitattributes` instead. ## Finish - `git status --short` must come back clean, or every remaining line must be intentionally left and mentioned in the report. - Report each commit: hash, subject, and one line on what it contains — plus an explicit note that nothing was pushed.
Voir sur GitHub