forge-workflow 1.3.0 → 1.4.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.
- package/.claude/commands/check.md +8 -0
- package/.claude/commands/dev.md +8 -0
- package/.claude/commands/plan.md +8 -0
- package/.claude/commands/rollback.md +724 -0
- package/.claude/settings.json +7 -0
- package/.claude/settings.local.json +11 -1
- package/.mcp.json.example +12 -0
- package/AGENTS.md +87 -9
- package/CLAUDE.md +108 -0
- package/bin/forge.js +885 -2
- package/docs/TOOLCHAIN.md +92 -3
- package/docs/WORKFLOW.md +23 -0
- package/package.json +4 -2
|
@@ -0,0 +1,724 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Safely rollback changes with USER section preservation
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Comprehensive rollback system with multiple methods and automatic USER content preservation.
|
|
6
|
+
|
|
7
|
+
# Rollback
|
|
8
|
+
|
|
9
|
+
This command provides safe rollback operations with comprehensive validation and USER section preservation.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx forge rollback
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Interactive menu with 6 options:
|
|
18
|
+
1. **Rollback last commit** - Quick undo of most recent change
|
|
19
|
+
2. **Rollback specific commit** - Target any commit by hash
|
|
20
|
+
3. **Rollback merged PR** - Revert an entire PR merge
|
|
21
|
+
4. **Rollback specific files** - Restore only certain files
|
|
22
|
+
5. **Rollback entire branch** - Revert multiple commits
|
|
23
|
+
6. **Preview rollback** - Dry run mode (shows changes without executing)
|
|
24
|
+
|
|
25
|
+
## How It Works
|
|
26
|
+
|
|
27
|
+
### Safety Features
|
|
28
|
+
|
|
29
|
+
**1. Working Directory Check**
|
|
30
|
+
- Requires clean working directory (no uncommitted changes)
|
|
31
|
+
- Prevents accidental data loss
|
|
32
|
+
- Prompts to commit or stash changes first
|
|
33
|
+
|
|
34
|
+
**2. Input Validation**
|
|
35
|
+
- Commit hashes: Must match `/^[0-9a-f]{4,40}$/i` or be 'HEAD'
|
|
36
|
+
- File paths: Validated to be within project (prevents path traversal)
|
|
37
|
+
- Methods: Whitelisted to 'commit', 'pr', 'partial', 'branch'
|
|
38
|
+
- Shell metacharacters: Rejected (`;`, `|`, `&`, `$`, `` ` ``, `(`, `)`, `<`, `>`, `\n`, `\r`)
|
|
39
|
+
|
|
40
|
+
**3. USER Section Preservation**
|
|
41
|
+
- Automatically extracts USER sections before rollback
|
|
42
|
+
- Restores USER sections after rollback
|
|
43
|
+
- Preserves custom commands in `.claude/commands/custom/`
|
|
44
|
+
- Amends rollback commit to include restored content
|
|
45
|
+
|
|
46
|
+
**4. Dry Run Mode**
|
|
47
|
+
- Preview affected files without executing
|
|
48
|
+
- Shows what would change
|
|
49
|
+
- No git operations performed
|
|
50
|
+
|
|
51
|
+
**5. Non-Destructive**
|
|
52
|
+
- Uses `git revert` (creates new commit)
|
|
53
|
+
- Never uses `git reset --hard` (destructive)
|
|
54
|
+
- Preserves full git history
|
|
55
|
+
- Can be undone with another rollback
|
|
56
|
+
|
|
57
|
+
### USER Section Preservation
|
|
58
|
+
|
|
59
|
+
**What Gets Preserved**:
|
|
60
|
+
```markdown
|
|
61
|
+
<!-- USER:START -->
|
|
62
|
+
Your custom content here
|
|
63
|
+
<!-- USER:END -->
|
|
64
|
+
|
|
65
|
+
<!-- USER:START:custom-name -->
|
|
66
|
+
Named USER section
|
|
67
|
+
<!-- USER:END:custom-name -->
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Process**:
|
|
71
|
+
1. Extract all USER sections from AGENTS.md, CLAUDE.md, etc.
|
|
72
|
+
2. Backup custom commands from `.claude/commands/custom/`
|
|
73
|
+
3. Execute rollback operation
|
|
74
|
+
4. Restore USER sections to current file content
|
|
75
|
+
5. Restore custom command files
|
|
76
|
+
6. Amend rollback commit to include restored content
|
|
77
|
+
|
|
78
|
+
**Result**: Your customizations survive rollback operations.
|
|
79
|
+
|
|
80
|
+
## Rollback Methods
|
|
81
|
+
|
|
82
|
+
### 1. Rollback Last Commit
|
|
83
|
+
|
|
84
|
+
**Use when**: Quick undo of most recent change
|
|
85
|
+
|
|
86
|
+
**How it works**:
|
|
87
|
+
```bash
|
|
88
|
+
git revert HEAD --no-edit
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Example**:
|
|
92
|
+
```bash
|
|
93
|
+
npx forge rollback
|
|
94
|
+
# Select: 1. Rollback last commit
|
|
95
|
+
|
|
96
|
+
✓ Working directory is clean
|
|
97
|
+
✓ Extracting USER sections...
|
|
98
|
+
✓ Executing: git revert HEAD --no-edit
|
|
99
|
+
✓ Restoring USER sections...
|
|
100
|
+
✓ Amended commit to preserve USER content
|
|
101
|
+
|
|
102
|
+
Rollback complete!
|
|
103
|
+
Commit: a1b2c3d "Revert: add authentication feature"
|
|
104
|
+
Files affected: 5
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 2. Rollback Specific Commit
|
|
108
|
+
|
|
109
|
+
**Use when**: Need to revert a commit from earlier in history
|
|
110
|
+
|
|
111
|
+
**How it works**:
|
|
112
|
+
```bash
|
|
113
|
+
git revert <commit-hash> --no-edit
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Example**:
|
|
117
|
+
```bash
|
|
118
|
+
npx forge rollback
|
|
119
|
+
# Select: 2. Rollback specific commit
|
|
120
|
+
# Enter: a1b2c3d
|
|
121
|
+
|
|
122
|
+
✓ Validating commit hash...
|
|
123
|
+
✓ Working directory is clean
|
|
124
|
+
✓ Extracting USER sections...
|
|
125
|
+
✓ Executing: git revert a1b2c3d --no-edit
|
|
126
|
+
✓ Restoring USER sections...
|
|
127
|
+
✓ Amended commit to preserve USER content
|
|
128
|
+
|
|
129
|
+
Rollback complete!
|
|
130
|
+
Commit: x9y8z7w "Revert: a1b2c3d"
|
|
131
|
+
Files affected: 8
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Input validation**:
|
|
135
|
+
- Accepts 4-40 character hex strings
|
|
136
|
+
- Accepts 'HEAD'
|
|
137
|
+
- Rejects shell metacharacters
|
|
138
|
+
- Rejects invalid formats
|
|
139
|
+
|
|
140
|
+
### 3. Rollback Merged PR
|
|
141
|
+
|
|
142
|
+
**Use when**: Need to revert an entire merged pull request
|
|
143
|
+
|
|
144
|
+
**How it works**:
|
|
145
|
+
```bash
|
|
146
|
+
git revert -m 1 <merge-commit-hash> --no-edit
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Example**:
|
|
150
|
+
```bash
|
|
151
|
+
npx forge rollback
|
|
152
|
+
# Select: 3. Rollback merged PR
|
|
153
|
+
# Enter: def456 (merge commit hash)
|
|
154
|
+
|
|
155
|
+
✓ Validating commit hash...
|
|
156
|
+
✓ Working directory is clean
|
|
157
|
+
✓ Extracting USER sections...
|
|
158
|
+
✓ Executing: git revert -m 1 def456 --no-edit
|
|
159
|
+
✓ Restoring USER sections...
|
|
160
|
+
✓ Amended commit to preserve USER content
|
|
161
|
+
✓ Beads integration: Issue #123 marked as 'reverted'
|
|
162
|
+
|
|
163
|
+
Rollback complete!
|
|
164
|
+
Commit: m1n2o3p "Revert: Merge pull request #123"
|
|
165
|
+
Files affected: 15
|
|
166
|
+
Beads issue: #123 status → reverted
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Beads Integration**:
|
|
170
|
+
- Parses commit message for issue number (`#123`)
|
|
171
|
+
- If found, runs: `bd update <id> --status reverted --comment "PR reverted"`
|
|
172
|
+
- Silently skips if Beads not installed
|
|
173
|
+
- Updates issue tracking automatically
|
|
174
|
+
|
|
175
|
+
### 4. Rollback Specific Files
|
|
176
|
+
|
|
177
|
+
**Use when**: Only certain files need to be restored
|
|
178
|
+
|
|
179
|
+
**How it works**:
|
|
180
|
+
```bash
|
|
181
|
+
git checkout HEAD~1 -- <file1> <file2> ...
|
|
182
|
+
git commit -m "Rollback: <files>"
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Example**:
|
|
186
|
+
```bash
|
|
187
|
+
npx forge rollback
|
|
188
|
+
# Select: 4. Rollback specific files
|
|
189
|
+
# Enter: AGENTS.md,docs/WORKFLOW.md
|
|
190
|
+
|
|
191
|
+
✓ Validating file paths...
|
|
192
|
+
✓ Working directory is clean
|
|
193
|
+
✓ Extracting USER sections...
|
|
194
|
+
✓ Executing: git checkout HEAD~1 -- AGENTS.md docs/WORKFLOW.md
|
|
195
|
+
✓ Committing changes...
|
|
196
|
+
✓ Restoring USER sections...
|
|
197
|
+
✓ Amended commit to preserve USER content
|
|
198
|
+
|
|
199
|
+
Rollback complete!
|
|
200
|
+
Commit: q4r5s6t "Rollback: AGENTS.md, docs/WORKFLOW.md"
|
|
201
|
+
Files affected: 2
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Path validation**:
|
|
205
|
+
- Comma-separated file paths
|
|
206
|
+
- Validates paths are within project root
|
|
207
|
+
- Prevents path traversal (`../../../etc/passwd`)
|
|
208
|
+
- Rejects shell metacharacters
|
|
209
|
+
- Uses `path.resolve()` + `startsWith()` check
|
|
210
|
+
|
|
211
|
+
### 5. Rollback Entire Branch
|
|
212
|
+
|
|
213
|
+
**Use when**: Need to revert a range of commits
|
|
214
|
+
|
|
215
|
+
**How it works**:
|
|
216
|
+
```bash
|
|
217
|
+
git revert <start-commit>..<end-commit> --no-edit
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Example**:
|
|
221
|
+
```bash
|
|
222
|
+
npx forge rollback
|
|
223
|
+
# Select: 5. Rollback entire branch
|
|
224
|
+
# Enter: abc123..def456
|
|
225
|
+
|
|
226
|
+
✓ Validating commit range...
|
|
227
|
+
✓ Working directory is clean
|
|
228
|
+
✓ Extracting USER sections...
|
|
229
|
+
✓ Executing: git revert abc123..def456 --no-edit
|
|
230
|
+
✓ Restoring USER sections...
|
|
231
|
+
✓ Amended commit to preserve USER content
|
|
232
|
+
|
|
233
|
+
Rollback complete!
|
|
234
|
+
Commits reverted: 7
|
|
235
|
+
Files affected: 24
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Range validation**:
|
|
239
|
+
- Format: `start..end`
|
|
240
|
+
- Both commits must be valid hashes (4-40 chars)
|
|
241
|
+
- Rejects invalid formats
|
|
242
|
+
- Checks for `..` separator
|
|
243
|
+
|
|
244
|
+
### 6. Preview Rollback (Dry Run)
|
|
245
|
+
|
|
246
|
+
**Use when**: Want to see what would change without executing
|
|
247
|
+
|
|
248
|
+
**How it works**:
|
|
249
|
+
- Prompts for method and target
|
|
250
|
+
- Validates inputs
|
|
251
|
+
- Shows affected files
|
|
252
|
+
- No git operations performed
|
|
253
|
+
|
|
254
|
+
**Example**:
|
|
255
|
+
```bash
|
|
256
|
+
npx forge rollback
|
|
257
|
+
# Select: 6. Preview rollback (dry run)
|
|
258
|
+
# Enter method: partial
|
|
259
|
+
# Enter target: AGENTS.md,package.json
|
|
260
|
+
|
|
261
|
+
✓ Validating inputs...
|
|
262
|
+
✓ DRY RUN MODE - No changes will be made
|
|
263
|
+
|
|
264
|
+
Preview of rollback:
|
|
265
|
+
Method: partial
|
|
266
|
+
Target: AGENTS.md, package.json
|
|
267
|
+
|
|
268
|
+
Files that would be affected:
|
|
269
|
+
- AGENTS.md
|
|
270
|
+
- package.json
|
|
271
|
+
|
|
272
|
+
USER sections that would be preserved:
|
|
273
|
+
- AGENTS.md: 2 sections
|
|
274
|
+
|
|
275
|
+
Custom commands that would be preserved:
|
|
276
|
+
- .claude/commands/custom/my-workflow.md
|
|
277
|
+
|
|
278
|
+
No changes made (dry run).
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Integration with Workflow
|
|
282
|
+
|
|
283
|
+
### When to Use Rollback
|
|
284
|
+
|
|
285
|
+
**During Development** (`/dev`):
|
|
286
|
+
- Implemented wrong approach
|
|
287
|
+
- Tests reveal fundamental issues
|
|
288
|
+
- Need to start over with different strategy
|
|
289
|
+
|
|
290
|
+
**After Shipping** (`/ship`):
|
|
291
|
+
- PR feedback requires complete redesign
|
|
292
|
+
- CI/CD failures indicate architecture problems
|
|
293
|
+
- Breaking changes need to be reverted
|
|
294
|
+
|
|
295
|
+
**After Merging** (`/merge`):
|
|
296
|
+
- Production issues discovered
|
|
297
|
+
- Need to revert feature entirely
|
|
298
|
+
- Rollback PR merge commit
|
|
299
|
+
|
|
300
|
+
**Recovery Scenarios**:
|
|
301
|
+
- Accidentally committed sensitive data (rollback + force push)
|
|
302
|
+
- Merge conflict resolution went wrong
|
|
303
|
+
- Refactor broke existing functionality
|
|
304
|
+
|
|
305
|
+
### Workflow Integration
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
# Standard workflow
|
|
309
|
+
/status → /research → /plan → /dev → /check → /ship → /review → /merge → /verify
|
|
310
|
+
|
|
311
|
+
# Recovery workflow
|
|
312
|
+
/dev → (issues discovered) → npx forge rollback → /dev (retry)
|
|
313
|
+
/ship → (CI fails) → npx forge rollback → /dev (fix) → /ship
|
|
314
|
+
/merge → (production issues) → npx forge rollback → /plan (redesign)
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Example: Failed Feature Implementation
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
# 1. Development phase - implement feature
|
|
321
|
+
/dev
|
|
322
|
+
# ... implementation ...
|
|
323
|
+
git commit -m "feat: add payment integration"
|
|
324
|
+
|
|
325
|
+
# 2. Check phase - tests fail
|
|
326
|
+
/check
|
|
327
|
+
# ERROR: Security vulnerability in payment handling
|
|
328
|
+
|
|
329
|
+
# 3. Rollback the implementation
|
|
330
|
+
npx forge rollback
|
|
331
|
+
# Select: 1. Rollback last commit
|
|
332
|
+
|
|
333
|
+
# 4. Research better approach
|
|
334
|
+
/research payment-integration
|
|
335
|
+
|
|
336
|
+
# 5. Plan with security in mind
|
|
337
|
+
/plan payment-integration
|
|
338
|
+
|
|
339
|
+
# 6. Implement correctly
|
|
340
|
+
/dev
|
|
341
|
+
# ... proper implementation with security ...
|
|
342
|
+
|
|
343
|
+
# 7. Verify and ship
|
|
344
|
+
/check → /ship
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
## Beads Integration
|
|
348
|
+
|
|
349
|
+
If Beads is installed (`npm i -g @beads/bd`), rollback automatically updates issue tracking.
|
|
350
|
+
|
|
351
|
+
### PR Rollback → Issue Status
|
|
352
|
+
|
|
353
|
+
When rolling back a merged PR:
|
|
354
|
+
1. Parse commit message for issue number (`#123`, `fixes #456`, etc.)
|
|
355
|
+
2. If issue number found:
|
|
356
|
+
```bash
|
|
357
|
+
bd update <id> --status reverted --comment "PR reverted by rollback"
|
|
358
|
+
```
|
|
359
|
+
3. Silently skip if:
|
|
360
|
+
- Beads not installed
|
|
361
|
+
- No issue number in commit message
|
|
362
|
+
- Issue doesn't exist
|
|
363
|
+
|
|
364
|
+
### Manual Beads Update
|
|
365
|
+
|
|
366
|
+
If automatic detection doesn't work:
|
|
367
|
+
```bash
|
|
368
|
+
# After rollback
|
|
369
|
+
bd update 123 --status reverted --comment "Rolled back due to production issues"
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## Troubleshooting
|
|
373
|
+
|
|
374
|
+
### Error: "Working directory not clean"
|
|
375
|
+
|
|
376
|
+
**Cause**: Uncommitted changes in working directory
|
|
377
|
+
|
|
378
|
+
**Solution**:
|
|
379
|
+
```bash
|
|
380
|
+
# Option 1: Commit changes
|
|
381
|
+
git add .
|
|
382
|
+
git commit -m "wip: current work"
|
|
383
|
+
|
|
384
|
+
# Option 2: Stash changes
|
|
385
|
+
git stash
|
|
386
|
+
|
|
387
|
+
# Then retry rollback
|
|
388
|
+
npx forge rollback
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### Error: "Invalid commit hash format"
|
|
392
|
+
|
|
393
|
+
**Cause**: Commit hash doesn't match required pattern
|
|
394
|
+
|
|
395
|
+
**Valid formats**:
|
|
396
|
+
- `HEAD` (special keyword)
|
|
397
|
+
- `a1b2c3d` (4-40 character hex string)
|
|
398
|
+
- `abc123def456` (longer hash)
|
|
399
|
+
|
|
400
|
+
**Invalid formats**:
|
|
401
|
+
- `abc;rm -rf /` (contains shell metacharacter)
|
|
402
|
+
- `12` (too short, < 4 chars)
|
|
403
|
+
- `not-a-hash` (not hexadecimal)
|
|
404
|
+
|
|
405
|
+
**Solution**:
|
|
406
|
+
```bash
|
|
407
|
+
# Get valid commit hash
|
|
408
|
+
git log --oneline
|
|
409
|
+
# Copy full or abbreviated hash (4+ chars)
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Error: "Path outside project"
|
|
413
|
+
|
|
414
|
+
**Cause**: File path resolves to outside project root
|
|
415
|
+
|
|
416
|
+
**Examples**:
|
|
417
|
+
- `../../../etc/passwd` (path traversal)
|
|
418
|
+
- `/absolute/path/outside/project`
|
|
419
|
+
|
|
420
|
+
**Solution**:
|
|
421
|
+
```bash
|
|
422
|
+
# Use relative paths within project
|
|
423
|
+
npx forge rollback
|
|
424
|
+
# Select: 4. Rollback specific files
|
|
425
|
+
# Enter: src/auth.js,docs/API.md (relative paths)
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
### Error: "Invalid characters in path"
|
|
429
|
+
|
|
430
|
+
**Cause**: File path contains shell metacharacters
|
|
431
|
+
|
|
432
|
+
**Rejected characters**: `;`, `|`, `&`, `$`, `` ` ``, `(`, `)`, `<`, `>`, `\n`, `\r`
|
|
433
|
+
|
|
434
|
+
**Solution**:
|
|
435
|
+
```bash
|
|
436
|
+
# Remove special characters from filename
|
|
437
|
+
mv "file;name.js" "filename.js"
|
|
438
|
+
|
|
439
|
+
# Or escape properly (not recommended)
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### Error: "Branch range must use format: start..end"
|
|
443
|
+
|
|
444
|
+
**Cause**: Branch range doesn't include `..` separator
|
|
445
|
+
|
|
446
|
+
**Valid formats**:
|
|
447
|
+
- `abc123..def456`
|
|
448
|
+
- `a1b2c3d..x9y8z7w`
|
|
449
|
+
|
|
450
|
+
**Invalid formats**:
|
|
451
|
+
- `abc123-def456` (wrong separator)
|
|
452
|
+
- `abc123` (no range)
|
|
453
|
+
|
|
454
|
+
**Solution**:
|
|
455
|
+
```bash
|
|
456
|
+
# Use correct format
|
|
457
|
+
npx forge rollback
|
|
458
|
+
# Select: 5. Rollback entire branch
|
|
459
|
+
# Enter: <start-commit>..<end-commit>
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
### Merge Conflicts During Rollback
|
|
463
|
+
|
|
464
|
+
**Cause**: Revert conflicts with subsequent changes
|
|
465
|
+
|
|
466
|
+
**Solution**:
|
|
467
|
+
```bash
|
|
468
|
+
# 1. Rollback creates conflict markers
|
|
469
|
+
git status
|
|
470
|
+
# On branch: main
|
|
471
|
+
# Unmerged paths:
|
|
472
|
+
# both modified: src/auth.js
|
|
473
|
+
|
|
474
|
+
# 2. Resolve conflicts manually
|
|
475
|
+
# Edit src/auth.js, remove markers
|
|
476
|
+
|
|
477
|
+
# 3. Complete the revert
|
|
478
|
+
git add src/auth.js
|
|
479
|
+
git revert --continue
|
|
480
|
+
|
|
481
|
+
# 4. USER sections restored automatically
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### USER Sections Not Restored
|
|
485
|
+
|
|
486
|
+
**Cause**: Markers missing or malformed
|
|
487
|
+
|
|
488
|
+
**Check markers**:
|
|
489
|
+
```bash
|
|
490
|
+
grep -n "USER:START" AGENTS.md
|
|
491
|
+
grep -n "USER:END" AGENTS.md
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
**Valid markers**:
|
|
495
|
+
```markdown
|
|
496
|
+
<!-- USER:START -->
|
|
497
|
+
Content
|
|
498
|
+
<!-- USER:END -->
|
|
499
|
+
|
|
500
|
+
<!-- USER:START:name -->
|
|
501
|
+
Named section
|
|
502
|
+
<!-- USER:END:name -->
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
**Invalid markers**:
|
|
506
|
+
```markdown
|
|
507
|
+
<!-- USER START --> (missing colon)
|
|
508
|
+
<!-- USER:START (missing closing -->)
|
|
509
|
+
<!-- USER:END --> (no matching START)
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
**Solution**:
|
|
513
|
+
```bash
|
|
514
|
+
# Fix markers before rollback
|
|
515
|
+
# Ensure all USER:START have matching USER:END
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
## Safety Notes
|
|
519
|
+
|
|
520
|
+
### Input Validation
|
|
521
|
+
|
|
522
|
+
All inputs are validated **before** use in git commands:
|
|
523
|
+
|
|
524
|
+
**Commit hashes**:
|
|
525
|
+
```javascript
|
|
526
|
+
if (target !== 'HEAD' && !/^[0-9a-f]{4,40}$/i.test(target)) {
|
|
527
|
+
return { valid: false, error: 'Invalid commit hash format' };
|
|
528
|
+
}
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
**File paths**:
|
|
532
|
+
```javascript
|
|
533
|
+
const resolved = path.resolve(projectRoot, file);
|
|
534
|
+
if (!resolved.startsWith(projectRoot)) {
|
|
535
|
+
return { valid: false, error: 'Path outside project' };
|
|
536
|
+
}
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
**Shell metacharacters**:
|
|
540
|
+
```javascript
|
|
541
|
+
if (/[;|&$`()<>\r\n]/.test(file)) {
|
|
542
|
+
return { valid: false, error: 'Invalid characters in path' };
|
|
543
|
+
}
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
### Non-Destructive Operations
|
|
547
|
+
|
|
548
|
+
**Uses**:
|
|
549
|
+
- `git revert` (creates new commit, preserves history)
|
|
550
|
+
- `git checkout HEAD~1 -- <files>` (restores specific files)
|
|
551
|
+
|
|
552
|
+
**Never uses**:
|
|
553
|
+
- `git reset --hard` (destroys commits)
|
|
554
|
+
- `git push --force` (overwrites remote)
|
|
555
|
+
- `git clean -f` (deletes untracked files)
|
|
556
|
+
|
|
557
|
+
### Data Preservation
|
|
558
|
+
|
|
559
|
+
**Always preserved**:
|
|
560
|
+
- USER sections in all files
|
|
561
|
+
- Custom commands in `.claude/commands/custom/`
|
|
562
|
+
- Git history (revert creates new commits)
|
|
563
|
+
- Untracked files (not affected)
|
|
564
|
+
|
|
565
|
+
**Never lost**:
|
|
566
|
+
- Your customizations
|
|
567
|
+
- Work in progress (if committed/stashed)
|
|
568
|
+
- Remote branches (local operation only)
|
|
569
|
+
|
|
570
|
+
### Recommended Workflow
|
|
571
|
+
|
|
572
|
+
```bash
|
|
573
|
+
# 1. Always commit work before rollback
|
|
574
|
+
git add .
|
|
575
|
+
git commit -m "wip: current state"
|
|
576
|
+
|
|
577
|
+
# 2. Use dry run to preview
|
|
578
|
+
npx forge rollback
|
|
579
|
+
# Select: 6. Preview rollback (dry run)
|
|
580
|
+
|
|
581
|
+
# 3. Execute rollback
|
|
582
|
+
npx forge rollback
|
|
583
|
+
# Select appropriate method
|
|
584
|
+
|
|
585
|
+
# 4. Verify USER sections preserved
|
|
586
|
+
grep -A5 "USER:START" AGENTS.md
|
|
587
|
+
|
|
588
|
+
# 5. Push if needed (after verification)
|
|
589
|
+
git push
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
## Examples
|
|
593
|
+
|
|
594
|
+
### Example 1: Quick Undo Last Commit
|
|
595
|
+
|
|
596
|
+
```bash
|
|
597
|
+
# Scenario: Just committed but realized approach is wrong
|
|
598
|
+
|
|
599
|
+
git log --oneline
|
|
600
|
+
# abc123d (HEAD) feat: add caching layer
|
|
601
|
+
# def456e fix: validation bug
|
|
602
|
+
|
|
603
|
+
npx forge rollback
|
|
604
|
+
# 1. Rollback last commit
|
|
605
|
+
|
|
606
|
+
# Output:
|
|
607
|
+
# ✓ Working directory is clean
|
|
608
|
+
# ✓ Extracting USER sections...
|
|
609
|
+
# ✓ Executing: git revert HEAD --no-edit
|
|
610
|
+
# ✓ Restoring USER sections...
|
|
611
|
+
# ✓ Rollback complete!
|
|
612
|
+
|
|
613
|
+
git log --oneline
|
|
614
|
+
# xyz789f (HEAD) Revert: feat: add caching layer
|
|
615
|
+
# abc123d feat: add caching layer
|
|
616
|
+
# def456e fix: validation bug
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
### Example 2: Revert Merged PR
|
|
620
|
+
|
|
621
|
+
```bash
|
|
622
|
+
# Scenario: PR #123 caused production issues
|
|
623
|
+
|
|
624
|
+
git log --oneline
|
|
625
|
+
# merge789 (HEAD) Merge pull request #123
|
|
626
|
+
# feat456a feat: add real-time updates
|
|
627
|
+
# bugfix123 fix: websocket connection
|
|
628
|
+
|
|
629
|
+
npx forge rollback
|
|
630
|
+
# 3. Rollback merged PR
|
|
631
|
+
# Enter: merge789
|
|
632
|
+
|
|
633
|
+
# Output:
|
|
634
|
+
# ✓ Validating commit hash...
|
|
635
|
+
# ✓ Working directory is clean
|
|
636
|
+
# ✓ Extracting USER sections...
|
|
637
|
+
# ✓ Executing: git revert -m 1 merge789 --no-edit
|
|
638
|
+
# ✓ Restoring USER sections...
|
|
639
|
+
# ✓ Beads: Issue #123 → status: reverted
|
|
640
|
+
# ✓ Rollback complete!
|
|
641
|
+
|
|
642
|
+
bd show 123
|
|
643
|
+
# ID: 123
|
|
644
|
+
# Title: Add real-time updates
|
|
645
|
+
# Status: reverted
|
|
646
|
+
# Comments:
|
|
647
|
+
# - PR reverted by rollback
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
### Example 3: Restore Specific Files
|
|
651
|
+
|
|
652
|
+
```bash
|
|
653
|
+
# Scenario: Accidentally updated wrong files in last commit
|
|
654
|
+
|
|
655
|
+
git show HEAD --name-only
|
|
656
|
+
# commit abc123
|
|
657
|
+
# feat: update documentation
|
|
658
|
+
# AGENTS.md (should not have changed)
|
|
659
|
+
# docs/API.md
|
|
660
|
+
# README.md
|
|
661
|
+
|
|
662
|
+
npx forge rollback
|
|
663
|
+
# 4. Rollback specific files
|
|
664
|
+
# Enter: AGENTS.md
|
|
665
|
+
|
|
666
|
+
# Output:
|
|
667
|
+
# ✓ Validating file paths...
|
|
668
|
+
# ✓ Working directory is clean
|
|
669
|
+
# ✓ Extracting USER sections...
|
|
670
|
+
# ✓ Executing: git checkout HEAD~1 -- AGENTS.md
|
|
671
|
+
# ✓ Committing changes...
|
|
672
|
+
# ✓ Restoring USER sections...
|
|
673
|
+
# ✓ Rollback complete!
|
|
674
|
+
# Files affected: 1
|
|
675
|
+
|
|
676
|
+
git status
|
|
677
|
+
# On branch: main
|
|
678
|
+
# nothing to commit, working tree clean
|
|
679
|
+
# (AGENTS.md restored to previous version)
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
### Example 4: Dry Run Preview
|
|
683
|
+
|
|
684
|
+
```bash
|
|
685
|
+
# Scenario: Want to see what rollback would do
|
|
686
|
+
|
|
687
|
+
npx forge rollback
|
|
688
|
+
# 6. Preview rollback (dry run)
|
|
689
|
+
# Method: commit
|
|
690
|
+
# Target: HEAD
|
|
691
|
+
|
|
692
|
+
# Output:
|
|
693
|
+
# ✓ Validating inputs...
|
|
694
|
+
# ✓ DRY RUN MODE - No changes will be made
|
|
695
|
+
#
|
|
696
|
+
# Preview of rollback:
|
|
697
|
+
# Method: commit
|
|
698
|
+
# Target: HEAD
|
|
699
|
+
#
|
|
700
|
+
# Files that would be affected:
|
|
701
|
+
# - src/auth/middleware.js
|
|
702
|
+
# - src/auth/validators.js
|
|
703
|
+
# - tests/auth.test.js
|
|
704
|
+
#
|
|
705
|
+
# USER sections that would be preserved:
|
|
706
|
+
# - AGENTS.md: 2 sections
|
|
707
|
+
# - CLAUDE.md: 1 section
|
|
708
|
+
#
|
|
709
|
+
# Custom commands that would be preserved:
|
|
710
|
+
# - .claude/commands/custom/deploy.md
|
|
711
|
+
#
|
|
712
|
+
# No changes made (dry run).
|
|
713
|
+
|
|
714
|
+
# Decision: Proceed with rollback
|
|
715
|
+
npx forge rollback
|
|
716
|
+
# 1. Rollback last commit
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
## See Also
|
|
720
|
+
|
|
721
|
+
- [/dev](.claude/commands/dev.md) - TDD development workflow
|
|
722
|
+
- [/check](.claude/commands/check.md) - Validation before shipping
|
|
723
|
+
- [docs/WORKFLOW.md](../../docs/WORKFLOW.md) - Complete workflow guide
|
|
724
|
+
- [Beads](https://github.com/beadshq/beads) - Issue tracking integration
|