fix(git): correct three command claims the plugin got wrong, and give rebase an owner

Three statements were false against the git in use (2.39.5), each verified by
running it.

`git rebase --autosquash HEAD~N` without `-i` is a silent no-op: git prints
"Successfully rebased", the `fixup!` commit survives with the same SHA, and
rewrite-history.md presented that as the preferred flow with `-i` as an optional
review step. The agent reports the squash as done and the `fixup!` subject then
trips this repo's own commit-msg gate. `-i` is now the command, not the alternative.

"Fetch never modifies a local branch, so it is always safe to run" — new text on
this branch — is false: `git fetch origin main:probe` fast-forwarded the local
branch, and a `+` prefix force-updates it, losing commits. The claim is scoped to
the no-refspec form.

`git worktree add --orphan` does not exist before Git 2.42; on 2.39.5 it is
`error: unknown option 'orphan'`, exit 129. The same file gives a version floor for
`--recurse-submodules` three sections earlier. Floor added, with a fallback that
was tested before being documented.

git-workflow claimed "every request resolves to exactly one of these six" while
rebase, reset and stash were owned by no skill — `git reset` appeared nowhere in
the plugin, old tree or new — so "undo my last commit" routed nowhere. The claim is
gone, the router gains rows for all three, and the procedures now exist: plain
rebase with `--onto` and conflict handling, a reset mode table gated on `--hard`,
and stash save/pop/list/drop. `--hard` gets an always-loaded Gotcha, matching the
register the force-push refusal already sets.

Cherry-pick had three claimants pointing at git-history while git-commits owned the
flow, and the two copies were not equivalent — git-history's lacked the destination
check, the rtk prefix and `--abort`. Resolved to git-commits per #112; the weaker
duplicate is replaced by a hand-off.

git-commits' metadata.version was deleted rather than bumped in 14af50b, leaving two
house-contract documents citing a worked v0.1.2 to v0.1.3 transition against a file
declaring no version. Restored to 0.1.3.

Also: the divergent-pull explanation stated a `--ff-only` default that does not
exist (it is a hard error); `--remote` "requires" a configured branch where it uses
one; `git push origin --delete` moved to git-remotes, which owns the remote-side
gates; seven retired `git:<name>` source slugs; git-orchestrate quoted a
git-workflow sentence that no longer exists; git-submodules regains the indirect
trigger that made "add a dependency repo" routable; and commit atomicity is a common
gate rather than reachable only from the create flow.

Refs: #112, #113
This commit is contained in:
2026-09-01 12:38:38 +00:00
parent fc305ba7d9
commit 20e5627fd7
32 changed files with 246 additions and 70 deletions

View File

@@ -16,7 +16,7 @@ You are the orchestrator for the git plugin—a composable workflow dispatcher d
You act on the caller's real branch and session context (you explicitly carry forward `current_branch`), not a disposable copy — you do not run in an isolated worktree. You act on the caller's real branch and session context (you explicitly carry forward `current_branch`), not a disposable copy — you do not run in an isolated worktree.
**Scope:** this orchestrator routes git-object operations only (commits, branches, worktrees, remotes, submodules, history). `pc-author` and `pc-run` (pre-commit config authoring and hook execution) are intentionally not routed here — they operate on `.pre-commit-config.yaml` and hook installation, not git objects. `git-workflow` is also not routed here, but for a different reason than `pc-author`/`pc-run`: it is a human-facing conversational wrapper for all git operation types (commits, branches, history, submodules, worktrees, remotes), and it itself calls this orchestrator internally as its execution backend — its own workflow explicitly invokes the `git-orchestrate` agent as its final step. It is not a peer to invoke instead of this dispatcher, and it explicitly refuses agent callers ("Do not use when the caller is an agent"). Agent callers route git-object operations here directly; direct human users to `git-workflow` when they want guided, conversational git help — it will call back into this orchestrator itself. Invoke `pc-author`/`pc-run` directly rather than through this dispatcher; do not invoke `git-workflow` as an agent caller under any circumstance. **Scope:** this orchestrator routes git-object operations only (commits, branches, worktrees, remotes, submodules, history). `pc-author` and `pc-run` (pre-commit config authoring and hook execution) are intentionally not routed here — they operate on `.pre-commit-config.yaml` and hook installation, not git objects. `git-workflow` is also not routed here, but for a different reason than `pc-author`/`pc-run`: it is a human-facing conversational wrapper for all git operation types (commits, branches, history, submodules, worktrees, remotes), and it itself calls this orchestrator internally as its execution backend — its own workflow explicitly invokes the `git-orchestrate` agent as its final step. It is not a peer to invoke instead of this dispatcher, and its own boundary clause sends agent callers here ("Not an agent caller -> `git-orchestrate`"). Agent callers route git-object operations here directly; direct human users to `git-workflow` when they want guided, conversational git help — it will call back into this orchestrator itself. Invoke `pc-author`/`pc-run` directly rather than through this dispatcher; do not invoke `git-workflow` as an agent caller under any circumstance.
## Hard rules ## Hard rules

View File

@@ -20,7 +20,7 @@ Describe your branch task: create a feature/hotfix/release branch, switch, delet
|------|---------| |------|---------|
| `SKILL.md` | Skill instructions for agents | | `SKILL.md` | Skill instructions for agents |
| `references/branch-patterns.md` | Loaded when a branch's base, name prefix, or merge rule depends on GitHub Flow vs. Gitflow | | `references/branch-patterns.md` | Loaded when a branch's base, name prefix, or merge rule depends on GitHub Flow vs. Gitflow |
| `references/branch-operations.md` | Loaded when running a create/switch/delete/rename/track/list action, or resolving `get-intent` | | `references/branch-operations.md` | Loaded when running a create/switch/delete/rename/track/list/stash action, or resolving `get-intent` |
| `references/merging.md` | Loaded when merging one branch into another or resolving merge conflicts | | `references/merging.md` | Loaded when merging one branch into another or resolving merge conflicts |
| `references/comparing-branches.md` | Loaded when comparing two branches or finding where they diverged | | `references/comparing-branches.md` | Loaded when comparing two branches or finding where they diverged |
| `references/orchestrator-contract.md` | Loaded when `git-orchestrate` or another calling agent supplies a structured request rather than prose | | `references/orchestrator-contract.md` | Loaded when `git-orchestrate` or another calling agent supplies a structured request rather than prose |
@@ -29,5 +29,6 @@ Describe your branch task: create a feature/hotfix/release branch, switch, delet
## Composition ## Composition
`git-orchestrate` calls this skill for the branch step of a multi-step workflow and parses its `git-orchestrate` calls this skill for the branch step of a multi-step workflow and parses its
structured result. Cherry-pick and revert are `git-history`'s; commit authoring and rebase are structured result. Revert is `git-history`'s; commit authoring, rebase, reset and cherry-pick are
`git-commits`'; branch operations against a Gitea-hosted remote are `gitea-branches`'. `git-commits`'; deleting a remote branch is `git-remotes`'; branch operations against a
Gitea-hosted remote are `gitea-branches`'.

View File

@@ -33,7 +33,7 @@ The two patterns are not mixable, and the wrong merge rule silently damages hist
| Action | Reference | | Action | Reference |
|---|---| |---|---|
| create, switch, delete, rename, track, list, get-intent | `references/branch-operations.md` | | create, switch, delete, rename, track, list, get-intent, stash | `references/branch-operations.md` |
| merge a branch, resolve merge conflicts | `references/merging.md` | | merge a branch, resolve merge conflicts | `references/merging.md` |
| compare two branches, find their divergence | `references/comparing-branches.md` | | compare two branches, find their divergence | `references/comparing-branches.md` |
@@ -51,7 +51,7 @@ These gates are passable. The `main`/`master` refusal in Gotchas is not.
## Step 4 — Set tracking ## Step 4 — Set tracking
When pushing a branch for the first time, always `git push -u origin <branch>`. Without an upstream, later pushes and pulls either fail or silently target the wrong remote branch, and the caller has no way to tell which happened. A new branch's first push must be `git push -u origin <branch>`. The push itself is `git-remotes`' — every remote-side gate lives there, which is why Step 2's remote-delete row hands off the same way — but the upstream requirement originates here, so carry it in the handoff. Without an upstream, later pushes and pulls either fail or silently target the wrong remote branch, and the caller has no way to tell which happened.
## Step 5 — Return a structured result ## Step 5 — Return a structured result

View File

@@ -15,7 +15,9 @@ hatch.
- **delete (local)** — `git branch -d <branch>` refuses when the branch holds unmerged commits, - **delete (local)** — `git branch -d <branch>` refuses when the branch holds unmerged commits,
which is why it is the default. `git branch -D <branch>` forces the deletion and discards that which is why it is the default. `git branch -D <branch>` forces the deletion and discards that
work — only after the destructive-operation gates pass and `confirm: true` is set. work — only after the destructive-operation gates pass and `confirm: true` is set.
- **delete (remote)** — `git push origin --delete <branch>`. - **delete (remote)** — not this skill's. Deleting a remote branch is a push, and every remote-side
gate lives in `git-remotes`; hand it there rather than running the push from here. Its
`references/push.md` carries the command and the refspec form.
- **rename** — `git branch -m <old> <new>`. - **rename** — `git branch -m <old> <new>`.
- **list** — `git branch` (local), `-a` (local plus remote-tracking), `-r` (remote-tracking only), - **list** — `git branch` (local), `-a` (local plus remote-tracking), `-r` (remote-tracking only),
`--merged` / `--no-merged` (filter by merge status into the current branch). `--merged` / `--no-merged` (filter by merge status into the current branch).
@@ -32,3 +34,23 @@ On `get-intent`, either parse the intent back out of the branch-name convention
(`feature/<intent-slug>`) or return `{ "intent": null }` when the caller never persisted the (`feature/<intent-slug>`) or return `{ "intent": null }` when the caller never persisted the
create-time value. Never fabricate an intent: a downstream commit message built on a guessed create-time value. Never fabricate an intent: a downstream commit message built on a guessed
intent is worse than one built on none. intent is worse than one built on none.
## Stashing work in progress
A switch aborts rather than clobbering conflicting local changes (see Gotchas). Stash is the way
past it: it shelves the working tree and index so the branch pointer can move.
- **save** — `git stash push -m "<message>"`. Add `-u` to include untracked files; verified on Git
2.39.5, a plain `push` leaves them in place, and a plain `push` with *only* untracked changes
reports `No local changes to save` and stashes nothing. Bare `git stash` is `push` with no message.
- **restore** — `git stash pop` applies the newest entry and deletes it. `git stash apply stash@{n}`
applies without deleting, for replaying one shelf onto more than one branch.
- **list** — `git stash list`; `git stash show -p stash@{n}` prints that entry's diff.
- **drop** — `git stash drop stash@{n}` deletes one entry. `git stash clear` deletes all of them
and nothing recovers them — confirm before running it.
- **branch from a stash** — `git stash branch <branch> stash@{n}` creates a branch at the commit the
stash was taken from and pops it there. Use it when the stash no longer applies to the current tip.
**A conflicting `pop` keeps the entry.** Verified on 2.39.5: it exits 1, writes conflict markers,
prints "The stash entry is kept in case you need it again", and `git stash list` still shows it.
Resolve, `git add`, then `git stash drop` the entry by hand — otherwise it silently accumulates.

View File

@@ -6,8 +6,8 @@ source_keys:
# Merging one branch into another # Merging one branch into another
Scope is fast-forward and merge-commit mechanics plus conflict resolution. Rebase belongs to Scope is fast-forward and merge-commit mechanics plus conflict resolution. Rebase and cherry-pick
`git-commits`; cherry-pick and revert to `git-history`. belong to `git-commits`; revert to `git-history`.
- **Fast-forward** — `git merge <branch>` advances the pointer with no merge commit when the - **Fast-forward** — `git merge <branch>` advances the pointer with no merge commit when the
target has not diverged. target has not diverged.

View File

@@ -8,6 +8,7 @@ description: >
Not branch lifecycle -> `git-branches`. Not branch lifecycle -> `git-branches`.
metadata: metadata:
version: "0.1.3"
category: git category: git
source_keys: source_keys:
- conventional-commits-spec - conventional-commits-spec
@@ -22,6 +23,7 @@ allowed-tools: Bash
- **Run git as `rtk git <subcommand>`, never bare `git`** — org convention, in `&&` chains too. - **Run git as `rtk git <subcommand>`, never bare `git`** — org convention, in `&&` chains too.
- **Refuse to force-push `main`/`master`** — a rewrite leaves the branch diverged and the reflex is to force it back; safe only where nobody else has based work on it. - **Refuse to force-push `main`/`master`** — a rewrite leaves the branch diverged and the reflex is to force it back; safe only where nobody else has based work on it.
- **`reset --hard` is a confirmation gate, not a default.** It overwrites the working tree, and uncommitted edits it discards were never in git, so no reflog recovers them. Name what will be lost and offer a stash first.
- **Never add `--no-verify`** — using it when a hook fails bypasses the QA gate the pipeline depends on. Only on the user's explicit demand, with a warning. - **Never add `--no-verify`** — using it when a hook fails bypasses the QA gate the pipeline depends on. Only on the user's explicit demand, with a warning.
## Dispatch ## Dispatch
@@ -31,18 +33,19 @@ Read exactly one flow file. Each is self-contained.
| Condition | Flow | Read | | Condition | Flow | Read |
|---|---|---| |---|---|---|
| Composing a new commit from staged changes | create | `references/create-commit.md` | | Composing a new commit from staged changes | create | `references/create-commit.md` |
| Amending, squashing, or folding a fixup into an earlier commit | rewrite | `references/rewrite-history.md` | | Amending, squashing, folding a fixup, rebasing onto a new base, or resetting HEAD | rewrite | `references/rewrite-history.md` |
| Replaying an existing commit onto the current branch | cherry-pick | `references/cherry-pick.md` | | Replaying an existing commit onto the current branch | cherry-pick | `references/cherry-pick.md` |
## Gates on every flow ## Gates on every flow
1. **Confirmation.** No history rewrite executes without explicit approval from the user or the calling agent. Cherry-pick needs the destination branch confirmed first. 1. **Confirmation.** No history rewrite executes without explicit approval from the user or the calling agent. Cherry-pick needs the destination branch confirmed first.
2. **Secrets.** Before any commit or amend, scan the staged diff for anything resembling an API key, 2. **Atomicity.** The result must be one logical, independently reviewable and reversible change that leaves the repository buildable and testable. This binds an amend or a squashed result as much as a fresh commit — say so before writing it, not after.
3. **Secrets.** Before any commit or amend, scan the staged diff for anything resembling an API key,
token, password, connection string, or environment-specific config. Stop and flag it rather than token, password, connection string, or environment-specific config. Stop and flag it rather than
committing it. committing it.
3. **Validation.** Check the message against commitlint `config-conventional` before committing. If a type, footer, or breaking-change edge case is not obvious, read `references/conventional-commits-spec.md` — it carries the constraint table, the 11-type set, and the footer token rules. 4. **Validation.** Check the message against commitlint `config-conventional` before committing. If a type, footer, or breaking-change edge case is not obvious, read `references/conventional-commits-spec.md` — it carries the constraint table, the 11-type set, and the footer token rules.
4. **SemVer impact.** Report the bump the commit implies: `feat` → MINOR, `fix`/`perf`/`revert` → PATCH, any breaking change → MAJOR, everything else → none. Callers decide releases from this, so never omit it. 5. **SemVer impact.** Report the bump the commit implies: `feat` → MINOR, `fix`/`perf`/`revert` → PATCH, any breaking change → MAJOR, everything else → none. Callers decide releases from this, so never omit it.
5. **Conflicts.** If a rebase or cherry-pick halts, offer resolution or an abort. Do not resolve automatically without confirmation. 6. **Conflicts.** If a rebase or cherry-pick halts, offer resolution or an abort. Do not resolve automatically without confirmation.
## Output ## Output

View File

@@ -21,7 +21,9 @@ Prefer this whenever a commit is written to be folded, because git does the mark
1. `rtk git commit --fixup=<commit>` keeps the target's message; `rtk git commit --squash=<commit>` lets you edit the combined message later. Both prefix the message with `fixup!`/`squash!` and name the target commit. 1. `rtk git commit --fixup=<commit>` keeps the target's message; `rtk git commit --squash=<commit>` lets you edit the combined message later. Both prefix the message with `fixup!`/`squash!` and name the target commit.
2. Get explicit approval — the rebase still rewrites history. 2. Get explicit approval — the rebase still rewrites history.
3. Run `rtk git rebase --autosquash HEAD~N`, or `-i --autosquash` to review the plan first. Git reorders the tagged commits against their targets automatically. 3. Run `rtk git rebase -i --autosquash HEAD~N`. Git pre-fills the todo list with the tagged commits already reordered against their targets; save it unchanged to apply.
**`-i` is not optional here.** On Git 2.39.5, `rtk git rebase --autosquash HEAD~N` without `-i` prints `Successfully rebased and updated refs/heads/<branch>.` and exits 0 while leaving the `fixup!` commit in place at its original SHA — `--autosquash` is honoured only by the interactive machinery, and the false success is the trap: the fold is reported as done, and the surviving `fixup!` subject then fails the Conventional Commits `commit-msg` hook. Later Git versions taught the non-interactive rebase to honour the flag, but `-i --autosquash` is correct on every version, so always write that.
## Squash by hand (interactive rebase) ## Squash by hand (interactive rebase)
@@ -35,3 +37,40 @@ Use this when the commits were not tagged at commit time. **Interactive rebase h
## When a rebase halts on a conflict ## When a rebase halts on a conflict
Offer conflict resolution or `rtk git rebase --abort`. Do not resolve conflicts automatically without confirmation. Offer conflict resolution or `rtk git rebase --abort`. Do not resolve conflicts automatically without confirmation.
## Rebase the branch onto a new base
Replays this branch's commits on top of another branch's tip — bringing a feature branch up to
date without a merge commit.
1. Confirm nothing being replayed has been pushed anywhere someone else has based work on. A rebase
gives every replayed commit a new SHA, which breaks any clone that already has the old ones.
2. Get explicit approval — this rewrites history like every other flow on this page.
3. `rtk git fetch origin` first, so `<newbase>` is the real tip rather than a stale local copy.
4. `rtk git rebase <newbase>` — for example `rtk git rebase main`. Use
`rtk git rebase --onto <newbase> <upstream> <branch>` to replay only the commits after
`<upstream>`, which is how a branch started from the wrong base gets moved.
5. The branch has now diverged from its remote. It needs
`--force-with-lease --force-if-includes` to push, never a bare `--force`, and never on
`main`/`master` — refuse that and explain.
## Move the branch pointer back (`git reset`)
`reset` moves the current branch to another commit. The mode decides what survives:
| Mode | Branch pointer | Index | Working tree |
|---|---|---|---|
| `--soft` | moves | untouched — the changes stay staged | untouched |
| `--mixed` (default) | moves | reset — the changes become unstaged | untouched |
| `--hard` | moves | reset | **overwritten; uncommitted work is destroyed** |
- "Undo my last commit but keep the changes" is `rtk git reset --soft HEAD~1`. That is the default
answer to the request; reach for anything else only when the caller asked for it.
- `rtk git reset --mixed HEAD~1` when the staging should be redone from scratch too.
- `rtk git reset --hard <ref>` is gated like a force-push: state exactly which uncommitted changes
will be discarded, get approval for that specific reset, and offer `rtk git stash push -u` first.
The commits it drops stay reachable through `git reflog`; the uncommitted edits never entered git
at all and nothing recovers them.
Reset does not rewrite the commits it leaves behind, so no force-push is needed unless the branch
was already pushed at the newer commit.

View File

@@ -8,7 +8,7 @@ This skill handles history inspection within the git workflow suite. It queries
## Composition ## Composition
`git-branches` delegates cherry-pick and revert here (see `git-branches`'s `references/merging.md`), which is why this skill carries those two operations rather than treating them as out of scope. They are general git knowledge, not drawn from the `history-inspection.md` research corpus. Server-side commit history on a Gitea-hosted repository belongs to `gitea-branches`; this skill reads the local working copy. `git-branches` delegates revert here (see `git-branches`'s `references/merging.md`), which is why this skill carries that operation rather than treating it as out of scope; it is general git knowledge, not drawn from the `history-inspection.md` research corpus. Cherry-pick is **not** this skill's: `git-commits` owns it, and this skill's job ends at locating the SHA to hand over. Server-side commit history on a Gitea-hosted repository belongs to `gitea-branches`; this skill reads the local working copy.
## Usage ## Usage

View File

@@ -48,7 +48,7 @@ If you need the placeholder catalogue, format presets, `--diff-filter` letters,
Offer the operation and its consequence; run it only once the user has chosen. Offer the operation and its consequence; run it only once the user has chosen.
- `git cherry-pick <commit>` copies the commit's changes onto the current HEAD — for backporting a fix to another branch. - Backporting the commit to another branch is a cherry-pick, and cherry-pick is `git-commits`' — it owns the destination-branch check, the `rtk git` wrapper and the `--abort` path. Hand it the SHA; do not run `git cherry-pick` from here.
- `git revert <commit>` adds a new commit undoing it — for un-applying merged work without rewriting history. - `git revert <commit>` adds a new commit undoing it — for un-applying merged work without rewriting history.
- `git blame <file>` attributes each line to the commit that last touched it, when the question is which commit introduced one specific line. - `git blame <file>` attributes each line to the commit that last touched it, when the question is which commit introduced one specific line.

View File

@@ -7,7 +7,9 @@ source_keys:
# Fetching # Fetching
Fetch updates remote-tracking branches (`refs/remotes/<name>/*`) and never modifies a local branch, so it is always safe to run. Fetch **with no refspec** updates remote-tracking branches (`refs/remotes/<name>/*`) and leaves every local branch alone.
That safety comes from the default refspec, not from `fetch` itself. Give it an explicit one and it writes to local branches: verified on Git 2.39.5, `git fetch origin main:probe` fast-forwarded the local `probe` branch, and a `+` prefix force-updates the destination, discarding whatever commits it held. Treat any `fetch` carrying a `<src>:<dst>` refspec as a branch update, not a read.
- **One remote**: `git fetch <remote>` — all branches - **One remote**: `git fetch <remote>` — all branches
- **One branch**: `git fetch <remote> <branch>` — the result lands in `FETCH_HEAD`, not a tracking ref - **One branch**: `git fetch <remote> <branch>` — the result lands in `FETCH_HEAD`, not a tracking ref

View File

@@ -23,9 +23,11 @@ A pull that diverges with no strategy configured fails, and that failure is the
## Config precedence ## Config precedence
The installed default varies by Git version — older versions merge on divergence, newer ones `--ff-only` is not Git's default on an unset config, and never has been. Older versions silently
default to `--ff-only` — so an unset `pull.ff` means the same pull behaves differently on different merged on divergence; current ones refuse outright — verified on Git 2.39.5, a divergent pull with
machines. Set it explicitly. nothing configured prints the reconciliation hint and exits 128 with
`fatal: Need to specify how to reconcile divergent branches.` The behaviour therefore still varies
by installed version, and neither variant is the one you want. Set it explicitly.
Highest wins: Highest wins:

View File

@@ -3,7 +3,8 @@ name: git-submodules
description: > description: >
Use when managing Git submodules — the full lifecycle of a nested Use when managing Git submodules — the full lifecycle of a nested
repository inside a superproject. repository inside a superproject — including phrasings that never say the
word, such as "add a dependency repo" or "vendor this repo inside ours".
Not multiple checkouts of one repo -> `git-worktrees`. Not multiple checkouts of one repo -> `git-worktrees`.
Not the superproject's own remotes -> `git-remotes`. Not the superproject's own remotes -> `git-remotes`.

View File

@@ -70,8 +70,8 @@ rtk git submodule update --remote --merge --recursive
rtk git commit -am "chore: update submodules to latest" rtk git commit -am "chore: update submodules to latest"
``` ```
`--remote` requires `submodule.<name>.branch`; without it Git falls back to the remote's default `--remote` uses `submodule.<name>.branch` when it is set; without it Git falls back to the remote's
branch. Commit the superproject afterwards or the new pin is lost on the next `update`. default branch. Commit the superproject afterwards or the new pin is lost on the next `update`.
## Run one command across every submodule ## Run one command across every submodule

View File

@@ -22,10 +22,10 @@ source_keys:
Other source keys extracted during the git plugin research phase inform sibling skills in the git workflow suite, not this one: Other source keys extracted during the git plugin research phase inform sibling skills in the git workflow suite, not this one:
- `context7-git-htmldocs` — git:branches, git:history, git:remotes - `context7-git-htmldocs` — git-branches, git-history, git-remotes
- `git-scm-docs` — git:configuration - `git-scm-docs` — no current skill; it backed a git-configuration skill that no longer exists and survives here as provenance only
- `git-scm-worktree-docs` — git:worktrees - `git-scm-worktree-docs` — git-worktrees
- `nvie-gitflow-post`, `atlassian-gitflow-tutorial`, `gitflow-cheatsheet` — git:branches - `nvie-gitflow-post`, `atlassian-gitflow-tutorial`, `gitflow-cheatsheet` — git-branches
- `conventional-commits-spec`, `commitlint-config-conventional` — git:commits - `conventional-commits-spec`, `commitlint-config-conventional` — git-commits
- `git-scm-push-docs`, `git-scm-fetch-docs`, `git-scm-pull-docs`, `git-scm-remote-docs` — git:remotes - `git-scm-push-docs`, `git-scm-fetch-docs`, `git-scm-pull-docs`, `git-scm-remote-docs` — git-remotes
- `git-scm-bisect-docs`, `git-scm-log-docs`, `git-scm-diff-docs` — git:history - `git-scm-bisect-docs`, `git-scm-log-docs`, `git-scm-diff-docs` — git-history

View File

@@ -28,13 +28,16 @@ metadata:
## Domains ## Domains
Every request resolves to exactly one of these six. An unambiguous one should have gone straight Route to the domain that owns the operation, and in sequence when a request spans two — a rebase
to the domain skill; this skill exists for the ones that did not. that ends in a force-push is `git-commits`, then `git-remotes`. An unambiguous request should have
gone straight to the domain skill; this one exists for the ones that did not.
| The request is about | Domain | | The request is about | Domain |
|---|---| |---|---|
| Writing, amending, squashing, or cherry-picking a commit, and its message | `git-commits` | | Writing, amending, squashing, or cherry-picking a commit, and its message | `git-commits` |
| Rebasing onto a new base, or undoing a commit with `reset` | `git-commits` |
| Creating, switching, deleting, renaming, tracking, or merging a local branch | `git-branches` | | Creating, switching, deleting, renaming, tracking, or merging a local branch | `git-branches` |
| Stashing work in progress to move between branches | `git-branches` |
| When a change landed, which commit broke something, what to revert or backport | `git-history` | | When a change landed, which commit broke something, what to revert or backport | `git-history` |
| Anything touching a remote — remote config, fetch, push, pull — even unnamed | `git-remotes` | | Anything touching a remote — remote config, fetch, push, pull — even unnamed | `git-remotes` |
| A nested repository pinned inside this one by a recorded commit | `git-submodules` | | A nested repository pinned inside this one by a recorded commit | `git-submodules` |

View File

@@ -53,7 +53,7 @@ final argument of the `--track -b` form.
| `-b <branch>` | Create and check out a new branch; fails if it exists | | `-b <branch>` | Create and check out a new branch; fails if it exists |
| `-B <branch>` | Like `-b` but resets the branch if it already exists | | `-B <branch>` | Like `-b` but resets the branch if it already exists |
| `-d` / `--detach` | Detach HEAD; useful for throwaway experiments | | `-d` / `--detach` | Detach HEAD; useful for throwaway experiments |
| `--orphan` | Create empty unborn branch | | `--orphan` | Create empty unborn branch — **Git 2.42+**; earlier versions exit 129 with `error: unknown option 'orphan'`. Fallback below |
| `--no-checkout` | Suppress initial checkout (for sparse-checkout setup) | | `--no-checkout` | Suppress initial checkout (for sparse-checkout setup) |
| `--guess-remote` | Look for a matching remote-tracking branch by path basename | | `--guess-remote` | Look for a matching remote-tracking branch by path basename |
| `--lock [--reason <str>]` | Lock immediately on creation (atomic; avoids race vs. add-then-lock) | | `--lock [--reason <str>]` | Lock immediately on creation (atomic; avoids race vs. add-then-lock) |
@@ -67,7 +67,22 @@ Using `-` as `<commit-ish>` is shorthand for `@{-1}` (the branch checked out bef
```bash ```bash
git worktree add --orphan -b <branch> <path> git worktree add --orphan -b <branch> <path>
``` ```
Creates an empty branch with no commits. Creates an empty branch with no commits. **`--orphan` needs Git 2.42 or later** — it was added
upstream in 2.42, and on 2.39.5 this fails with `error: unknown option 'orphan'` and exit 129.
Check `git --version` before reaching for it.
Fallback on older Git, verified on 2.39.5 — detach first, then orphan the linked worktree in place,
which leaves the main worktree on its own branch throughout:
```bash
git worktree add -d <path> # linked worktree, detached HEAD
cd <path>
git switch --orphan <branch> # unborn branch: empty index, empty working tree
```
`git worktree list` then shows the new worktree at `0000000 [<branch>]` until its first commit.
Do not substitute `git switch --orphan` in the *main* worktree: it clears that checkout, which is
the disruption worktrees exist to avoid.
## Sparse-checkout worktree ## Sparse-checkout worktree

View File

@@ -16,7 +16,7 @@ You are the orchestrator for the git plugin—a composable workflow dispatcher d
You act on the caller's real branch and session context (you explicitly carry forward `current_branch`), not a disposable copy — you do not run in an isolated worktree. You act on the caller's real branch and session context (you explicitly carry forward `current_branch`), not a disposable copy — you do not run in an isolated worktree.
**Scope:** this orchestrator routes git-object operations only (commits, branches, worktrees, remotes, submodules, history). `pc-author` and `pc-run` (pre-commit config authoring and hook execution) are intentionally not routed here — they operate on `.pre-commit-config.yaml` and hook installation, not git objects. `git-workflow` is also not routed here, but for a different reason than `pc-author`/`pc-run`: it is a human-facing conversational wrapper for all git operation types (commits, branches, history, submodules, worktrees, remotes), and it itself calls this orchestrator internally as its execution backend — its own workflow explicitly invokes the `git-orchestrate` agent as its final step. It is not a peer to invoke instead of this dispatcher, and it explicitly refuses agent callers ("Do not use when the caller is an agent"). Agent callers route git-object operations here directly; direct human users to `git-workflow` when they want guided, conversational git help — it will call back into this orchestrator itself. Invoke `pc-author`/`pc-run` directly rather than through this dispatcher; do not invoke `git-workflow` as an agent caller under any circumstance. **Scope:** this orchestrator routes git-object operations only (commits, branches, worktrees, remotes, submodules, history). `pc-author` and `pc-run` (pre-commit config authoring and hook execution) are intentionally not routed here — they operate on `.pre-commit-config.yaml` and hook installation, not git objects. `git-workflow` is also not routed here, but for a different reason than `pc-author`/`pc-run`: it is a human-facing conversational wrapper for all git operation types (commits, branches, history, submodules, worktrees, remotes), and it itself calls this orchestrator internally as its execution backend — its own workflow explicitly invokes the `git-orchestrate` agent as its final step. It is not a peer to invoke instead of this dispatcher, and its own boundary clause sends agent callers here ("Not an agent caller -> `git-orchestrate`"). Agent callers route git-object operations here directly; direct human users to `git-workflow` when they want guided, conversational git help — it will call back into this orchestrator itself. Invoke `pc-author`/`pc-run` directly rather than through this dispatcher; do not invoke `git-workflow` as an agent caller under any circumstance.
## Hard rules ## Hard rules

View File

@@ -20,7 +20,7 @@ Describe your branch task: create a feature/hotfix/release branch, switch, delet
|------|---------| |------|---------|
| `SKILL.md` | Skill instructions for agents | | `SKILL.md` | Skill instructions for agents |
| `references/branch-patterns.md` | Loaded when a branch's base, name prefix, or merge rule depends on GitHub Flow vs. Gitflow | | `references/branch-patterns.md` | Loaded when a branch's base, name prefix, or merge rule depends on GitHub Flow vs. Gitflow |
| `references/branch-operations.md` | Loaded when running a create/switch/delete/rename/track/list action, or resolving `get-intent` | | `references/branch-operations.md` | Loaded when running a create/switch/delete/rename/track/list/stash action, or resolving `get-intent` |
| `references/merging.md` | Loaded when merging one branch into another or resolving merge conflicts | | `references/merging.md` | Loaded when merging one branch into another or resolving merge conflicts |
| `references/comparing-branches.md` | Loaded when comparing two branches or finding where they diverged | | `references/comparing-branches.md` | Loaded when comparing two branches or finding where they diverged |
| `references/orchestrator-contract.md` | Loaded when `git-orchestrate` or another calling agent supplies a structured request rather than prose | | `references/orchestrator-contract.md` | Loaded when `git-orchestrate` or another calling agent supplies a structured request rather than prose |
@@ -29,5 +29,6 @@ Describe your branch task: create a feature/hotfix/release branch, switch, delet
## Composition ## Composition
`git-orchestrate` calls this skill for the branch step of a multi-step workflow and parses its `git-orchestrate` calls this skill for the branch step of a multi-step workflow and parses its
structured result. Cherry-pick and revert are `git-history`'s; commit authoring and rebase are structured result. Revert is `git-history`'s; commit authoring, rebase, reset and cherry-pick are
`git-commits`'; branch operations against a Gitea-hosted remote are `gitea-branches`'. `git-commits`'; deleting a remote branch is `git-remotes`'; branch operations against a
Gitea-hosted remote are `gitea-branches`'.

View File

@@ -33,7 +33,7 @@ The two patterns are not mixable, and the wrong merge rule silently damages hist
| Action | Reference | | Action | Reference |
|---|---| |---|---|
| create, switch, delete, rename, track, list, get-intent | `references/branch-operations.md` | | create, switch, delete, rename, track, list, get-intent, stash | `references/branch-operations.md` |
| merge a branch, resolve merge conflicts | `references/merging.md` | | merge a branch, resolve merge conflicts | `references/merging.md` |
| compare two branches, find their divergence | `references/comparing-branches.md` | | compare two branches, find their divergence | `references/comparing-branches.md` |
@@ -51,7 +51,7 @@ These gates are passable. The `main`/`master` refusal in Gotchas is not.
## Step 4 — Set tracking ## Step 4 — Set tracking
When pushing a branch for the first time, always `git push -u origin <branch>`. Without an upstream, later pushes and pulls either fail or silently target the wrong remote branch, and the caller has no way to tell which happened. A new branch's first push must be `git push -u origin <branch>`. The push itself is `git-remotes`' — every remote-side gate lives there, which is why Step 2's remote-delete row hands off the same way — but the upstream requirement originates here, so carry it in the handoff. Without an upstream, later pushes and pulls either fail or silently target the wrong remote branch, and the caller has no way to tell which happened.
## Step 5 — Return a structured result ## Step 5 — Return a structured result

View File

@@ -15,7 +15,9 @@ hatch.
- **delete (local)** — `git branch -d <branch>` refuses when the branch holds unmerged commits, - **delete (local)** — `git branch -d <branch>` refuses when the branch holds unmerged commits,
which is why it is the default. `git branch -D <branch>` forces the deletion and discards that which is why it is the default. `git branch -D <branch>` forces the deletion and discards that
work — only after the destructive-operation gates pass and `confirm: true` is set. work — only after the destructive-operation gates pass and `confirm: true` is set.
- **delete (remote)** — `git push origin --delete <branch>`. - **delete (remote)** — not this skill's. Deleting a remote branch is a push, and every remote-side
gate lives in `git-remotes`; hand it there rather than running the push from here. Its
`references/push.md` carries the command and the refspec form.
- **rename** — `git branch -m <old> <new>`. - **rename** — `git branch -m <old> <new>`.
- **list** — `git branch` (local), `-a` (local plus remote-tracking), `-r` (remote-tracking only), - **list** — `git branch` (local), `-a` (local plus remote-tracking), `-r` (remote-tracking only),
`--merged` / `--no-merged` (filter by merge status into the current branch). `--merged` / `--no-merged` (filter by merge status into the current branch).
@@ -32,3 +34,23 @@ On `get-intent`, either parse the intent back out of the branch-name convention
(`feature/<intent-slug>`) or return `{ "intent": null }` when the caller never persisted the (`feature/<intent-slug>`) or return `{ "intent": null }` when the caller never persisted the
create-time value. Never fabricate an intent: a downstream commit message built on a guessed create-time value. Never fabricate an intent: a downstream commit message built on a guessed
intent is worse than one built on none. intent is worse than one built on none.
## Stashing work in progress
A switch aborts rather than clobbering conflicting local changes (see Gotchas). Stash is the way
past it: it shelves the working tree and index so the branch pointer can move.
- **save** — `git stash push -m "<message>"`. Add `-u` to include untracked files; verified on Git
2.39.5, a plain `push` leaves them in place, and a plain `push` with *only* untracked changes
reports `No local changes to save` and stashes nothing. Bare `git stash` is `push` with no message.
- **restore** — `git stash pop` applies the newest entry and deletes it. `git stash apply stash@{n}`
applies without deleting, for replaying one shelf onto more than one branch.
- **list** — `git stash list`; `git stash show -p stash@{n}` prints that entry's diff.
- **drop** — `git stash drop stash@{n}` deletes one entry. `git stash clear` deletes all of them
and nothing recovers them — confirm before running it.
- **branch from a stash** — `git stash branch <branch> stash@{n}` creates a branch at the commit the
stash was taken from and pops it there. Use it when the stash no longer applies to the current tip.
**A conflicting `pop` keeps the entry.** Verified on 2.39.5: it exits 1, writes conflict markers,
prints "The stash entry is kept in case you need it again", and `git stash list` still shows it.
Resolve, `git add`, then `git stash drop` the entry by hand — otherwise it silently accumulates.

View File

@@ -6,8 +6,8 @@ source_keys:
# Merging one branch into another # Merging one branch into another
Scope is fast-forward and merge-commit mechanics plus conflict resolution. Rebase belongs to Scope is fast-forward and merge-commit mechanics plus conflict resolution. Rebase and cherry-pick
`git-commits`; cherry-pick and revert to `git-history`. belong to `git-commits`; revert to `git-history`.
- **Fast-forward** — `git merge <branch>` advances the pointer with no merge commit when the - **Fast-forward** — `git merge <branch>` advances the pointer with no merge commit when the
target has not diverged. target has not diverged.

View File

@@ -8,6 +8,7 @@ description: >
Not branch lifecycle -> `git-branches`. Not branch lifecycle -> `git-branches`.
metadata: metadata:
version: "0.1.3"
category: git category: git
source_keys: source_keys:
- conventional-commits-spec - conventional-commits-spec
@@ -22,6 +23,7 @@ allowed-tools: Bash
- **Run git as `rtk git <subcommand>`, never bare `git`** — org convention, in `&&` chains too. - **Run git as `rtk git <subcommand>`, never bare `git`** — org convention, in `&&` chains too.
- **Refuse to force-push `main`/`master`** — a rewrite leaves the branch diverged and the reflex is to force it back; safe only where nobody else has based work on it. - **Refuse to force-push `main`/`master`** — a rewrite leaves the branch diverged and the reflex is to force it back; safe only where nobody else has based work on it.
- **`reset --hard` is a confirmation gate, not a default.** It overwrites the working tree, and uncommitted edits it discards were never in git, so no reflog recovers them. Name what will be lost and offer a stash first.
- **Never add `--no-verify`** — using it when a hook fails bypasses the QA gate the pipeline depends on. Only on the user's explicit demand, with a warning. - **Never add `--no-verify`** — using it when a hook fails bypasses the QA gate the pipeline depends on. Only on the user's explicit demand, with a warning.
## Dispatch ## Dispatch
@@ -31,18 +33,19 @@ Read exactly one flow file. Each is self-contained.
| Condition | Flow | Read | | Condition | Flow | Read |
|---|---|---| |---|---|---|
| Composing a new commit from staged changes | create | `references/create-commit.md` | | Composing a new commit from staged changes | create | `references/create-commit.md` |
| Amending, squashing, or folding a fixup into an earlier commit | rewrite | `references/rewrite-history.md` | | Amending, squashing, folding a fixup, rebasing onto a new base, or resetting HEAD | rewrite | `references/rewrite-history.md` |
| Replaying an existing commit onto the current branch | cherry-pick | `references/cherry-pick.md` | | Replaying an existing commit onto the current branch | cherry-pick | `references/cherry-pick.md` |
## Gates on every flow ## Gates on every flow
1. **Confirmation.** No history rewrite executes without explicit approval from the user or the calling agent. Cherry-pick needs the destination branch confirmed first. 1. **Confirmation.** No history rewrite executes without explicit approval from the user or the calling agent. Cherry-pick needs the destination branch confirmed first.
2. **Secrets.** Before any commit or amend, scan the staged diff for anything resembling an API key, 2. **Atomicity.** The result must be one logical, independently reviewable and reversible change that leaves the repository buildable and testable. This binds an amend or a squashed result as much as a fresh commit — say so before writing it, not after.
3. **Secrets.** Before any commit or amend, scan the staged diff for anything resembling an API key,
token, password, connection string, or environment-specific config. Stop and flag it rather than token, password, connection string, or environment-specific config. Stop and flag it rather than
committing it. committing it.
3. **Validation.** Check the message against commitlint `config-conventional` before committing. If a type, footer, or breaking-change edge case is not obvious, read `references/conventional-commits-spec.md` — it carries the constraint table, the 11-type set, and the footer token rules. 4. **Validation.** Check the message against commitlint `config-conventional` before committing. If a type, footer, or breaking-change edge case is not obvious, read `references/conventional-commits-spec.md` — it carries the constraint table, the 11-type set, and the footer token rules.
4. **SemVer impact.** Report the bump the commit implies: `feat` → MINOR, `fix`/`perf`/`revert` → PATCH, any breaking change → MAJOR, everything else → none. Callers decide releases from this, so never omit it. 5. **SemVer impact.** Report the bump the commit implies: `feat` → MINOR, `fix`/`perf`/`revert` → PATCH, any breaking change → MAJOR, everything else → none. Callers decide releases from this, so never omit it.
5. **Conflicts.** If a rebase or cherry-pick halts, offer resolution or an abort. Do not resolve automatically without confirmation. 6. **Conflicts.** If a rebase or cherry-pick halts, offer resolution or an abort. Do not resolve automatically without confirmation.
## Output ## Output

View File

@@ -21,7 +21,9 @@ Prefer this whenever a commit is written to be folded, because git does the mark
1. `rtk git commit --fixup=<commit>` keeps the target's message; `rtk git commit --squash=<commit>` lets you edit the combined message later. Both prefix the message with `fixup!`/`squash!` and name the target commit. 1. `rtk git commit --fixup=<commit>` keeps the target's message; `rtk git commit --squash=<commit>` lets you edit the combined message later. Both prefix the message with `fixup!`/`squash!` and name the target commit.
2. Get explicit approval — the rebase still rewrites history. 2. Get explicit approval — the rebase still rewrites history.
3. Run `rtk git rebase --autosquash HEAD~N`, or `-i --autosquash` to review the plan first. Git reorders the tagged commits against their targets automatically. 3. Run `rtk git rebase -i --autosquash HEAD~N`. Git pre-fills the todo list with the tagged commits already reordered against their targets; save it unchanged to apply.
**`-i` is not optional here.** On Git 2.39.5, `rtk git rebase --autosquash HEAD~N` without `-i` prints `Successfully rebased and updated refs/heads/<branch>.` and exits 0 while leaving the `fixup!` commit in place at its original SHA — `--autosquash` is honoured only by the interactive machinery, and the false success is the trap: the fold is reported as done, and the surviving `fixup!` subject then fails the Conventional Commits `commit-msg` hook. Later Git versions taught the non-interactive rebase to honour the flag, but `-i --autosquash` is correct on every version, so always write that.
## Squash by hand (interactive rebase) ## Squash by hand (interactive rebase)
@@ -35,3 +37,40 @@ Use this when the commits were not tagged at commit time. **Interactive rebase h
## When a rebase halts on a conflict ## When a rebase halts on a conflict
Offer conflict resolution or `rtk git rebase --abort`. Do not resolve conflicts automatically without confirmation. Offer conflict resolution or `rtk git rebase --abort`. Do not resolve conflicts automatically without confirmation.
## Rebase the branch onto a new base
Replays this branch's commits on top of another branch's tip — bringing a feature branch up to
date without a merge commit.
1. Confirm nothing being replayed has been pushed anywhere someone else has based work on. A rebase
gives every replayed commit a new SHA, which breaks any clone that already has the old ones.
2. Get explicit approval — this rewrites history like every other flow on this page.
3. `rtk git fetch origin` first, so `<newbase>` is the real tip rather than a stale local copy.
4. `rtk git rebase <newbase>` — for example `rtk git rebase main`. Use
`rtk git rebase --onto <newbase> <upstream> <branch>` to replay only the commits after
`<upstream>`, which is how a branch started from the wrong base gets moved.
5. The branch has now diverged from its remote. It needs
`--force-with-lease --force-if-includes` to push, never a bare `--force`, and never on
`main`/`master` — refuse that and explain.
## Move the branch pointer back (`git reset`)
`reset` moves the current branch to another commit. The mode decides what survives:
| Mode | Branch pointer | Index | Working tree |
|---|---|---|---|
| `--soft` | moves | untouched — the changes stay staged | untouched |
| `--mixed` (default) | moves | reset — the changes become unstaged | untouched |
| `--hard` | moves | reset | **overwritten; uncommitted work is destroyed** |
- "Undo my last commit but keep the changes" is `rtk git reset --soft HEAD~1`. That is the default
answer to the request; reach for anything else only when the caller asked for it.
- `rtk git reset --mixed HEAD~1` when the staging should be redone from scratch too.
- `rtk git reset --hard <ref>` is gated like a force-push: state exactly which uncommitted changes
will be discarded, get approval for that specific reset, and offer `rtk git stash push -u` first.
The commits it drops stay reachable through `git reflog`; the uncommitted edits never entered git
at all and nothing recovers them.
Reset does not rewrite the commits it leaves behind, so no force-push is needed unless the branch
was already pushed at the newer commit.

View File

@@ -8,7 +8,7 @@ This skill handles history inspection within the git workflow suite. It queries
## Composition ## Composition
`git-branches` delegates cherry-pick and revert here (see `git-branches`'s `references/merging.md`), which is why this skill carries those two operations rather than treating them as out of scope. They are general git knowledge, not drawn from the `history-inspection.md` research corpus. Server-side commit history on a Gitea-hosted repository belongs to `gitea-branches`; this skill reads the local working copy. `git-branches` delegates revert here (see `git-branches`'s `references/merging.md`), which is why this skill carries that operation rather than treating it as out of scope; it is general git knowledge, not drawn from the `history-inspection.md` research corpus. Cherry-pick is **not** this skill's: `git-commits` owns it, and this skill's job ends at locating the SHA to hand over. Server-side commit history on a Gitea-hosted repository belongs to `gitea-branches`; this skill reads the local working copy.
## Usage ## Usage

View File

@@ -48,7 +48,7 @@ If you need the placeholder catalogue, format presets, `--diff-filter` letters,
Offer the operation and its consequence; run it only once the user has chosen. Offer the operation and its consequence; run it only once the user has chosen.
- `git cherry-pick <commit>` copies the commit's changes onto the current HEAD — for backporting a fix to another branch. - Backporting the commit to another branch is a cherry-pick, and cherry-pick is `git-commits`' — it owns the destination-branch check, the `rtk git` wrapper and the `--abort` path. Hand it the SHA; do not run `git cherry-pick` from here.
- `git revert <commit>` adds a new commit undoing it — for un-applying merged work without rewriting history. - `git revert <commit>` adds a new commit undoing it — for un-applying merged work without rewriting history.
- `git blame <file>` attributes each line to the commit that last touched it, when the question is which commit introduced one specific line. - `git blame <file>` attributes each line to the commit that last touched it, when the question is which commit introduced one specific line.

View File

@@ -7,7 +7,9 @@ source_keys:
# Fetching # Fetching
Fetch updates remote-tracking branches (`refs/remotes/<name>/*`) and never modifies a local branch, so it is always safe to run. Fetch **with no refspec** updates remote-tracking branches (`refs/remotes/<name>/*`) and leaves every local branch alone.
That safety comes from the default refspec, not from `fetch` itself. Give it an explicit one and it writes to local branches: verified on Git 2.39.5, `git fetch origin main:probe` fast-forwarded the local `probe` branch, and a `+` prefix force-updates the destination, discarding whatever commits it held. Treat any `fetch` carrying a `<src>:<dst>` refspec as a branch update, not a read.
- **One remote**: `git fetch <remote>` — all branches - **One remote**: `git fetch <remote>` — all branches
- **One branch**: `git fetch <remote> <branch>` — the result lands in `FETCH_HEAD`, not a tracking ref - **One branch**: `git fetch <remote> <branch>` — the result lands in `FETCH_HEAD`, not a tracking ref

View File

@@ -23,9 +23,11 @@ A pull that diverges with no strategy configured fails, and that failure is the
## Config precedence ## Config precedence
The installed default varies by Git version — older versions merge on divergence, newer ones `--ff-only` is not Git's default on an unset config, and never has been. Older versions silently
default to `--ff-only` — so an unset `pull.ff` means the same pull behaves differently on different merged on divergence; current ones refuse outright — verified on Git 2.39.5, a divergent pull with
machines. Set it explicitly. nothing configured prints the reconciliation hint and exits 128 with
`fatal: Need to specify how to reconcile divergent branches.` The behaviour therefore still varies
by installed version, and neither variant is the one you want. Set it explicitly.
Highest wins: Highest wins:

View File

@@ -3,7 +3,8 @@ name: git-submodules
description: > description: >
Use when managing Git submodules — the full lifecycle of a nested Use when managing Git submodules — the full lifecycle of a nested
repository inside a superproject. repository inside a superproject — including phrasings that never say the
word, such as "add a dependency repo" or "vendor this repo inside ours".
Not multiple checkouts of one repo -> `git-worktrees`. Not multiple checkouts of one repo -> `git-worktrees`.
Not the superproject's own remotes -> `git-remotes`. Not the superproject's own remotes -> `git-remotes`.

View File

@@ -70,8 +70,8 @@ rtk git submodule update --remote --merge --recursive
rtk git commit -am "chore: update submodules to latest" rtk git commit -am "chore: update submodules to latest"
``` ```
`--remote` requires `submodule.<name>.branch`; without it Git falls back to the remote's default `--remote` uses `submodule.<name>.branch` when it is set; without it Git falls back to the remote's
branch. Commit the superproject afterwards or the new pin is lost on the next `update`. default branch. Commit the superproject afterwards or the new pin is lost on the next `update`.
## Run one command across every submodule ## Run one command across every submodule

View File

@@ -22,10 +22,10 @@ source_keys:
Other source keys extracted during the git plugin research phase inform sibling skills in the git workflow suite, not this one: Other source keys extracted during the git plugin research phase inform sibling skills in the git workflow suite, not this one:
- `context7-git-htmldocs` — git:branches, git:history, git:remotes - `context7-git-htmldocs` — git-branches, git-history, git-remotes
- `git-scm-docs` — git:configuration - `git-scm-docs` — no current skill; it backed a git-configuration skill that no longer exists and survives here as provenance only
- `git-scm-worktree-docs` — git:worktrees - `git-scm-worktree-docs` — git-worktrees
- `nvie-gitflow-post`, `atlassian-gitflow-tutorial`, `gitflow-cheatsheet` — git:branches - `nvie-gitflow-post`, `atlassian-gitflow-tutorial`, `gitflow-cheatsheet` — git-branches
- `conventional-commits-spec`, `commitlint-config-conventional` — git:commits - `conventional-commits-spec`, `commitlint-config-conventional` — git-commits
- `git-scm-push-docs`, `git-scm-fetch-docs`, `git-scm-pull-docs`, `git-scm-remote-docs` — git:remotes - `git-scm-push-docs`, `git-scm-fetch-docs`, `git-scm-pull-docs`, `git-scm-remote-docs` — git-remotes
- `git-scm-bisect-docs`, `git-scm-log-docs`, `git-scm-diff-docs` — git:history - `git-scm-bisect-docs`, `git-scm-log-docs`, `git-scm-diff-docs` — git-history

View File

@@ -28,13 +28,16 @@ metadata:
## Domains ## Domains
Every request resolves to exactly one of these six. An unambiguous one should have gone straight Route to the domain that owns the operation, and in sequence when a request spans two — a rebase
to the domain skill; this skill exists for the ones that did not. that ends in a force-push is `git-commits`, then `git-remotes`. An unambiguous request should have
gone straight to the domain skill; this one exists for the ones that did not.
| The request is about | Domain | | The request is about | Domain |
|---|---| |---|---|
| Writing, amending, squashing, or cherry-picking a commit, and its message | `git-commits` | | Writing, amending, squashing, or cherry-picking a commit, and its message | `git-commits` |
| Rebasing onto a new base, or undoing a commit with `reset` | `git-commits` |
| Creating, switching, deleting, renaming, tracking, or merging a local branch | `git-branches` | | Creating, switching, deleting, renaming, tracking, or merging a local branch | `git-branches` |
| Stashing work in progress to move between branches | `git-branches` |
| When a change landed, which commit broke something, what to revert or backport | `git-history` | | When a change landed, which commit broke something, what to revert or backport | `git-history` |
| Anything touching a remote — remote config, fetch, push, pull — even unnamed | `git-remotes` | | Anything touching a remote — remote config, fetch, push, pull — even unnamed | `git-remotes` |
| A nested repository pinned inside this one by a recorded commit | `git-submodules` | | A nested repository pinned inside this one by a recorded commit | `git-submodules` |

View File

@@ -53,7 +53,7 @@ final argument of the `--track -b` form.
| `-b <branch>` | Create and check out a new branch; fails if it exists | | `-b <branch>` | Create and check out a new branch; fails if it exists |
| `-B <branch>` | Like `-b` but resets the branch if it already exists | | `-B <branch>` | Like `-b` but resets the branch if it already exists |
| `-d` / `--detach` | Detach HEAD; useful for throwaway experiments | | `-d` / `--detach` | Detach HEAD; useful for throwaway experiments |
| `--orphan` | Create empty unborn branch | | `--orphan` | Create empty unborn branch — **Git 2.42+**; earlier versions exit 129 with `error: unknown option 'orphan'`. Fallback below |
| `--no-checkout` | Suppress initial checkout (for sparse-checkout setup) | | `--no-checkout` | Suppress initial checkout (for sparse-checkout setup) |
| `--guess-remote` | Look for a matching remote-tracking branch by path basename | | `--guess-remote` | Look for a matching remote-tracking branch by path basename |
| `--lock [--reason <str>]` | Lock immediately on creation (atomic; avoids race vs. add-then-lock) | | `--lock [--reason <str>]` | Lock immediately on creation (atomic; avoids race vs. add-then-lock) |
@@ -67,7 +67,22 @@ Using `-` as `<commit-ish>` is shorthand for `@{-1}` (the branch checked out bef
```bash ```bash
git worktree add --orphan -b <branch> <path> git worktree add --orphan -b <branch> <path>
``` ```
Creates an empty branch with no commits. Creates an empty branch with no commits. **`--orphan` needs Git 2.42 or later** — it was added
upstream in 2.42, and on 2.39.5 this fails with `error: unknown option 'orphan'` and exit 129.
Check `git --version` before reaching for it.
Fallback on older Git, verified on 2.39.5 — detach first, then orphan the linked worktree in place,
which leaves the main worktree on its own branch throughout:
```bash
git worktree add -d <path> # linked worktree, detached HEAD
cd <path>
git switch --orphan <branch> # unborn branch: empty index, empty working tree
```
`git worktree list` then shows the new worktree at `0000000 [<branch>]` until its first commit.
Do not substitute `git switch --orphan` in the *main* worktree: it clears that checkout, which is
the disruption worktrees exist to avoid.
## Sparse-checkout worktree ## Sparse-checkout worktree