Skip to content

Commit bbd4f6d

Browse files
tmchowclaude
andauthored
feat(git-commit-push-pr): pre-resolve context to reduce bash calls (#488)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent afdd9d4 commit bbd4f6d

2 files changed

Lines changed: 107 additions & 92 deletions

File tree

plugins/compound-engineering/skills/git-commit-push-pr/SKILL.md

Lines changed: 68 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -37,36 +37,57 @@ Interpret the result this way:
3737

3838
---
3939

40-
## Description Update workflow
40+
## Context
4141

42-
### DU-1: Confirm intent
42+
**If you are not Claude Code**, skip to the "Context fallback" section below and run the command there to gather context.
4343

44-
Ask the user to confirm: "Update the PR description for this branch?" Use the platform's blocking question tool (`AskUserQuestion` in Claude Code, `request_user_input` in Codex, `ask_user` in Gemini). If no question tool is available, present the question and wait for the user's reply.
44+
**If you are Claude Code**, the six labeled sections below (Git status, Working tree diff, Current branch, Recent commits, Remote default branch, Existing PR check) contain pre-populated data. Use them directly throughout this skill -- do not re-run these commands.
4545

46-
If the user declines, stop.
46+
**Git status:**
47+
!`git status`
4748

48-
### DU-2: Find the PR
49+
**Working tree diff:**
50+
!`git diff HEAD`
4951

50-
Run these commands to identify the branch and locate the PR:
52+
**Current branch:**
53+
!`git branch --show-current`
5154

52-
```bash
53-
git branch --show-current
54-
```
55+
**Recent commits:**
56+
!`git log --oneline -10`
57+
58+
**Remote default branch:**
59+
!`git rev-parse --abbrev-ref origin/HEAD 2>/dev/null || echo '__DEFAULT_BRANCH_UNRESOLVED__'`
5560

56-
If empty (detached HEAD), report that there is no branch to update and stop.
61+
**Existing PR check:**
62+
!`PR_OUT=$(gh pr view --json url,title,state 2>&1); PR_EXIT=$?; printf '%s\n__GH_PR_VIEW_EXIT__=%s\n' "$PR_OUT" "$PR_EXIT"`
5763

58-
Otherwise, check for an existing open PR:
64+
### Context fallback
65+
66+
**If you are Claude Code, skip this section — the data above is already available.**
67+
68+
Run this single command to gather all context:
5969

6070
```bash
61-
if PR_VIEW_OUTPUT=$(gh pr view --json url,title,state 2>&1); then
62-
PR_VIEW_EXIT=0
63-
else
64-
PR_VIEW_EXIT=$?
65-
fi
66-
printf '%s\n__GH_PR_VIEW_EXIT__=%s\n' "$PR_VIEW_OUTPUT" "$PR_VIEW_EXIT"
71+
printf '=== STATUS ===\n'; git status; printf '\n=== DIFF ===\n'; git diff HEAD; printf '\n=== BRANCH ===\n'; git branch --show-current; printf '\n=== LOG ===\n'; git log --oneline -10; printf '\n=== DEFAULT_BRANCH ===\n'; git rev-parse --abbrev-ref origin/HEAD 2>/dev/null || echo '__DEFAULT_BRANCH_UNRESOLVED__'; printf '\n=== PR_CHECK ===\n'; PR_OUT=$(gh pr view --json url,title,state 2>&1); PR_EXIT=$?; printf '%s\n__GH_PR_VIEW_EXIT__=%s\n' "$PR_OUT" "$PR_EXIT"
6772
```
6873

69-
Interpret the result using the Reusable PR probe rules above:
74+
Interpret the PR check result using the Reusable PR probe rules above.
75+
76+
---
77+
78+
## Description Update workflow
79+
80+
### DU-1: Confirm intent
81+
82+
Ask the user to confirm: "Update the PR description for this branch?" Use the platform's blocking question tool (`AskUserQuestion` in Claude Code, `request_user_input` in Codex, `ask_user` in Gemini). If no question tool is available, present the question and wait for the user's reply.
83+
84+
If the user declines, stop.
85+
86+
### DU-2: Find the PR
87+
88+
Use the current branch and existing PR check from the context above. If the current branch is empty (detached HEAD), report that there is no branch to update and stop.
89+
90+
Interpret the PR check result using the Reusable PR probe rules above:
7091

7192
- If it returns PR data with `state: OPEN`, an open PR exists for the current branch.
7293
- If it returns PR data with a non-OPEN state (CLOSED, MERGED), treat this as "no open PR." Report that no open PR exists for this branch and stop.
@@ -102,35 +123,25 @@ Report the PR URL.
102123

103124
### Step 1: Gather context
104125

105-
Run these commands.
106-
107-
```bash
108-
git status
109-
git diff HEAD
110-
git branch --show-current
111-
git log --oneline -10
112-
git rev-parse --abbrev-ref origin/HEAD
113-
```
126+
Use the context above (git status, working tree diff, current branch, recent commits, remote default branch, and existing PR check). All data needed for this step and Step 3 is already available -- do not re-run those commands.
114127

115-
The last command returns the remote default branch (e.g., `origin/main`). Strip the `origin/` prefix to get the branch name. If the command fails or returns a bare `HEAD`, try:
128+
The remote default branch value returns something like `origin/main`. Strip the `origin/` prefix to get the branch name. If it returned `__DEFAULT_BRANCH_UNRESOLVED__` or a bare `HEAD`, try:
116129

117130
```bash
118131
gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name'
119132
```
120133

121134
If both fail, fall back to `main`.
122135

123-
Run `git branch --show-current`. If it returns an empty result, the repository is in detached HEAD state. Explain that a branch is required before committing and pushing. Ask whether to create a feature branch now. Use the platform's blocking question tool (`AskUserQuestion` in Claude Code, `request_user_input` in Codex, `ask_user` in Gemini). If no question tool is available, present the options and wait for the user's reply.
136+
If the current branch from the context above is empty, the repository is in detached HEAD state. Explain that a branch is required before committing and pushing. Ask whether to create a feature branch now. Use the platform's blocking question tool (`AskUserQuestion` in Claude Code, `request_user_input` in Codex, `ask_user` in Gemini). If no question tool is available, present the options and wait for the user's reply.
124137

125138
- If the user agrees, derive a descriptive branch name from the change content, create it with `git checkout -b <branch-name>`, then run `git branch --show-current` again and use that result as the current branch name for the rest of the workflow.
126139
- If the user declines, stop.
127140

128-
If the `git status` result from this step shows a clean working tree (no staged, modified, or untracked files), check whether there are unpushed commits or a missing PR before stopping:
141+
If the git status from the context above shows a clean working tree (no staged, modified, or untracked files), check whether there are unpushed commits or a missing PR before stopping. The current branch and existing PR check are already available from the context above. Additionally:
129142

130-
1. Run `git branch --show-current` to get the current branch name.
131-
2. Run `git rev-parse --abbrev-ref --symbolic-full-name @{u}` to check whether an upstream is configured.
132-
3. If the command succeeds, run `git log <upstream>..HEAD --oneline` using the upstream name from the previous command.
133-
4. If an upstream is configured, check for an existing PR using the method in Step 3.
143+
1. Run `git rev-parse --abbrev-ref --symbolic-full-name @{u}` to check whether an upstream is configured.
144+
2. If the command succeeds, run `git log <upstream>..HEAD --oneline` using the upstream name from the previous command.
134145

135146
- If the current branch is `main`, `master`, or the resolved default branch from Step 1 and there is **no upstream** or there are **unpushed commits**, explain that pushing now would use the default branch directly. Ask whether to create a feature branch first. Use the platform's blocking question tool (`AskUserQuestion` in Claude Code, `request_user_input` in Codex, `ask_user` in Gemini). If no question tool is available, present the options and wait for the user's reply.
136147
- If the user agrees, derive a descriptive branch name from the change content, create it with `git checkout -b <branch-name>`, then continue from Step 5 (push).
@@ -151,20 +162,9 @@ Follow this priority order for commit messages *and* PR titles:
151162

152163
### Step 3: Check for existing PR
153164

154-
Run `git branch --show-current` to get the current branch name. If it returns an empty result here, report that the workflow is still in detached HEAD state and stop.
155-
156-
Then check for an existing open PR:
157-
158-
```bash
159-
if PR_VIEW_OUTPUT=$(gh pr view --json url,title,state 2>&1); then
160-
PR_VIEW_EXIT=0
161-
else
162-
PR_VIEW_EXIT=$?
163-
fi
164-
printf '%s\n__GH_PR_VIEW_EXIT__=%s\n' "$PR_VIEW_OUTPUT" "$PR_VIEW_EXIT"
165-
```
165+
Use the current branch and existing PR check from the context above. If the current branch is empty, report that the workflow is in detached HEAD state and stop.
166166

167-
Interpret the result using the Reusable PR probe rules above:
167+
Interpret the PR check result using the Reusable PR probe rules:
168168

169169
- If it **returns PR data with `state: OPEN`**, an open PR exists for the current branch. Note the URL and continue to Step 4 (commit) and Step 5 (push). Then skip to Step 7 (existing PR flow) instead of creating a new PR.
170170
- If it **returns PR data with a non-OPEN state** (CLOSED, MERGED), treat this the same as "no PR exists" -- the previous PR is done and a new one is needed. Continue to Step 4 through Step 8 as normal.
@@ -173,10 +173,15 @@ Interpret the result using the Reusable PR probe rules above:
173173

174174
### Step 4: Branch, stage, and commit
175175

176-
1. Run `git branch --show-current`. If it returns `main`, `master`, or the resolved default branch from Step 1, create a descriptive feature branch first with `git checkout -b <branch-name>`. Derive the branch name from the change content.
176+
1. If the current branch from the context above is `main`, `master`, or the resolved default branch from Step 1, create a descriptive feature branch first with `git checkout -b <branch-name>`. Derive the branch name from the change content.
177177
2. Before staging everything together, scan the changed files for naturally distinct concerns. If modified files clearly group into separate logical changes (e.g., a refactor in one set of files and a new feature in another), create separate commits for each group. Keep this lightweight -- group at the **file level only** (no `git add -p`), split only when obvious, and aim for two or three logical commits at most. If it's ambiguous, one commit is fine.
178-
3. Stage relevant files by name. Avoid `git add -A` or `git add .` to prevent accidentally including sensitive files.
179-
4. Commit following the conventions from Step 2. Use a heredoc for the message.
178+
3. For each commit group, stage and commit in a single call. Avoid `git add -A` or `git add .` to prevent accidentally including sensitive files. Follow the conventions from Step 2. Use a heredoc for the message:
179+
```bash
180+
git add file1 file2 file3 && git commit -m "$(cat <<'EOF'
181+
commit message here
182+
EOF
183+
)"
184+
```
180185
181186
### Step 5: Push
182187
@@ -203,11 +208,7 @@ Use this fallback chain. Stop at the first that succeeds:
203208
git remote -v
204209
```
205210
Match the `owner/repo` from the PR URL against the fetch URLs. Use the matching remote as the base remote. If no remote matches, fall back to `origin`.
206-
2. **`origin/HEAD` symbolic ref:**
207-
```bash
208-
git symbolic-ref --quiet --short refs/remotes/origin/HEAD
209-
```
210-
Strip the `origin/` prefix from the result. Use `origin` as the base remote.
211+
2. **Remote default branch from context above:** If the remote default branch resolved (not `__DEFAULT_BRANCH_UNRESOLVED__`), strip the `origin/` prefix and use that. Use `origin` as the base remote.
211212
3. **GitHub default branch metadata:**
212213
```bash
213214
gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name'
@@ -223,28 +224,19 @@ If none resolve, ask the user to specify the target branch. Use the platform's b
223224
224225
#### Gather the branch scope
225226
226-
Once the base branch and remote are known:
227+
Once the base branch and remote are known, gather the full scope in as few calls as possible.
227228
228-
1. Verify the remote-tracking ref exists locally and fetch if needed:
229-
```bash
230-
git rev-parse --verify <base-remote>/<base-branch>
231-
```
232-
If this fails (ref missing or stale), fetch it:
233-
```bash
234-
git fetch --no-tags <base-remote> <base-branch>
235-
```
236-
2. Find the merge base:
237-
```bash
238-
git merge-base <base-remote>/<base-branch> HEAD
239-
```
240-
3. List all commits unique to this branch:
241-
```bash
242-
git log --oneline <merge-base>..HEAD
243-
```
244-
4. Get the full diff a reviewer will see:
245-
```bash
246-
git diff <merge-base>...HEAD
247-
```
229+
First, verify the remote-tracking ref exists and fetch if needed:
230+
231+
```bash
232+
git rev-parse --verify <base-remote>/<base-branch> 2>/dev/null || git fetch --no-tags <base-remote> <base-branch>
233+
```
234+
235+
Then gather the merge base, commit list, and full diff in a single call:
236+
237+
```bash
238+
MERGE_BASE=$(git merge-base <base-remote>/<base-branch> HEAD) && echo "MERGE_BASE=$MERGE_BASE" && echo '=== COMMITS ===' && git log --oneline $MERGE_BASE..HEAD && echo '=== DIFF ===' && git diff $MERGE_BASE...HEAD
239+
```
248240
249241
Use the full branch diff and commit list as the basis for the PR description -- not the working-tree diff from Step 1.
250242

plugins/compound-engineering/skills/git-commit/SKILL.md

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,56 @@ description: Create a git commit with a clear, value-communicating message. Use
77

88
Create a single, well-crafted git commit from the current working tree changes.
99

10-
## Workflow
10+
## Context
1111

12-
### Step 1: Gather context
12+
**If you are not Claude Code**, skip to the "Context fallback" section below and run the command there to gather context.
13+
14+
**If you are Claude Code**, the five labeled sections below (Git status, Working tree diff, Current branch, Recent commits, Remote default branch) contain pre-populated data. Use them directly throughout this skill -- do not re-run these commands.
15+
16+
**Git status:**
17+
!`git status`
18+
19+
**Working tree diff:**
20+
!`git diff HEAD`
21+
22+
**Current branch:**
23+
!`git branch --show-current`
24+
25+
**Recent commits:**
26+
!`git log --oneline -10`
27+
28+
**Remote default branch:**
29+
!`git rev-parse --abbrev-ref origin/HEAD 2>/dev/null || echo '__DEFAULT_BRANCH_UNRESOLVED__'`
30+
31+
### Context fallback
1332

14-
Run these commands to understand the current state.
33+
**If you are Claude Code, skip this section — the data above is already available.**
34+
35+
Run this single command to gather all context:
1536

1637
```bash
17-
git status
18-
git diff HEAD
19-
git branch --show-current
20-
git log --oneline -10
21-
git rev-parse --abbrev-ref origin/HEAD
38+
printf '=== STATUS ===\n'; git status; printf '\n=== DIFF ===\n'; git diff HEAD; printf '\n=== BRANCH ===\n'; git branch --show-current; printf '\n=== LOG ===\n'; git log --oneline -10; printf '\n=== DEFAULT_BRANCH ===\n'; git rev-parse --abbrev-ref origin/HEAD 2>/dev/null || echo '__DEFAULT_BRANCH_UNRESOLVED__'
2239
```
2340

24-
The last command returns the remote default branch (e.g., `origin/main`). Strip the `origin/` prefix to get the branch name. If the command fails or returns a bare `HEAD`, try:
41+
---
42+
43+
## Workflow
44+
45+
### Step 1: Gather context
46+
47+
Use the context above (git status, working tree diff, current branch, recent commits, remote default branch). All data needed for this step is already available -- do not re-run those commands.
48+
49+
The remote default branch value returns something like `origin/main`. Strip the `origin/` prefix to get the branch name. If it returned `__DEFAULT_BRANCH_UNRESOLVED__` or a bare `HEAD`, try:
2550

2651
```bash
2752
gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name'
2853
```
2954

3055
If both fail, fall back to `main`.
3156

32-
If the `git status` result from this step shows a clean working tree (no staged, modified, or untracked files), report that there is nothing to commit and stop.
57+
If the git status from the context above shows a clean working tree (no staged, modified, or untracked files), report that there is nothing to commit and stop.
3358

34-
Run `git branch --show-current`. If it returns an empty result, the repository is in detached HEAD state. Explain that a branch is required before committing if the user wants this work attached to a branch. Ask whether to create a feature branch now. Use the platform's blocking question tool (`AskUserQuestion` in Claude Code, `request_user_input` in Codex, `ask_user` in Gemini). If no question tool is available, present the options and wait for the user's reply before proceeding.
59+
If the current branch from the context above is empty, the repository is in detached HEAD state. Explain that a branch is required before committing if the user wants this work attached to a branch. Ask whether to create a feature branch now. Use the platform's blocking question tool (`AskUserQuestion` in Claude Code, `request_user_input` in Codex, `ask_user` in Gemini). If no question tool is available, present the options and wait for the user's reply before proceeding.
3560

3661
- If the user chooses to create a branch, derive the name from the change content, create it with `git checkout -b <branch-name>`, then run `git branch --show-current` again and use that result as the current branch name for the rest of the workflow.
3762
- If the user declines, continue with the detached HEAD commit.
@@ -55,18 +80,16 @@ Keep this lightweight:
5580

5681
### Step 4: Stage and commit
5782

58-
Run `git branch --show-current`. If it returns `main`, `master`, or the resolved default branch from Step 1, warn the user and ask whether to continue committing here or create a feature branch first. Use the platform's blocking question tool (`AskUserQuestion` in Claude Code, `request_user_input` in Codex, `ask_user` in Gemini). If no question tool is available, present the options and wait for the user's reply before proceeding. If the user chooses to create a branch, derive the name from the change content, create it with `git checkout -b <branch-name>`, then run `git branch --show-current` again and use that result as the current branch name for the rest of the workflow.
59-
60-
Stage the relevant files. Prefer staging specific files by name over `git add -A` or `git add .` to avoid accidentally including sensitive files (.env, credentials) or unrelated changes.
83+
If the current branch from the context above is `main`, `master`, or the resolved default branch from Step 1, warn the user and ask whether to continue committing here or create a feature branch first. Use the platform's blocking question tool (`AskUserQuestion` in Claude Code, `request_user_input` in Codex, `ask_user` in Gemini). If no question tool is available, present the options and wait for the user's reply before proceeding. If the user chooses to create a branch, derive the name from the change content, create it with `git checkout -b <branch-name>`, then continue.
6184

6285
Write the commit message:
6386
- **Subject line**: Concise, imperative mood, focused on *why* not *what*. Follow the convention determined in Step 2.
6487
- **Body** (when needed): Add a body separated by a blank line for non-trivial changes. Explain motivation, trade-offs, or anything a future reader would need. Omit the body for obvious single-purpose changes.
6588

66-
Use a heredoc to preserve formatting:
89+
For each commit group, stage and commit in a single call. Prefer staging specific files by name over `git add -A` or `git add .` to avoid accidentally including sensitive files (.env, credentials) or unrelated changes. Use a heredoc to preserve formatting:
6790

6891
```bash
69-
git commit -m "$(cat <<'EOF'
92+
git add file1 file2 file3 && git commit -m "$(cat <<'EOF'
7093
type(scope): subject line here
7194
7295
Optional body explaining why this change was made,

0 commit comments

Comments
 (0)