ace-git 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/.ace-defaults/git/config.yml +83 -0
  3. data/.ace-defaults/nav/protocols/guide-sources/ace-git.yml +10 -0
  4. data/.ace-defaults/nav/protocols/tmpl-sources/ace-git.yml +19 -0
  5. data/.ace-defaults/nav/protocols/wfi-sources/ace-git.yml +19 -0
  6. data/CHANGELOG.md +762 -0
  7. data/LICENSE +21 -0
  8. data/README.md +48 -0
  9. data/Rakefile +14 -0
  10. data/docs/demo/ace-git-getting-started.gif +0 -0
  11. data/docs/demo/ace-git-getting-started.tape.yml +18 -0
  12. data/docs/demo/fixtures/README.md +3 -0
  13. data/docs/demo/fixtures/sample.txt +1 -0
  14. data/docs/getting-started.md +87 -0
  15. data/docs/handbook.md +50 -0
  16. data/docs/usage.md +259 -0
  17. data/exe/ace-git +37 -0
  18. data/handbook/guides/version-control/ruby.md +41 -0
  19. data/handbook/guides/version-control/rust.md +49 -0
  20. data/handbook/guides/version-control/typescript.md +47 -0
  21. data/handbook/guides/version-control-system-git.g.md +829 -0
  22. data/handbook/skills/as-git-rebase/SKILL.md +43 -0
  23. data/handbook/skills/as-git-reorganize-commits/SKILL.md +41 -0
  24. data/handbook/skills/as-github-pr-create/SKILL.md +60 -0
  25. data/handbook/skills/as-github-pr-update/SKILL.md +41 -0
  26. data/handbook/skills/as-github-release-publish/SKILL.md +58 -0
  27. data/handbook/templates/commit/squash.template.md +59 -0
  28. data/handbook/templates/pr/bugfix.template.md +103 -0
  29. data/handbook/templates/pr/default.template.md +40 -0
  30. data/handbook/templates/pr/feature.template.md +41 -0
  31. data/handbook/workflow-instructions/git/rebase.wf.md +402 -0
  32. data/handbook/workflow-instructions/git/reorganize-commits.wf.md +158 -0
  33. data/handbook/workflow-instructions/github/pr/create.wf.md +282 -0
  34. data/handbook/workflow-instructions/github/pr/update.wf.md +199 -0
  35. data/handbook/workflow-instructions/github/release-publish.wf.md +162 -0
  36. data/lib/ace/git/atoms/command_executor.rb +253 -0
  37. data/lib/ace/git/atoms/date_resolver.rb +129 -0
  38. data/lib/ace/git/atoms/diff_numstat_parser.rb +82 -0
  39. data/lib/ace/git/atoms/diff_parser.rb +110 -0
  40. data/lib/ace/git/atoms/file_grouper.rb +152 -0
  41. data/lib/ace/git/atoms/git_scope_filter.rb +86 -0
  42. data/lib/ace/git/atoms/git_status_fetcher.rb +29 -0
  43. data/lib/ace/git/atoms/grouped_stats_formatter.rb +233 -0
  44. data/lib/ace/git/atoms/lock_error_detector.rb +79 -0
  45. data/lib/ace/git/atoms/pattern_filter.rb +156 -0
  46. data/lib/ace/git/atoms/pr_identifier_parser.rb +88 -0
  47. data/lib/ace/git/atoms/repository_checker.rb +97 -0
  48. data/lib/ace/git/atoms/repository_state_detector.rb +92 -0
  49. data/lib/ace/git/atoms/stale_lock_cleaner.rb +247 -0
  50. data/lib/ace/git/atoms/status_formatter.rb +180 -0
  51. data/lib/ace/git/atoms/task_pattern_extractor.rb +57 -0
  52. data/lib/ace/git/atoms/time_formatter.rb +84 -0
  53. data/lib/ace/git/cli/commands/branch.rb +62 -0
  54. data/lib/ace/git/cli/commands/diff.rb +252 -0
  55. data/lib/ace/git/cli/commands/pr.rb +119 -0
  56. data/lib/ace/git/cli/commands/status.rb +84 -0
  57. data/lib/ace/git/cli.rb +87 -0
  58. data/lib/ace/git/models/diff_config.rb +185 -0
  59. data/lib/ace/git/models/diff_result.rb +94 -0
  60. data/lib/ace/git/models/repo_status.rb +202 -0
  61. data/lib/ace/git/molecules/branch_reader.rb +92 -0
  62. data/lib/ace/git/molecules/config_loader.rb +108 -0
  63. data/lib/ace/git/molecules/diff_filter.rb +102 -0
  64. data/lib/ace/git/molecules/diff_generator.rb +160 -0
  65. data/lib/ace/git/molecules/git_status_fetcher.rb +32 -0
  66. data/lib/ace/git/molecules/pr_metadata_fetcher.rb +286 -0
  67. data/lib/ace/git/molecules/recent_commits_fetcher.rb +53 -0
  68. data/lib/ace/git/organisms/diff_orchestrator.rb +178 -0
  69. data/lib/ace/git/organisms/repo_status_loader.rb +264 -0
  70. data/lib/ace/git/version.rb +7 -0
  71. data/lib/ace/git.rb +230 -0
  72. metadata +201 -0
@@ -0,0 +1,402 @@
1
+ ---
2
+ doc-type: workflow
3
+ title: Rebase Workflow
4
+ purpose: Safe rebase workflow with state capture, explicit conflict triage, and verification
5
+ ace-docs:
6
+ last-updated: 2026-03-12
7
+ last-checked: 2026-03-21
8
+ ---
9
+
10
+ # Rebase Workflow
11
+
12
+ ## Purpose
13
+
14
+ Rebase feature branches against a target branch with automatic state capture for recovery and verification. The workflow attempts simple rebase first, keeps localized conflicts on the normal rebase path, and escalates to cherry-pick only when per-commit replay is the safer tool.
15
+
16
+ ## Requirements
17
+
18
+ - **Bash 4+**: Required for array syntax (macOS: install via Homebrew)
19
+ - **ace-b36ts**: For generating compact session IDs
20
+
21
+ ## Strategies
22
+
23
+ | Strategy | Trigger | Description |
24
+ |----------|---------|-------------|
25
+ | **simple** (DEFAULT) | No conflicts | Standard `git rebase` - preserves exact commit history |
26
+ | **continue-first** | Small or localized conflict set | Resolve the conflict and continue the existing rebase |
27
+ | **cherry-pick** (ESCALATION) | Repeated conflicts, large conflict set, or explicit request | Per-commit replay from cached commit list |
28
+
29
+ > For interactive history editing, see [Appendix: Alternative Strategies](#appendix-alternative-strategies).
30
+
31
+ ## Variables & Helpers
32
+
33
+ ```bash
34
+ # Variables
35
+ # $target_branch: Branch to rebase against (default: auto-detect or origin/main)
36
+ # $no_verify: Skip post-rebase verification (default: false)
37
+
38
+ # Helper: Auto-detect target branch from task spec or default to origin/main
39
+ get_target_branch() {
40
+ local task_file
41
+ task_file=$(ls _current/*.s.md 2>/dev/null | head -1)
42
+ if [ -n "$task_file" ] && [ -f "$task_file" ] && [ -r "$task_file" ]; then
43
+ ruby -ryaml -e '
44
+ c = File.read(ARGV[0])
45
+ if c.start_with?("---")
46
+ yaml_content = c.split("---", 3)[1]
47
+ if yaml_content
48
+ data = YAML.safe_load(yaml_content, permitted_classes: [Symbol])
49
+ puts data.dig("worktree", "target_branch") || "origin/main"
50
+ else
51
+ puts "origin/main"
52
+ end
53
+ else
54
+ puts "origin/main"
55
+ end
56
+ ' "$task_file" 2>/dev/null || echo "origin/main"
57
+ else
58
+ echo "origin/main"
59
+ fi
60
+ }
61
+
62
+ # Helper: Recover session variables (for multi-shell workflows)
63
+ recover_session() {
64
+ if [ -n "$cache_dir" ]; then return; fi
65
+ sessions=($(ls -td .ace-local/git/*-rebase 2>/dev/null))
66
+ if [ ${#sessions[@]} -eq 0 ]; then
67
+ echo "ERROR: No rebase sessions found"; exit 1
68
+ elif [ ${#sessions[@]} -eq 1 ]; then
69
+ cache_dir="${sessions[0]}"
70
+ else
71
+ echo "Multiple sessions found:"
72
+ for i in "${!sessions[@]}"; do
73
+ echo " [$i] $(basename ${sessions[$i]} | sed 's/-rebase$//')"
74
+ done
75
+ read -p "Select (Enter for most recent): " choice
76
+ if [ -z "$choice" ]; then
77
+ cache_dir="${sessions[0]}"
78
+ elif echo "$choice" | grep -qE '^[0-9]+$' && [ "$choice" -lt ${#sessions[@]} ]; then
79
+ cache_dir="${sessions[$choice]}"
80
+ else
81
+ echo "ERROR: Invalid selection"; exit 1
82
+ fi
83
+ fi
84
+ session_id=$(basename "$cache_dir" | sed 's/-rebase$//')
85
+ target_branch=$(grep "target_branch:" "$cache_dir/metadata.yml" | cut -d' ' -f2)
86
+ export cache_dir session_id target_branch
87
+ echo "Recovered session: $session_id"
88
+ }
89
+ ```
90
+
91
+ **Session Continuity:** If continuing in a new shell, call `recover_session` before any phase. Variables `cache_dir`, `session_id`, and `target_branch` are exported for subprocess visibility.
92
+
93
+ **Conflict Policy:** The first conflict stays on the normal rebase path unless the conflict set is clearly large or the operator explicitly wants per-commit replay. Cherry-pick fallback is the escalation path, not the default response to every conflict.
94
+
95
+ ---
96
+
97
+ ## Phase 1: State Capture
98
+
99
+ ### 1.1 Initialize Session
100
+
101
+ ```bash
102
+ # Set target branch
103
+ target_branch="${target_branch:-$(get_target_branch)}"
104
+
105
+ # Generate session ID and cache directory
106
+ session_id=$(ace-b36ts encode now)
107
+ cache_dir=".ace-local/git/${session_id}-rebase"
108
+ mkdir -p "$cache_dir"
109
+ export cache_dir session_id target_branch
110
+
111
+ echo "Session: $session_id | Target: $target_branch | Cache: $cache_dir"
112
+ ```
113
+
114
+ ### 1.2 Capture Pre-Rebase State
115
+
116
+ ```bash
117
+ git fetch origin
118
+ merge_base=$(git merge-base HEAD "$target_branch")
119
+
120
+ # Metadata
121
+ cat > "$cache_dir/metadata.yml" << EOF
122
+ session_id: $session_id
123
+ target_branch: $target_branch
124
+ source_branch: $(git branch --show-current)
125
+ source_head: $(git rev-parse HEAD)
126
+ merge_base: $merge_base
127
+ started_at: $(date -u +"%Y-%m-%dT%H:%M:%SZ")
128
+ EOF
129
+
130
+ # Commit list (oldest first for cherry-pick replay)
131
+ git log --reverse --oneline "$merge_base"..HEAD > "$cache_dir/commits.txt"
132
+ : > "$cache_dir/applied-shas.txt"
133
+
134
+ # Diffs for recovery and verification
135
+ git diff "$merge_base"..HEAD > "$cache_dir/pre-rebase.diff"
136
+ git diff --stat "$merge_base"..HEAD > "$cache_dir/pre-rebase.stats"
137
+ ```
138
+
139
+ ### 1.3 Validate State
140
+
141
+ ```bash
142
+ # Check working directory is clean
143
+ if ! git diff --quiet || ! git diff --cached --quiet; then
144
+ echo "ERROR: Working directory not clean. Commit or stash changes first."
145
+ exit 1
146
+ fi
147
+
148
+ # Warn about untracked files
149
+ untracked=$(git status --porcelain=v1 | grep '^[??]' | wc -l | tr -d ' ')
150
+ if [ "$untracked" -gt 0 ]; then
151
+ echo "WARNING: $untracked untracked file(s) may be deleted during rebase cleanup."
152
+ git status --porcelain=v1 | grep '^[??]'
153
+ read -p "Press Enter to continue (or Ctrl+C to abort): "
154
+ fi
155
+
156
+ # Check commits exist
157
+ commit_count=$(wc -l < "$cache_dir/commits.txt" | tr -d ' ')
158
+ if [ "$commit_count" -eq 0 ]; then
159
+ echo "Already up to date with $target_branch"; exit 0
160
+ fi
161
+
162
+ echo "Commits to rebase: $commit_count"
163
+ cat "$cache_dir/commits.txt"
164
+ ```
165
+
166
+ ---
167
+
168
+ ## Phase 2: Simple Rebase
169
+
170
+ ### 2.1 Attempt Rebase
171
+
172
+ ```bash
173
+ echo "Attempting simple rebase onto $target_branch..."
174
+ git rebase "$target_branch"
175
+ ```
176
+
177
+ ### 2.2 Triage First Conflict
178
+
179
+ ```bash
180
+ # If conflicts detected, inspect them before changing strategies
181
+ if [ -d ".git/rebase-merge" ] || [ -d ".git/rebase-apply" ]; then
182
+ conflicted_files=($(git diff --name-only --diff-filter=U))
183
+ conflict_count=${#conflicted_files[@]}
184
+ current_commit=$(git rev-parse --short REBASE_HEAD 2>/dev/null || echo "unknown")
185
+
186
+ echo "Conflict detected in rebase commit: $current_commit"
187
+ printf ' %s\n' "${conflicted_files[@]}"
188
+
189
+ if [ "$conflict_count" -le 2 ]; then
190
+ echo "Strategy: continue-first"
191
+ echo "Resolve conflicts, then run: git add <files> && git rebase --continue"
192
+ echo "Escalate only if the next rebase stop is also conflicted or resolution coordination becomes complex."
193
+ echo "CHANGELOG.md note: prefer git checkout --theirs CHANGELOG.md, then re-apply your entries on top before git add."
194
+ else
195
+ echo "Strategy: cherry-pick fallback (conflict set is large)"
196
+ echo "Abort the rebase and proceed to Phase 3."
197
+ fi
198
+ else
199
+ echo "Simple rebase complete - proceed to Phase 4"
200
+ fi
201
+ ```
202
+
203
+ ### 2.3 Escalate to Cherry-Pick Only When Needed
204
+
205
+ ```bash
206
+ # Use this only after triage says the conflict set is large, repeated, or explicitly requires per-commit replay
207
+ git rebase --abort || rm -rf .git/rebase-merge .git/rebase-apply
208
+ git reset --hard HEAD
209
+ echo "WARNING: About to delete untracked files."
210
+ read -p "Press Enter to continue with git clean -fd (or Ctrl+C): "
211
+ git clean -fd
212
+ # Proceed to Phase 3
213
+ ```
214
+
215
+ ---
216
+
217
+ ## Phase 3: Cherry-Pick Fallback
218
+
219
+ Use this path only after the first-conflict triage says normal rebase is no longer the right tool.
220
+
221
+ ### 3.1 Setup Work Branch
222
+
223
+ ```bash
224
+ recover_session # Ensure session variables are set
225
+
226
+ original_branch=$(git branch --show-current)
227
+ git branch -m "$original_branch" "${original_branch}-backup-${session_id}"
228
+ git checkout --no-track -B "${original_branch}-rebase-${session_id}" "$target_branch"
229
+ ```
230
+
231
+ ### 3.2 Apply Commits
232
+
233
+ ```bash
234
+ while IFS=' ' read -r sha msg; do
235
+ # Skip commits already recorded in this replay session
236
+ if grep -qxF "$sha" "$cache_dir/applied-shas.txt"; then
237
+ echo "Skipping (already applied): $sha"
238
+ continue
239
+ fi
240
+
241
+ echo "Applying: $sha $msg"
242
+ if ! git cherry-pick "$sha"; then
243
+ echo ""
244
+ echo "CONFLICT in: $sha - $msg"
245
+ echo ""
246
+ echo "To resolve:"
247
+ echo " 1. Fix conflicts, then: git add <files> && git cherry-pick --continue"
248
+ echo " 2. Record the replayed SHA after continue: echo $sha >> $cache_dir/applied-shas.txt"
249
+ echo " 3. Re-run Phase 3.2 (already-applied SHAs will be skipped)"
250
+ echo ""
251
+ echo "To skip: git cherry-pick --skip"
252
+ echo "To abort: git cherry-pick --abort && git checkout ${original_branch}-backup-${session_id}"
253
+ exit 1
254
+ fi
255
+
256
+ echo "$sha" >> "$cache_dir/applied-shas.txt"
257
+ done < "$cache_dir/commits.txt"
258
+ ```
259
+
260
+ ### 3.3 Finalize
261
+
262
+ ```bash
263
+ git branch -m "${original_branch}-rebase-${session_id}" "$original_branch"
264
+ # Restore tracking — git branch -m drops upstream config
265
+ git branch --set-upstream-to="origin/${original_branch}" "$original_branch"
266
+ echo "Cherry-pick complete. Backup at: ${original_branch}-backup-${session_id}"
267
+ ```
268
+
269
+ ---
270
+
271
+ ## Phase 4: Verification
272
+
273
+ ### 4.1 Generate Post-Rebase Stats
274
+
275
+ ```bash
276
+ recover_session # Ensure session variables are set
277
+
278
+ if [ "$no_verify" = "true" ]; then
279
+ echo "Verification skipped (--no-verify)"
280
+ else
281
+ new_merge_base=$(git merge-base HEAD "$target_branch")
282
+ git diff --stat "$new_merge_base"..HEAD > "$cache_dir/post-rebase.stats"
283
+ ```
284
+
285
+ ### 4.2 Compare & Report
286
+
287
+ ```bash
288
+ echo "=== Verification Report ==="
289
+ echo "Pre: $(tail -1 "$cache_dir/pre-rebase.stats")"
290
+ echo "Post: $(tail -1 "$cache_dir/post-rebase.stats")"
291
+
292
+ # Compare commit counts (primary check)
293
+ pre_commits=$(wc -l < "$cache_dir/commits.txt" | tr -d ' ')
294
+ post_commits=$(git log --oneline "$new_merge_base"..HEAD | wc -l | tr -d ' ')
295
+
296
+ if [ "$pre_commits" = "$post_commits" ]; then
297
+ echo "Commits: MATCH ($pre_commits)"
298
+ else
299
+ echo "Commits: MISMATCH (pre: $pre_commits, post: $post_commits)"
300
+ fi
301
+
302
+ # Compare file counts (secondary check)
303
+ pre_files=$(grep -cE "^diff --git" "$cache_dir/pre-rebase.diff" 2>/dev/null || echo 0)
304
+ post_files=$(git diff --name-only "$new_merge_base"..HEAD | wc -l | tr -d ' ')
305
+ echo "Files: pre=$pre_files, post=$post_files"
306
+ fi
307
+ ```
308
+
309
+ ---
310
+
311
+ ## Phase 5: Push Changes
312
+
313
+ ```bash
314
+ # Run tests before pushing
315
+ if ! ace-test; then
316
+ echo "ERROR: Tests failed. Fix before pushing."
317
+ exit 1
318
+ fi
319
+
320
+ # Force push and set upstream tracking (-u ensures branch tracks remote after rename)
321
+ git push --force-with-lease -u origin "$(git branch --show-current)"
322
+ ```
323
+
324
+ ---
325
+
326
+ ## Recovery
327
+
328
+ ### Using Cached Data
329
+
330
+ ```bash
331
+ # Find session
332
+ ls -td .ace-local/git/*-rebase/ | head -5
333
+
334
+ # Set variables
335
+ cache_dir=$(ls -td .ace-local/git/*-rebase 2>/dev/null | head -1)
336
+ cat "$cache_dir/metadata.yml"
337
+
338
+ # Reset to original HEAD
339
+ original_head=$(grep "source_head:" "$cache_dir/metadata.yml" | cut -d' ' -f2)
340
+ git reset --hard "$original_head"
341
+ ```
342
+
343
+ ### Cache Cleanup
344
+
345
+ ```bash
346
+ # Remove specific session
347
+ rm -rf "$cache_dir"
348
+
349
+ # Clean sessions older than 7 days
350
+ find .ace-local/git -name "*-rebase" -type d -mtime +7 -exec rm -rf {} +
351
+ ```
352
+
353
+ ---
354
+
355
+ ## Edge Cases
356
+
357
+ | Case | Detection | Handling |
358
+ |------|-----------|----------|
359
+ | Already up to date | `commit_count -eq 0` | Exit cleanly in Phase 1.3 |
360
+ | Single commit | `commit_count -eq 1` | Simple rebase (no cherry-pick benefit) |
361
+ | Rebase in progress | `.git/rebase-merge` exists | Prompt: `--continue` or `--abort` |
362
+
363
+ ---
364
+
365
+ ## Appendix: Alternative Strategies
366
+
367
+ ### Manual Conflict Resolution
368
+
369
+ ```bash
370
+ git rebase "$target_branch"
371
+ # On conflict: resolve files, git add, git rebase --continue
372
+ # Escalate to Phase 3 only if conflicts keep repeating or require per-commit replay
373
+ # CHANGELOG: git checkout --theirs CHANGELOG.md, add your entries on top
374
+ ```
375
+
376
+ ### Interactive Rebase
377
+
378
+ ```bash
379
+ git rebase -i "$target_branch"
380
+ # pick/squash/reword/edit/drop commits in editor
381
+ # git rebase --continue after each stop
382
+ ```
383
+
384
+ ---
385
+
386
+ ## Success Criteria
387
+
388
+ - State captured to `.ace-local/git/{id}-rebase/`
389
+ - Branch rebased on target (simple, continue-first, or cherry-pick)
390
+ - Stats verified (or --no-verify)
391
+ - Tests pass
392
+ - Pushed with --force-with-lease
393
+
394
+ ## Response Template
395
+
396
+ ```
397
+ Session: {id} | Strategy: simple|continue-first|cherry-pick
398
+ Target: {branch} | Commits: {count}
399
+ Verification: {MATCH|MISMATCH} | Tests: {Pass|Fail}
400
+ Reason: {no-conflicts|localized-conflict|repeated-conflicts|large-conflict-set|user-request}
401
+ Status: {Complete|Needs attention}
402
+ ```
@@ -0,0 +1,158 @@
1
+ ---
2
+ doc-type: workflow
3
+ title: Reorganize Commits Workflow
4
+ purpose: simplified commit reorganization workflow
5
+ ace-docs:
6
+ last-updated: 2026-02-22
7
+ last-checked: 2026-03-21
8
+ ---
9
+
10
+ # Reorganize Commits Workflow
11
+
12
+ Reorganize multiple commits into clean, logical commits.
13
+
14
+ ## Key Principle
15
+
16
+ **Reorganize = Reorder, NOT Squash**
17
+
18
+ The goal is to reorder commits into logical groups while preserving per-scope granularity.
19
+ `ace-git-commit` creates one commit per configuration scope by design - this is expected behavior, not a problem to fix.
20
+
21
+ | Term | Meaning |
22
+ |------|---------|
23
+ | Reorganize | Reorder commits into logical groups |
24
+ | Squash | Combine multiple commits into one (NOT the goal here) |
25
+
26
+ ## Scope Determination
27
+
28
+ **If user provides explicit scope** (commit list, range, or PR reference):
29
+ - Use the user-provided scope directly
30
+ - Trust the user's intent - they know what they want to reorganize
31
+ - Do NOT second-guess with embedded status
32
+
33
+ **If no explicit scope provided**:
34
+ - Use embedded repository status as the default
35
+ - "ahead N" means N unpushed commits (reasonable default)
36
+ - If user seems to expect more commits, ASK before proceeding
37
+
38
+ **Mismatch Warning**: If embedded status shows fewer commits than user seems to expect (e.g., user provides a commit list longer than "ahead N"), STOP and clarify:
39
+ - Did user want to reorganize all PR commits (use merge-base)?
40
+ - Or just the unpushed ones (use embedded status)?
41
+
42
+ ---
43
+
44
+ ## Steps
45
+
46
+ ### 1. Identify Base
47
+
48
+ Determine base commit using **Scope Determination** above.
49
+
50
+ **Common patterns**:
51
+
52
+ ```bash
53
+ # From user-provided commit range (user said "reorganize abc123..HEAD")
54
+ base=abc123
55
+
56
+ # From merge-base for full PR (user wants all PR commits)
57
+ base=$(git merge-base HEAD origin/main)
58
+
59
+ # From embedded status (default: unpushed commits only)
60
+ # If status shows "ahead 5", use HEAD~5
61
+ base=HEAD~5
62
+ ```
63
+
64
+ > ⚠️ **When in doubt**: If user provides explicit commits or range, use that. Otherwise use embedded status but verify it matches user's expectations.
65
+
66
+ ### 2. Identify Commit Intentions
67
+
68
+ Read all commit messages (only the messages) to understand what changes will be reorganized:
69
+
70
+ ```bash
71
+ git log $base..HEAD --format="%s"
72
+ ```
73
+
74
+ Based on the commit messages, define the logical intention(s) that will be used in step 4. This helps `ace-git-commit` group changes correctly.
75
+
76
+
77
+ ### 3. Reset
78
+
79
+ ```bash
80
+ git reset --soft $base
81
+ ```
82
+
83
+ ### 4. Create Logical Commits
84
+
85
+ ```bash
86
+ ace-git-commit -i "brief intention"
87
+ ```
88
+
89
+ **IMPORTANT:** Do NOT specify file paths. Let the tool group by scope automatically.
90
+
91
+ `ace-git-commit` handles grouping and messages automatically.
92
+
93
+ **Expected Output**: Multiple commits, one per scope:
94
+ ```
95
+ [1/5] Committing ace-foo changes...
96
+ abc1234 feat(ace-foo): Implement feature X
97
+ [2/5] Committing ace-bar changes...
98
+ def5678 test(ace-bar): Update tests for feature X
99
+ ...
100
+ ```
101
+
102
+ This is correct behavior - do NOT try to combine these into fewer commits.
103
+
104
+ ---
105
+
106
+ ## Recovery
107
+
108
+ ```bash
109
+ git reflog
110
+ git reset --hard HEAD@{n}
111
+ ```
112
+
113
+ ---
114
+
115
+ ## Manual Override (almost never needed)
116
+
117
+ **Before using manual override, verify**:
118
+ - Did you try adjusting the intention? (usually fixes grouping issues)
119
+ - Are you trying to squash commits? (that's not the goal - stop)
120
+ - Is the auto-grouping actually wrong, or just different from expectation?
121
+
122
+ Only use if `ace-git-commit` groups files incorrectly AND adjusting the intention doesn't help:
123
+
124
+ ```bash
125
+ git reset --soft $base && git reset HEAD
126
+ ace-git-commit <paths> -i "group 1"
127
+ ace-git-commit <paths> -i "group 2"
128
+ ```
129
+
130
+ ---
131
+
132
+ ## Examples
133
+
134
+ ### User Provides Explicit Scope
135
+
136
+ ```
137
+ User: "Reorganize these commits: abc, def, ghi, jkl..."
138
+ → Use merge-base to include all listed commits
139
+ → Do NOT use "ahead 5" from embedded status
140
+ ```
141
+
142
+ ### No Explicit Scope (Use Default)
143
+
144
+ ```
145
+ User: "Reorganize commits"
146
+ Embedded status: "ahead 5"
147
+ → Use HEAD~5 (unpushed commits)
148
+ → If user expected more, they would have specified
149
+ ```
150
+
151
+ ### Mismatch - ASK Before Proceeding
152
+
153
+ ```
154
+ User: "Here are the 12 commits to reorganize: ..."
155
+ Embedded status: "ahead 5"
156
+ → User provided 12, status shows 5
157
+ → ASK: "Do you want all 12 commits (from main) or just the 5 unpushed?"
158
+ ```