gitgrip 0.10.0

Multi-repo workflow tool - manage multiple git repositories as one
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
# gitgrip Development Guide

**git a grip** - Multi-repo workflow tool (Rust implementation)

## Build & Test

```bash
cargo build                # Build debug binary
cargo build --release      # Build release binary
cargo test                 # Run tests
cargo clippy               # Lint code
cargo fmt                  # Format code
cargo bench                # Run benchmarks
```

## Git Workflow

**IMPORTANT:** Never push directly to main. Never use raw `git` commands. Always use `gr` for all operations.

### Branch Strategy

**Main Branch (`main`)**
- Production-ready code
- Protected with PR requirements
- All PRs must target `main`
- Use `gr sync` to stay current (not `git pull`)

**Feature Branches (`feat/*`, `fix/*`, `chore/*`)**
- All development happens here
- Short-lived, deleted after merge

### Standard Workflow

```bash
# Start new work
gr sync                              # Pull latest from all repos
gr status                            # Verify clean state
gr branch feat/my-feature            # Create branch across repos

# Make changes...
gr diff                              # Review changes
gr add .                             # Stage changes across repos
gr commit -m "feat: description"     # Commit across repos
gr push -u                           # Push with upstream tracking

# Create PR
gr pr create -t "feat: description" --push

# After PR merged
gr sync                              # Pull latest and cleanup
gr checkout main                     # Switch back to main
```

### IMPORTANT: Never Use Raw Git

All git operations must go through `gr`. There is no exception.

```
❌ WRONG:
   git checkout -b feat/x
   git add . && git commit -m "msg" && git push
   gh pr create --title "msg"

✅ CORRECT:
   gr branch feat/x
   gr add . && gr commit -m "msg" && gr push -u
   gr pr create -t "msg" --push
```

`gr` manages all repos and the manifest together. Using raw `git` or `gh` bypasses multi-repo coordination and will miss the manifest repo.

### PR Review Process

**IMPORTANT: Never merge a PR without reviewing it first.** Always review your own PRs before merging.

**For AI agents (Claude, Codi, etc.):** Do NOT immediately merge after creating a PR. Always:
1. Create the PR with `gr pr create -t "title"`
2. Run `cargo build && cargo test` to verify nothing is broken
3. Check PR status with `gr pr status`
4. **Wait for GitHub checks to pass** - use `gh pr checks <number>` to verify
5. Review the diff with `gh pr diff <number>` (for each repo with changes)
6. Check feature completeness (see checklist below)
7. Only then merge with `gr pr merge` (if all checks pass and no issues found)

**CRITICAL: GitHub checks must pass before merging.** If checks are pending, wait. If checks fail, fix the issues first.

**Feature completeness checklist:**
- [ ] New command registered in `src/main.rs`
- [ ] Types added to appropriate module if needed
- [ ] Tests added for new functionality

**CRITICAL: Run benchmarks for performance-related changes:**

When modifying core git operations or command implementations:

```bash
# Run benchmarks
cargo bench

# Run workspace benchmarks (requires gitgrip workspace)
gr bench -n 10
```

Compare results before/after your changes. Document significant improvements or regressions in the PR description.

**CRITICAL: Update all documentation when changing commands/API:**
- [ ] `CLAUDE.md` - Development guide and command reference
- [ ] `README.md` - User-facing documentation
- [ ] `CONTRIBUTING.md` - If workflow changes
- [ ] `CHANGELOG.md` - Add entry for the change
- [ ] `.claude/skills/gitgrip/SKILL.md` - Claude Code skill definition

Forgetting to update docs creates drift between code and documentation. Always check these files when adding/modifying commands.

### Release Process

When creating a new release:

1. **Update version numbers:**
   - [ ] `Cargo.toml` - version field
   - [ ] `CHANGELOG.md` - Add new version section with date

2. **Create and merge release PR:**
   ```bash
   gr branch release/vX.Y.Z
   # Update Cargo.toml version and CHANGELOG.md
   cargo build --release  # Updates Cargo.lock
   gr add . && gr commit -m "chore: release vX.Y.Z"
   gr push -u && gr pr create -t "chore: release vX.Y.Z"
   # Wait for CI, then merge
   gr pr merge --force
   gr checkout main && gr sync
   ```

3. **Create GitHub release:**
   ```bash
   gh release create vX.Y.Z --repo laynepenney/gitgrip --title "vX.Y.Z" --notes "Release notes..."
   ```
   This triggers GitHub Actions to automatically:
   - Build binaries for all platforms
   - Publish to crates.io
   - Create GitHub release with binaries

4. **CRITICAL: Update Homebrew formula (MUST DO EVERY RELEASE):**

   The `homebrew-tap` repo is part of the gitgrip workspace. Update it using `gr` commands:

   ```bash
   # Get SHA256 of the new release tarball
   curl -sL https://github.com/laynepenney/gitgrip/archive/refs/tags/vX.Y.Z.tar.gz | shasum -a 256

   # Update the formula
   # Edit homebrew-tap/Formula/gitgrip.rb:
   #   - Update url to new version tag
   #   - Update sha256 to new hash

   # Commit and merge via gr
   gr branch chore/bump-gitgrip-X.Y.Z
   gr add . && gr commit -m "chore: bump gitgrip to vX.Y.Z"
   gr push -u && gr pr create -t "chore: bump gitgrip to vX.Y.Z"
   gr pr merge --force
   gr checkout main && gr sync
   ```

   **Forgetting to update Homebrew means users on `brew upgrade` won't get the new version.**

   Verify the update worked:
   ```bash
   brew update
   brew outdated  # Should show gitgrip if you have old version
   brew upgrade gitgrip
   gr --version   # Should show new version
   ```

## Project Structure

```
src/
├── main.rs               # CLI entry point (clap)
├── lib.rs                # Library exports
├── cli/                  # CLI command implementations
│   ├── mod.rs            # CLI module exports
│   ├── init.rs           # gr init
│   ├── sync.rs           # gr sync
│   ├── status.rs         # gr status
│   ├── branch.rs         # gr branch
│   ├── checkout.rs       # gr checkout
│   ├── add.rs            # gr add
│   ├── diff.rs           # gr diff
│   ├── commit.rs         # gr commit
│   ├── push.rs           # gr push
│   ├── pull.rs           # gr pull
│   ├── rebase.rs         # gr rebase
│   ├── forall.rs         # gr forall
│   ├── grep.rs           # gr grep
│   ├── prune.rs          # gr prune
│   ├── gc.rs             # gr gc
│   ├── cherry_pick.rs    # gr cherry-pick
│   ├── ci.rs             # gr ci
│   ├── group.rs          # gr group
│   ├── manifest.rs       # gr manifest
│   ├── repo.rs           # gr repo
│   ├── link.rs           # gr link
│   ├── run.rs            # gr run
│   ├── env.rs            # gr env
│   ├── bench.rs          # gr bench
│   ├── tree.rs           # gr tree (griptrees)
│   └── pr/               # PR subcommands
│       ├── mod.rs
│       ├── create.rs
│       ├── status.rs
│       ├── merge.rs
│       ├── checks.rs
│       └── diff.rs
├── core/                 # Core library
│   ├── mod.rs
│   ├── manifest.rs       # Manifest parsing
│   ├── griptree.rs       # Griptree config and upstream tracking
│   ├── workspace.rs      # Workspace operations
│   ├── repo.rs           # Repo info and filtering
│   └── config.rs         # Configuration
├── git/                  # Git operations
│   ├── mod.rs
│   ├── repo.rs           # Repository operations
│   ├── branch.rs         # Branch operations
│   ├── remote.rs         # Remote/fetch/pull operations
│   ├── cache.rs          # Git status cache
│   └── worktree.rs       # Worktree operations
├── platform/             # Multi-platform hosting support
│   ├── mod.rs
│   ├── github.rs         # GitHub adapter
│   ├── gitlab.rs         # GitLab adapter
│   ├── azure.rs          # Azure DevOps adapter
│   ├── bitbucket.rs      # Bitbucket adapter
│   ├── rate_limit.rs     # API rate limiting
│   ├── traits.rs         # HostingPlatform trait
│   └── types.rs          # Shared platform types
├── files/                # File operations
│   └── mod.rs            # copyfile/linkfile
└── util/                 # Utilities
    ├── mod.rs
    ├── cmd.rs            # Command logging with credential sanitization
    ├── output.rs         # Colored output with progress bars
    ├── retry.rs          # Retry with exponential backoff
    └── timing.rs         # Benchmarking
```

## Key Concepts

### Manifest
Workspace configuration in `.gitgrip/manifests/manifest.yaml`:
- `repos`: Repository definitions with URL, path, default_branch
- `manifest`: Self-tracking for the manifest repo itself
- `workspace`: Scripts, hooks, and environment variables
- `settings`: PR prefix, merge strategy


### Commands
All commands use `gr` (or `gitgrip`):
- `gr init <url>` - Initialize workspace from manifest URL
- `gr init --from-dirs` - Initialize workspace from existing local directories
- `gr init --from-repo` - Initialize from existing `.repo/` directory (git-repo coexistence)
- `gr sync` - Pull all repos in parallel + process links + run hooks (includes manifest)
  - `gr sync --sequential` - Sync repos sequentially (slower but ordered output)
  - `gr sync --group <name>` - Sync only repos in a group
- `gr status` - Show repo and manifest status
  - `gr status --json` - Machine-readable output
- `gr branch <name>` - Create branch across all repos (includes manifest)
  - `gr branch --repo <names>` - Create branch in specific repos only
  - `gr branch --delete` - Delete branch across repos
  - `gr branch --move` - Move commits to new branch
- `gr checkout <branch>` - Checkout branch across all repos (includes manifest)
  - `gr checkout -b <branch>` - Create and checkout branch in one command
  - `gr checkout --base` - Checkout griptree base branch (griptree workspaces only)
- `gr add` - Stage changes across all repos
- `gr diff` - Show diff across all repos (includes manifest)
- `gr commit` - Commit staged changes across all repos
- `gr push` - Push current branch in all repos (includes manifest)
- `gr pull` - Pull latest changes across repos
  - `gr pull --rebase` - Rebase instead of merge
- `gr rebase` - Rebase across repos
  - `gr rebase --upstream` - Rebase onto upstream (uses griptree config if available)
  - `gr rebase --abort` / `--continue` - Manage in-progress rebases
- `gr pr create/status/merge/checks/diff` - Linked PR workflow
  - `gr pr create --push --draft` - Push and create as draft
  - `gr pr merge --update` - Update branch from base if behind, then merge
  - `gr pr merge --auto` - Enable auto-merge (merges when checks pass)
  - `gr pr merge --force` - Merge even if checks pending
- `gr repo add/list/remove` - Manage repositories
- `gr group list` - List all groups and their repos
  - `gr group add <group> <repos...>` - Add repos to a group
  - `gr group remove <group> <repos...>` - Remove repos from a group
- `gr grep <pattern>` - Search across all repos using git grep
  - `gr grep -i` - Case insensitive search
  - `gr grep --parallel` - Concurrent search
- `gr prune` - Clean up merged branches (dry-run by default)
  - `gr prune --execute` - Actually delete branches
  - `gr prune --remote` - Also prune remote tracking refs
- `gr gc` - Run garbage collection across repos
  - `gr gc --aggressive` - More thorough (slower)
  - `gr gc --dry-run` - Only report .git sizes
- `gr cherry-pick <commit>` - Cherry-pick commits across repos
  - `gr cherry-pick --abort` / `--continue` - Manage in-progress cherry-picks
- `gr ci run/list/status` - CI/CD pipeline operations
- `gr manifest import/sync/schema` - Manifest operations
  - `gr manifest schema` - Show manifest specification (YAML/JSON/Markdown)
- `gr link` - Manage copyfile/linkfile entries
- `gr run` - Execute workspace scripts
- `gr env` - Show workspace environment variables
- `gr bench` - Run benchmarks
- `gr forall -c "cmd"` - Run command in each repo
- `gr tree add/list/remove` - Manage griptrees (worktree-based multi-branch workspaces)
- `gr completions <shell>` - Generate shell completions (bash, zsh, fish, elvish, powershell)

### Griptrees (Multi-Branch Workspaces)

Griptrees allow you to work on multiple branches simultaneously without switching branches. Each griptree is a parallel workspace using git worktrees.

```bash
# Create a griptree for a feature branch
gr tree add feat/auth

# This creates a directory structure:
# ../feat-auth/
#   ├── codi/           # worktree of main/codi on feat/auth
#   ├── codi-private/   # worktree of main/codi-private on feat/auth
#   └── .gitgrip/manifests/  # worktree of manifest on feat/auth

# List all griptrees
gr tree list

# Lock a griptree to prevent accidental removal
gr tree lock feat/auth

# Return to griptree base branch
gr checkout --base

# Remove a griptree (removes worktrees, not branches)
gr tree remove feat/auth
```

**Upstream Tracking:**

Each griptree records per-repo upstream defaults in `.gitgrip/griptree.json`. This allows repos in the same workspace to track different upstream branches (e.g., one repo tracks `origin/main`, another tracks `origin/dev`).

- `gr tree add` auto-detects upstream for each repo
- `gr sync` uses per-repo upstream when on the griptree base branch
- `gr rebase --upstream` rebases each repo onto its configured upstream
- Falls back to `origin/<default_branch>` when no upstream is configured

**Benefits:**
- No branch switching - work on multiple features in parallel
- Shared git objects - worktrees share `.git/objects` with main
- Faster than cloning - worktree creation is nearly instant
- Per-repo upstream tracking - different repos can track different branches

**Limitations:**
- Branch exclusivity - can't checkout same branch in two worktrees
- Separate dependencies - each worktree needs own dependencies

### File Linking
- `copyfile`: Copy file from repo to workspace
- `linkfile`: Create symlink from workspace to repo
- Path validation prevents directory traversal

### Multi-Platform Support

gitgrip supports multiple hosting platforms:
- **GitHub** (github.com and GitHub Enterprise)
- **GitLab** (gitlab.com and self-hosted)
- **Azure DevOps** (dev.azure.com and Azure DevOps Server)
- **Bitbucket** (bitbucket.org and self-hosted)

**Platform Detection:**
- Platform is auto-detected from git URLs
- Can be overridden in manifest with `platform:` config

**Example mixed-platform manifest:**
```yaml
repos:
  frontend:
    url: git@github.com:org/frontend.git
    path: ./frontend
  backend:
    url: git@gitlab.com:org/backend.git
    path: ./backend
  infra:
    url: https://dev.azure.com/org/project/_git/infra
    path: ./infra
  legacy:
    url: git@bitbucket.org:org/legacy.git
    path: ./legacy
```

**Platform Architecture:**
- `HostingPlatform` trait defines all platform operations
- Each platform has an adapter in `src/platform/`
- Platform adapters handle: PR create/merge/status, reviews, status checks, URL parsing
- Rate limiting infrastructure for API calls

**Adding a New Platform:**
1. Create adapter in `src/platform/newplatform.rs`
2. Implement `HostingPlatform` trait
3. Add detection logic in `src/platform/mod.rs`
4. Add tests

## Testing

```bash
cargo test                      # Run all tests
cargo test -- --nocapture       # Show output
cargo test manifest             # Filter by name
```

Test files are alongside the modules they test or in `tests/`.

## Adding a New Command

1. Create `src/cli/mycommand.rs`
2. Add command to CLI in `src/main.rs`
3. Implement the command handler
4. Add tests

## Code Style

- Follow Rust idioms
- Use `anyhow` for error handling
- Use `colored` for colored output
- Validate manifest schema in `core/manifest.rs`

## Continuous Improvement

gitgrip is self-improving. When you encounter friction, missing features, or bugs:

1. **Tell the user** about the friction point
2. **Ask if they want a GitHub issue created** - e.g., "Want me to create an issue for this?"
3. **Create the issue directly** with `gh issue create` if approved

No need to document in IMPROVEMENTS.md first - create issues directly to reduce overhead.

### CRITICAL: Report When Falling Back to Raw Commands

**If you ever use raw `git` or `gh` commands, you MUST immediately:**

1. Tell the user about the friction point
2. Ask if they want a GitHub issue created

This is mandatory. Every workaround reveals a gap in `gr` that should be fixed.