@solaqua/gji 0.11.0 → 0.12.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/README.md +82 -496
- package/dist/clean.js +2 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +40 -4
- package/dist/context-card.d.ts +1 -0
- package/dist/context-card.js +25 -0
- package/dist/doctor.js +21 -0
- package/dist/done.js +2 -0
- package/dist/gji-bundle.mjs +988 -350
- package/dist/go.d.ts +1 -0
- package/dist/go.js +8 -0
- package/dist/hooks.d.ts +1 -0
- package/dist/hooks.js +7 -1
- package/dist/hub.d.ts +31 -0
- package/dist/hub.js +287 -0
- package/dist/ls.js +9 -1
- package/dist/new.d.ts +1 -0
- package/dist/new.js +9 -0
- package/dist/pr-open.js +2 -10
- package/dist/pull-requests.d.ts +1 -0
- package/dist/pull-requests.js +32 -3
- package/dist/remove.js +2 -0
- package/dist/repo.d.ts +1 -0
- package/dist/repo.js +4 -0
- package/dist/run-hook.js +2 -0
- package/dist/shell-completion.js +11 -3
- package/dist/slots.d.ts +8 -0
- package/dist/slots.js +61 -0
- package/dist/status.d.ts +2 -0
- package/dist/status.js +9 -1
- package/dist/task-command.d.ts +9 -0
- package/dist/task-command.js +29 -0
- package/dist/task.d.ts +9 -0
- package/dist/task.js +37 -0
- package/dist/terminal-text.d.ts +4 -0
- package/dist/terminal-text.js +72 -0
- package/dist/worktree-bootstrap.js +3 -0
- package/dist/worktree-info.d.ts +6 -1
- package/dist/worktree-info.js +14 -4
- package/dist/worktree-picker.d.ts +3 -3
- package/dist/worktree-picker.js +71 -82
- package/dist/worktree-sources.d.ts +1 -0
- package/dist/worktree-sources.js +57 -11
- package/man/man1/gji-back.1 +1 -1
- package/man/man1/gji-clean.1 +1 -1
- package/man/man1/gji-completion.1 +1 -1
- package/man/man1/gji-config.1 +1 -1
- package/man/man1/gji-doctor.1 +1 -1
- package/man/man1/gji-done.1 +1 -1
- package/man/man1/gji-go.1 +4 -1
- package/man/man1/gji-history.1 +1 -1
- package/man/man1/gji-init.1 +1 -1
- package/man/man1/gji-ls.1 +1 -1
- package/man/man1/gji-new.1 +4 -1
- package/man/man1/gji-open.1 +1 -1
- package/man/man1/gji-pr.1 +1 -1
- package/man/man1/gji-remove.1 +1 -1
- package/man/man1/gji-root.1 +1 -1
- package/man/man1/gji-run-hook.1 +1 -1
- package/man/man1/gji-status.1 +1 -1
- package/man/man1/gji-sync-files.1 +1 -1
- package/man/man1/gji-sync.1 +1 -1
- package/man/man1/gji-task.1 +16 -0
- package/man/man1/gji-undo.1 +1 -1
- package/man/man1/gji-warp.1 +1 -1
- package/man/man1/gji.1 +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,558 +1,144 @@
|
|
|
1
|
-
# gji — Git
|
|
1
|
+
# gji — Switch Git contexts without stashing
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Start, review, and switch between Git tasks without disturbing the work already open.
|
|
4
4
|
|
|
5
|
-
`gji`
|
|
5
|
+
`gji` makes Git worktrees feel like normal shell navigation. Each task gets its
|
|
6
|
+
own directory, dependencies, editor context, and terminal — so moving to a
|
|
7
|
+
pull request or experiment does not require stashing, checking out, or
|
|
8
|
+
reinstalling.
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
## Start your next task
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
gji new feature/payment-refactor # new branch + worktree, cd in
|
|
11
|
-
gji pr 1234 # review PR in isolation, cd in
|
|
12
|
-
gji pr open # open the PR for the current worktree
|
|
13
|
-
gji go main # jump back, shell changes directory
|
|
14
|
-
gji done feature/payment-refactor
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Before / After
|
|
18
|
-
|
|
19
|
-
<table>
|
|
20
|
-
<tr>
|
|
21
|
-
<td width="50%" valign="top">
|
|
22
|
-
<strong>Before</strong><br />
|
|
23
|
-
<img src=".github/assets/readme-before.gif" alt="Traditional branch review flow with git stash, branch switching, reinstalling dependencies, and a merge conflict on stash pop." />
|
|
24
|
-
</td>
|
|
25
|
-
<td width="50%" valign="top">
|
|
26
|
-
<strong>After</strong><br />
|
|
27
|
-
<img src=".github/assets/readme-after.gif" alt="gji creating an isolated pull request worktree from the terminal in a few commands." />
|
|
28
|
-
</td>
|
|
29
|
-
</tr>
|
|
30
|
-
</table>
|
|
31
|
-
|
|
32
|
-
Maintainer note: `pnpm generate:readme-demos` currently expects macOS, `zsh`, Google Chrome, `asciinema`, and `ffmpeg`.
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
**If `gji` has saved you from a `git stash` spiral, a ⭐ on [GitHub](https://github.com/sjquant/gji) means a lot — it helps other developers find this tool.**
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
## The problem
|
|
41
|
-
|
|
42
|
-
You are deep in a feature branch. A colleague asks for a quick review. You:
|
|
43
|
-
|
|
44
|
-
1. stash your changes
|
|
45
|
-
2. checkout their branch
|
|
46
|
-
3. wait for `npm install` to finish
|
|
47
|
-
4. review
|
|
48
|
-
5. checkout back
|
|
49
|
-
6. pop your stash
|
|
50
|
-
7. realize something is broken
|
|
51
|
-
|
|
52
|
-
**Or you use `gji`, run `gji pr 1234`, and let the fresh worktree boot itself.**
|
|
53
|
-
|
|
54
|
-
## Why it matters more now
|
|
55
|
-
|
|
56
|
-
AI increases the amount of parallel work around a codebase.
|
|
57
|
-
|
|
58
|
-
It is increasingly normal to have:
|
|
59
|
-
|
|
60
|
-
1. your own branch open
|
|
61
|
-
2. another branch for review
|
|
62
|
-
3. a scratch space for testing an AI-generated change
|
|
63
|
-
4. a separate worktree for validating a risky migration or refactor
|
|
64
|
-
|
|
65
|
-
That makes Git worktrees more important, because a single shared checkout becomes the bottleneck. `gji` turns worktrees into a daily workflow instead of a Git power-user feature.
|
|
66
|
-
|
|
67
|
-
## Install
|
|
12
|
+
Run `gji new` and let the interactive flow guide you into a fresh worktree:
|
|
68
13
|
|
|
69
14
|
```sh
|
|
70
|
-
|
|
15
|
+
gji new
|
|
71
16
|
```
|
|
72
17
|
|
|
73
|
-
|
|
18
|
+
Choose a task name and setup options, then continue working in the new
|
|
19
|
+
directory. For repeatable workflows, you can still provide a branch directly:
|
|
74
20
|
|
|
75
21
|
```sh
|
|
76
|
-
gji
|
|
77
|
-
# restart your shell, or source the rc file shown by the wizard
|
|
78
|
-
gji doctor
|
|
22
|
+
gji new feature/payment-refactor
|
|
79
23
|
```
|
|
80
24
|
|
|
81
|
-
The
|
|
25
|
+
## The problem
|
|
26
|
+
|
|
27
|
+
You are halfway through a feature when someone asks you to review a pull
|
|
28
|
+
request. Without worktrees, a quick review often becomes:
|
|
82
29
|
|
|
83
|
-
```
|
|
84
|
-
|
|
30
|
+
```text
|
|
31
|
+
stash → checkout → reinstall → review → checkout back → stash pop
|
|
85
32
|
```
|
|
86
33
|
|
|
87
|
-
|
|
34
|
+
With `gji`, the review gets its own workspace and your current task stays
|
|
35
|
+
untouched:
|
|
88
36
|
|
|
89
37
|
```sh
|
|
90
|
-
# start a new task
|
|
91
|
-
gji new feature/dark-mode
|
|
92
|
-
|
|
93
|
-
# start a task and open it straight in your editor
|
|
94
|
-
gji new feature/dark-mode --open --editor cursor
|
|
95
|
-
|
|
96
|
-
# review a pull request
|
|
97
38
|
gji pr 1234
|
|
98
|
-
gji pr open # open the PR for the current worktree
|
|
99
|
-
gji pr open --select # choose a PR from any linked worktree
|
|
100
|
-
gji pr open feature/auth-refactor # open the PR for a branch
|
|
101
|
-
gji pr open '#1234' # open an open PR directly
|
|
102
|
-
|
|
103
|
-
# see what's open
|
|
104
|
-
gji status
|
|
105
|
-
|
|
106
|
-
# jump between worktrees
|
|
107
|
-
gji go feature/dark-mode
|
|
108
|
-
gji go main
|
|
109
|
-
|
|
110
|
-
# open the current worktree in an editor
|
|
111
|
-
gji open
|
|
112
|
-
gji open --select # choose another worktree interactively
|
|
113
|
-
gji open feature/dark-mode --editor code
|
|
114
|
-
|
|
115
|
-
# finish a worktree when done
|
|
116
|
-
gji done feature/dark-mode
|
|
117
39
|
```
|
|
118
40
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
41
|
+
<table>
|
|
42
|
+
<tr>
|
|
43
|
+
<td width="50%" valign="top">
|
|
44
|
+
<strong>Before</strong><br />
|
|
45
|
+
<img src=".github/assets/readme-before.gif" alt="Traditional branch switching with stash and reinstall steps" />
|
|
46
|
+
</td>
|
|
47
|
+
<td width="50%" valign="top">
|
|
48
|
+
<strong>After</strong><br />
|
|
49
|
+
<img src=".github/assets/readme-after.gif" alt="Creating an isolated pull request worktree with gji" />
|
|
50
|
+
</td>
|
|
51
|
+
</tr>
|
|
52
|
+
</table>
|
|
126
53
|
|
|
127
|
-
##
|
|
54
|
+
## Remember four commands
|
|
128
55
|
|
|
129
56
|
```sh
|
|
130
|
-
gji new
|
|
131
|
-
gji
|
|
132
|
-
gji
|
|
133
|
-
|
|
134
|
-
gji pr 1234 # checkout PR locally
|
|
135
|
-
gji pr https://github.com/org/repo/pull/1234 # or paste the URL
|
|
136
|
-
|
|
137
|
-
gji go feature/auth-refactor # jump to a worktree
|
|
138
|
-
gji go teammate-branch # open an existing local or remote branch
|
|
139
|
-
gji go - # return to the previous worktree
|
|
140
|
-
gji go --root # return to the main repository checkout
|
|
141
|
-
gji root # jump to repo root
|
|
142
|
-
gji warp repo-a/main # compatibility spelling for cross-repo navigation
|
|
143
|
-
gji back # return through navigation history
|
|
144
|
-
gji history # inspect recent navigation
|
|
145
|
-
|
|
146
|
-
# with no branch, the chooser starts in the current repo; press Tab for all repos
|
|
147
|
-
|
|
148
|
-
gji status # health overview + ahead/behind counts
|
|
149
|
-
gji ls # list with status/upstream/last commit
|
|
150
|
-
gji ls --compact # branch/path only
|
|
151
|
-
|
|
152
|
-
gji sync # rebase current worktree onto default branch
|
|
153
|
-
gji sync --all # rebase every worktree
|
|
154
|
-
|
|
155
|
-
gji clean # interactive bulk cleanup
|
|
156
|
-
gji clean --stale # only target safe stale cleanup candidates
|
|
157
|
-
gji done feature/auth-refactor # finish one worktree and its branch
|
|
158
|
-
|
|
159
|
-
gji trigger-hook afterCreate # re-run setup in the current worktree
|
|
57
|
+
gji new # interactively start a task
|
|
58
|
+
gji pr 1234 # open a pull request in isolation
|
|
59
|
+
gji go main # jump to another worktree
|
|
60
|
+
gji done feature/payment-refactor # finish and clean up a task
|
|
160
61
|
```
|
|
161
62
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
`gji` sits between raw Git primitives and larger Git or repository tools:
|
|
165
|
-
|
|
166
|
-
- **vs raw `git worktree`**: same underlying capability, but with branch-first commands, shell handoff, PR checkout, hooks, sync, and cleanup built into the workflow
|
|
167
|
-
- **vs `lazygit`**: `lazygit` is a broad Git UI; `gji` is narrower and faster for opening, jumping between, and removing isolated branch directories
|
|
168
|
-
- **vs `ghq`**: `ghq` organizes where repositories live; `gji` organizes which branch, PR, or worktree you should be in once you are inside one
|
|
169
|
-
|
|
170
|
-
Use `gji` when your bottleneck is repeated context switching between features, reviews, and maintenance work without disturbing what is already open.
|
|
171
|
-
|
|
172
|
-
It is especially useful when those contexts are happening in parallel across both human and AI-assisted work.
|
|
173
|
-
|
|
174
|
-
See the full comparison in [website/docs/comparison.mdx](./website/docs/comparison.mdx).
|
|
175
|
-
|
|
176
|
-
## Shell setup
|
|
63
|
+
With shell integration enabled, each command moves your shell into the
|
|
64
|
+
selected worktree automatically.
|
|
177
65
|
|
|
178
|
-
|
|
66
|
+
## Install
|
|
179
67
|
|
|
180
68
|
```sh
|
|
69
|
+
npm install -g @solaqua/gji
|
|
181
70
|
gji init
|
|
182
|
-
gji doctor
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
`gji init` is interactive. For dotfiles or CI, the explicit shell commands remain available and preserve their existing output:
|
|
186
|
-
|
|
187
|
-
```sh
|
|
188
|
-
# zsh
|
|
189
|
-
echo 'eval "$(gji init zsh)"' >> ~/.zshrc
|
|
190
|
-
|
|
191
|
-
# bash
|
|
192
|
-
echo 'eval "$(gji init bash)"' >> ~/.bashrc
|
|
193
|
-
|
|
194
|
-
# fish
|
|
195
|
-
gji init fish --write
|
|
196
71
|
```
|
|
197
72
|
|
|
198
|
-
|
|
73
|
+
`gji init` interactively installs shell integration, completions, and an
|
|
74
|
+
available editor. Restart your shell, or source the rc file shown by the
|
|
75
|
+
wizard, then run:
|
|
199
76
|
|
|
200
77
|
```sh
|
|
201
|
-
|
|
202
|
-
mkdir -p ~/.zsh/completions
|
|
203
|
-
gji completion zsh > ~/.zsh/completions/_gji
|
|
204
|
-
# add this before running compinit in ~/.zshrc
|
|
205
|
-
fpath=(~/.zsh/completions $fpath)
|
|
206
|
-
|
|
207
|
-
# bash
|
|
208
|
-
mkdir -p ~/.local/share/bash-completion/completions
|
|
209
|
-
gji completion bash > ~/.local/share/bash-completion/completions/gji
|
|
210
|
-
|
|
211
|
-
# fish
|
|
212
|
-
mkdir -p ~/.config/fish/completions
|
|
213
|
-
gji completion fish > ~/.config/fish/completions/gji.fish
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
After a reinstall or upgrade, refresh both the wrapper and the completion file:
|
|
217
|
-
|
|
218
|
-
```sh
|
|
219
|
-
# zsh
|
|
220
|
-
eval "$(gji init zsh)"
|
|
221
|
-
gji completion zsh > ~/.zsh/completions/_gji
|
|
222
|
-
# if zsh is already running, refresh completion discovery too
|
|
223
|
-
autoload -Uz compinit && compinit
|
|
224
|
-
|
|
225
|
-
# fish
|
|
226
|
-
gji init fish --write
|
|
227
|
-
gji completion fish > ~/.config/fish/completions/gji.fish
|
|
228
|
-
source ~/.config/fish/config.fish
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
For scripts that need the raw path, use `--print`:
|
|
232
|
-
|
|
233
|
-
```sh
|
|
234
|
-
path=$(gji go --print feature/dark-mode)
|
|
235
|
-
path=$(gji root --print)
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
## Commands
|
|
239
|
-
|
|
240
|
-
| Command | Description |
|
|
241
|
-
|---|---|
|
|
242
|
-
| `gji new [branch] [--from-current] [--detached] [--no-fetch] [--take] [--copy] [--force] [--open] [--editor <cli>] [--dry-run] [--json]` | create branch + worktree from a refreshed remote base by default; `--no-fetch` opts out |
|
|
243
|
-
| `gji done [branch] [--force] [--keep-branch] [--json]` | safely finish a linked worktree and return |
|
|
244
|
-
| `gji undo [id] [--list] [--json]` | restore a journaled cleanup without overwriting work |
|
|
245
|
-
| `gji pr <ref> [--json]` | fetch PR ref, create worktree, cd in |
|
|
246
|
-
| `gji pr open [branch|#N] [--select]` | open the current worktree PR, or choose a linked worktree with `--select` |
|
|
247
|
-
| `gji back [n] [--print]` | return to a previous worktree from navigation history |
|
|
248
|
-
| `gji history [--json]` | show navigation history |
|
|
249
|
-
| `gji warp [branch] [--print] [--json]` | compatibility spelling for cross-repository navigation |
|
|
250
|
-
| `gji open [branch] [--select] [--editor <cli>] [--save] [--workspace]` | open the current or selected worktree in an editor |
|
|
251
|
-
| `gji go [branch] [--root] [--print] [--json]` | resolve and jump to a worktree, branch, remote, or PR |
|
|
252
|
-
| `gji root [--print]` | jump to the main repo root |
|
|
253
|
-
| `gji status [--json]` | repo overview, worktree health, ahead/behind |
|
|
254
|
-
| `gji ls [--compact] [--json]` | list active worktrees |
|
|
255
|
-
| `gji sync [--all]` | fetch and rebase worktrees onto default branch |
|
|
256
|
-
| `gji sync-files [list\|add\|remove] [paths...]` | manage local files copied into new worktrees |
|
|
257
|
-
| `gji clean [--stale] [--force] [--dry-run] [--json]` | interactively prune linked worktrees |
|
|
258
|
-
| `gji remove [branch] [--force] [--dry-run] [--json]` (`rm`) | **deprecated**; use `gji done` for one worktree or `gji clean` for bulk cleanup |
|
|
259
|
-
| `gji trigger-hook <hook>` | run a hook in the current worktree |
|
|
260
|
-
| `gji config [get\|set\|unset] [key] [value]` | manage global defaults |
|
|
261
|
-
| `gji init [shell]` | interactively set up onboarding, or print/install a shell wrapper |
|
|
262
|
-
| `gji doctor [--json] [--fix] [--yes]` | check installation and configuration health; optionally remove stale repository entries |
|
|
263
|
-
| `gji completion [shell]` | print shell completion definitions |
|
|
264
|
-
|
|
265
|
-
The repository registry records projects that gji has visited so `go`, `warp`,
|
|
266
|
-
and the chooser can resolve worktrees across repositories. It is advisory
|
|
267
|
-
metadata: missing paths are skipped and `gji doctor --fix` can remove stale
|
|
268
|
-
entries.
|
|
269
|
-
|
|
270
|
-
`gji remove` and its `rm` alias remain available during the deprecation window,
|
|
271
|
-
but print a migration warning in human-readable mode. Use `gji done <branch>`
|
|
272
|
-
to finish one linked worktree or `gji clean` to prune several worktrees.
|
|
273
|
-
|
|
274
|
-
## Configuration
|
|
275
|
-
|
|
276
|
-
No setup required. Optional config lives in:
|
|
277
|
-
|
|
278
|
-
- `~/.config/gji/config.json` — global defaults
|
|
279
|
-
- `.gji.json` — repo-local overrides (takes precedence)
|
|
280
|
-
|
|
281
|
-
### Available keys
|
|
282
|
-
|
|
283
|
-
| Key | Description |
|
|
284
|
-
|---|---|
|
|
285
|
-
| `branchPrefix` | prefix added to new branch names (e.g. `"feature/"`) |
|
|
286
|
-
| `editor` | default editor CLI for `gji open` and `gji new --open` (e.g. `"cursor"`, `"code"`, `"zed"`); set automatically with `gji open --save` |
|
|
287
|
-
| `worktreePath` | base directory for new worktrees (absolute or `~/…`); overrides the default `../worktrees/<repo>/` layout |
|
|
288
|
-
| `syncRemote` | remote for `gji sync` (default: `origin`) |
|
|
289
|
-
| `syncDefaultBranch` | branch to rebase onto (default: remote `HEAD`) |
|
|
290
|
-
| `syncFiles` | files to copy from main worktree into each new worktree; use global per-repo config for private files |
|
|
291
|
-
| `syncDirs` | arbitrary directories to clone with filesystem copy-on-write before sync files |
|
|
292
|
-
| `dependencyBootstrap` | dependency/build-state policy: `off`, `cow-then-repair`, or `install-only` |
|
|
293
|
-
| `dependencyBuildCommand` | optional Cargo repair command used by `dependencyBootstrap` (default: `cargo check`) |
|
|
294
|
-
| `skipInstallPrompt` | `true` to disable the auto-install prompt permanently |
|
|
295
|
-
| `installSaveTarget` | `"local"` or `"global"` — where dependency policy and legacy **Always**/**Never** choices are persisted (default: `"local"`); set during `gji init <shell> --write` |
|
|
296
|
-
| `hooks` | lifecycle scripts (see [Hooks](#hooks)) |
|
|
297
|
-
| `repos` | per-repo overrides inside the global config (see below) |
|
|
298
|
-
|
|
299
|
-
```json
|
|
300
|
-
{
|
|
301
|
-
"branchPrefix": "feature/",
|
|
302
|
-
"syncRemote": "upstream",
|
|
303
|
-
"syncDefaultBranch": "main",
|
|
304
|
-
"syncFiles": [".env.example", ".nvmrc"],
|
|
305
|
-
"syncDirs": [".next"],
|
|
306
|
-
"dependencyBootstrap": "cow-then-repair"
|
|
307
|
-
}
|
|
78
|
+
gji doctor
|
|
308
79
|
```
|
|
309
80
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
81
|
+
Without shell integration, commands still print paths for scripts and other
|
|
82
|
+
non-interactive use. See the [installation guide](https://gji.solaqua.dev/docs/installation)
|
|
83
|
+
for explicit shell setup.
|
|
313
84
|
|
|
314
|
-
|
|
85
|
+
## A typical day
|
|
315
86
|
|
|
316
87
|
```sh
|
|
317
|
-
|
|
318
|
-
gji
|
|
319
|
-
gji sync-files remove .npmrc
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
This stores:
|
|
88
|
+
# Start feature work
|
|
89
|
+
gji new
|
|
323
90
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
"repos": {
|
|
327
|
-
"/home/me/code/my-repo": {
|
|
328
|
-
"syncFiles": [".env.local"]
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
```
|
|
91
|
+
# Check what is active
|
|
92
|
+
gji
|
|
333
93
|
|
|
334
|
-
|
|
94
|
+
# Review a PR without changing the current task
|
|
95
|
+
gji pr 1234
|
|
335
96
|
|
|
336
|
-
|
|
97
|
+
# Move between tasks
|
|
98
|
+
gji go feature/payment-refactor
|
|
99
|
+
gji back
|
|
337
100
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}
|
|
101
|
+
# Keep worktrees current and remove finished work
|
|
102
|
+
gji sync
|
|
103
|
+
gji done feature/payment-refactor
|
|
342
104
|
```
|
|
343
105
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
Paths are relative to the repository root. Absolute paths, `..` segments, and `.git` paths are rejected in all three config layers.
|
|
347
|
-
|
|
348
|
-
The human output includes clone timing; dry-run can provide source-size estimates:
|
|
106
|
+
Worktrees use a predictable location by default:
|
|
349
107
|
|
|
350
108
|
```text
|
|
351
|
-
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
Use `dependencyBootstrap` when a package manager or build cache needs a reusable seed followed by authoritative repair:
|
|
355
|
-
|
|
356
|
-
```json
|
|
357
|
-
{
|
|
358
|
-
"dependencyBootstrap": "cow-then-repair"
|
|
359
|
-
}
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
`cow-then-repair` supports pnpm (`node_modules` + `pnpm install --frozen-lockfile`), Yarn (`node_modules` + `yarn install --immutable`), uv (`.venv` + `uv sync --locked`), Cargo (`target` + the configured `dependencyBuildCommand`, or `cargo check`), and Bundler (`vendor/bundle` + `BUNDLE_PATH=vendor/bundle bundle install`). npm is install-only (`npm ci`) because it can delete an existing dependency tree; it never seeds `node_modules`. Only project-local targets are eligible, so global Ruby gems and package-manager caches are never cloned. CoW failure never triggers ordinary copying: repair runs from an empty target instead. The lifecycle is `CoW seed → syncFiles → repair/install → after-create`; a sync-file failure stops repair, install prompts, and hooks. A successful dependency seed is reported as `reused and repaired`, not as an install skip.
|
|
363
|
-
|
|
364
|
-
When a supported lockfile is detected and no `dependencyBootstrap` policy is configured, interactive `gji new` and `gji pr` ask which policy to persist: **Reuse and repair (recommended)**, **Install fresh each time**, or **Skip dependency setup**. The prompt explains the detected tool—for example, pnpm reuses local `node_modules` through CoW and then runs `pnpm install --frozen-lockfile`. The choice is saved locally or in the per-repo global config according to `installSaveTarget`. Headless, JSON, and dry-run commands never prompt and retain the safe `off` default.
|
|
365
|
-
|
|
366
|
-
Ecosystems dominated by global caches, such as Gradle, Maven, and Go, are not seeded until a safe project-local target and deterministic repair rule are available. Future adapters can add Composer, Poetry/PDM, Mix, Dart/Flutter, or .NET without changing `syncDirs`.
|
|
367
|
-
|
|
368
|
-
Use `gji new --dry-run` to see the directories and estimated sizes without creating anything. `gji new --json` adds a `cloned` array and structured `dependencyBootstrap` events, including machine-readable reasons for skips and failures. If bootstrap fails, the JSON error includes the created worktree path; text mode prints the same path and a cleanup hint. The benchmark target for a 2 GB dependency tree on supported APFS/Btrfs or XFS filesystems is under 5 seconds; benchmark your repository locally because filesystem and storage behavior determine the result.
|
|
369
|
-
|
|
370
|
-
### Per-repo overrides in global config
|
|
371
|
-
|
|
372
|
-
If you work across many repositories, you can scope config to a specific repo inside `~/.config/gji/config.json` without adding a `.gji.json` to that repo:
|
|
373
|
-
|
|
374
|
-
```json
|
|
375
|
-
{
|
|
376
|
-
"branchPrefix": "feature/",
|
|
377
|
-
"repos": {
|
|
378
|
-
"/home/me/code/my-repo": {
|
|
379
|
-
"branchPrefix": "fix/",
|
|
380
|
-
"hooks": {
|
|
381
|
-
"afterCreate": "npm install"
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
Precedence (lowest → highest): **global defaults → per-repo global → local `.gji.json`**. Hooks from all three layers are merged per key — different keys all apply, same key the higher-precedence layer wins.
|
|
389
|
-
|
|
390
|
-
### Config commands
|
|
391
|
-
|
|
392
|
-
```sh
|
|
393
|
-
gji config get
|
|
394
|
-
gji config get branchPrefix
|
|
395
|
-
gji config set branchPrefix feature/
|
|
396
|
-
gji config unset branchPrefix
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
## Hooks
|
|
400
|
-
|
|
401
|
-
Run scripts automatically at key lifecycle moments:
|
|
402
|
-
|
|
403
|
-
```json
|
|
404
|
-
{
|
|
405
|
-
"hooks": {
|
|
406
|
-
"afterCreate": ["pnpm", "install"],
|
|
407
|
-
"afterEnter": ["printf", "switched to %s\n", "{{branch}}"],
|
|
408
|
-
"beforeRemove": "pnpm run cleanup"
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
| Hook | When it runs |
|
|
414
|
-
|---|---|
|
|
415
|
-
| `afterCreate` | after `gji new` or `gji pr` creates a worktree |
|
|
416
|
-
| `afterEnter` | after `gji go` switches to a worktree |
|
|
417
|
-
| `beforeRemove` | before `gji done` or `gji clean` deletes a worktree |
|
|
418
|
-
|
|
419
|
-
Hooks receive `{{branch}}`, `{{path}}`, `{{repo}}` as template variables and `GJI_BRANCH`, `GJI_PATH`, `GJI_REPO` as environment variables. A failing hook emits a warning but never aborts the command.
|
|
420
|
-
|
|
421
|
-
Prefer argv-array hooks for simple commands:
|
|
422
|
-
|
|
423
|
-
```json
|
|
424
|
-
{
|
|
425
|
-
"hooks": {
|
|
426
|
-
"afterCreate": ["pnpm", "install"],
|
|
427
|
-
"afterEnter": ["printf", "switched to %s at %s\n", "{{branch}}", "{{path}}"]
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
```
|
|
431
|
-
|
|
432
|
-
Array hooks run without a shell and pass each array item as exactly one argument. Use string hooks only when you need shell features like `&&`, pipes, redirects, shell functions, or `nvm use`.
|
|
433
|
-
|
|
434
|
-
Template values are interpolated before the shell parses string hooks, so avoid putting `{{branch}}`, `{{path}}`, or `{{repo}}` directly into shell strings. For shell-string hooks, the safer pattern is to use the environment variables and double-quote each expansion:
|
|
435
|
-
|
|
436
|
-
```json
|
|
437
|
-
{
|
|
438
|
-
"hooks": {
|
|
439
|
-
"afterCreate": "pnpm install && printf 'ready: %s\n' \"$GJI_PATH\""
|
|
440
|
-
}
|
|
441
|
-
}
|
|
109
|
+
../worktrees/<repo>/<branch>
|
|
442
110
|
```
|
|
443
111
|
|
|
444
|
-
|
|
112
|
+
That keeps editor bookmarks, scripts, and terminal navigation stable.
|
|
445
113
|
|
|
446
|
-
|
|
114
|
+
## More capabilities
|
|
447
115
|
|
|
448
|
-
|
|
449
|
-
// ~/.config/gji/config.json
|
|
450
|
-
{ "hooks": { "afterCreate": "nvm use", "afterEnter": "echo hi" } }
|
|
116
|
+
Use the documentation when you need to go beyond the core workflow:
|
|
451
117
|
|
|
452
|
-
|
|
453
|
-
|
|
118
|
+
- [Daily workflow](https://gji.solaqua.dev/docs/daily-workflow) — navigation, PRs, sync, and cleanup
|
|
119
|
+
- [Commands](https://gji.solaqua.dev/docs/commands) — complete command reference
|
|
120
|
+
- [Shell integration](https://gji.solaqua.dev/docs/shell-integration) — zsh, bash, and fish setup
|
|
121
|
+
- [Configuration](https://gji.solaqua.dev/docs/configuration) — paths, defaults, and local files
|
|
122
|
+
- [Hooks](https://gji.solaqua.dev/docs/hooks) — automate setup and cleanup
|
|
123
|
+
- [Sync and cleanup](https://gji.solaqua.dev/docs/sync-and-cleanup) — maintain active worktrees
|
|
124
|
+
- [Comparison](https://gji.solaqua.dev/docs/comparison) — `gji` vs `git worktree`, `lazygit`, and `ghq`
|
|
125
|
+
- [FAQ and troubleshooting](https://gji.solaqua.dev/docs/faq) — common questions and fixes
|
|
454
126
|
|
|
455
|
-
|
|
456
|
-
{ "hooks": { "beforeRemove": "echo bye" } }
|
|
457
|
-
|
|
458
|
-
// effective
|
|
459
|
-
{ "hooks": { "afterCreate": "npm install", "afterEnter": "echo hi", "beforeRemove": "echo bye" } }
|
|
460
|
-
```
|
|
461
|
-
|
|
462
|
-
### Triggering hooks manually
|
|
463
|
-
|
|
464
|
-
Run any hook in the current worktree on demand:
|
|
127
|
+
`gji` also supports JSON output for scripts and AI-assisted workflows:
|
|
465
128
|
|
|
466
129
|
```sh
|
|
467
|
-
gji
|
|
468
|
-
gji trigger-hook afterEnter # re-run the enter script
|
|
469
|
-
gji trigger-hook beforeRemove # dry-run the cleanup script
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
This is useful after cloning on a new machine, recovering a broken worktree, or letting an AI agent bootstrap an already-existing worktree without needing interactive prompts.
|
|
473
|
-
|
|
474
|
-
## Install prompt
|
|
475
|
-
|
|
476
|
-
For supported lockfiles, the dependency policy prompt above is the primary setup choice. Keep `after-create` hooks for project-specific work such as `pnpm run generate`, code generation, local-service setup, or environment-specific commands; hooks are not a second dependency-bootstrap configuration.
|
|
477
|
-
|
|
478
|
-
Projects without a supported dependency adapter can still use the legacy one-shot install prompt:
|
|
479
|
-
|
|
480
|
-
```
|
|
481
|
-
Run `pnpm install` in the new worktree?
|
|
482
|
-
› Yes run once
|
|
483
|
-
No skip this time
|
|
484
|
-
Always save as afterCreate hook
|
|
485
|
-
Never disable this prompt for this repo
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
**Always** saves `hooks.afterCreate`; **Never** writes `skipInstallPrompt: true`. Where they are saved depends on `installSaveTarget` (see [Available keys](#available-keys)) — defaults to `.gji.json`.
|
|
489
|
-
|
|
490
|
-
`syncDirs` remains generic and never suppresses installation or repair. To automate supported dependency/build setup, use `dependencyBootstrap`; the adapter always runs its lockfile/build repair after `syncFiles`. Explicit policies in global defaults, per-repo global config, or `.gji.json` always win over prompting.
|
|
491
|
-
|
|
492
|
-
## JSON output
|
|
493
|
-
|
|
494
|
-
Every mutating command supports `--json` for scripting and AI agent use. Success goes to stdout, errors go to stderr with exit code 1.
|
|
495
|
-
|
|
496
|
-
```sh
|
|
497
|
-
# create
|
|
130
|
+
gji --json
|
|
498
131
|
gji new --json feature/dark-mode
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
# fetch PR
|
|
502
|
-
gji pr --json 1234
|
|
503
|
-
# → { "branch": "pr/1234", "path": "/…/worktrees/repo/pr/1234", "repository": { "name": "repo", "root": "/…/repo" } }
|
|
504
|
-
|
|
505
|
-
# resolve an existing destination without changing directories
|
|
506
|
-
gji go --json feature/auth-refactor
|
|
507
|
-
# → { "branch": "feature/auth-refactor", "path": "/…/worktrees/repo/feature/auth-refactor", "repository": { "name": "repo", "root": "/…/repo" } }
|
|
508
|
-
|
|
509
|
-
# detailed list
|
|
510
|
-
gji ls --json
|
|
511
|
-
# → [{ "branch": "...", "status": "clean", "upstream": { "kind": "tracked", ... }, ... }]
|
|
512
|
-
|
|
513
|
-
# finish one worktree
|
|
514
|
-
gji done --json --force feature/dark-mode
|
|
515
|
-
# → { "branch": "feature/dark-mode", "path": "/…", "deleted": true }
|
|
516
|
-
|
|
517
|
-
# bulk clean
|
|
518
|
-
gji clean --json --force
|
|
519
|
-
# → { "removed": [{ "branch": "...", "path": "..." }, …] }
|
|
520
|
-
|
|
521
|
-
# stale-only clean
|
|
522
|
-
gji clean --stale --json --force
|
|
523
|
-
# → { "removed": [{ "branch": "...", "path": "..." }, …] }
|
|
524
|
-
|
|
525
|
-
# error shape (any command)
|
|
526
|
-
# stderr → { "error": "branch argument is required" }
|
|
132
|
+
gji go --json feature/dark-mode
|
|
527
133
|
```
|
|
528
134
|
|
|
529
|
-
|
|
135
|
+
Read the [full documentation](https://gji.solaqua.dev) for configuration,
|
|
136
|
+
dependency bootstrap, hooks, automation, and the complete CLI reference.
|
|
530
137
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
`gji ls --json` and `gji status --json` also produce structured output — see `gji status --json | jq` for the full schema.
|
|
534
|
-
|
|
535
|
-
## Non-interactive / CI mode
|
|
536
|
-
|
|
537
|
-
```sh
|
|
538
|
-
GJI_NO_TUI=1 gji new feature/ci-branch
|
|
539
|
-
GJI_NO_TUI=1 gji done --force feature/ci-branch
|
|
540
|
-
GJI_NO_TUI=1 gji clean --force
|
|
541
|
-
```
|
|
542
|
-
|
|
543
|
-
`GJI_NO_TUI=1` disables all prompts. Commands that need confirmation require their non-interactive approval flag (`--force` for cleanup commands, `--yes` for `doctor --fix`). `--json` implies the same behaviour.
|
|
544
|
-
|
|
545
|
-
`gji pr open --select` requires an interactive terminal; plain `gji pr open` opens the PR for the current worktree without prompting.
|
|
546
|
-
If the current worktree has no open PR or has multiple open PRs in headless mode, pass `gji pr open <branch|#N>` explicitly.
|
|
547
|
-
|
|
548
|
-
Update notifications are also suppressed automatically in non-interactive and `--json` runs. Users can opt out explicitly with `NO_UPDATE_NOTIFIER=1` or `--no-update-notifier`.
|
|
549
|
-
|
|
550
|
-
## Notes
|
|
138
|
+
---
|
|
551
139
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
- `gji pr` fetches from `origin` using the first matching forge ref namespace: GitHub `refs/pull/<number>/head`, GitLab `refs/merge-requests/<number>/head`, then Bitbucket `refs/pull-requests/<number>/from`
|
|
555
|
-
- `gji pr open` reads open PRs from the `origin` forge (GitHub, GitLab, or Bitbucket), preferring an installed authenticated provider CLI and falling back to its public API
|
|
140
|
+
If `gji` has saved you from a `git stash` spiral, a ⭐ on
|
|
141
|
+
[GitHub](https://github.com/sjquant/gji) helps other developers find it.
|
|
556
142
|
|
|
557
143
|
## License
|
|
558
144
|
|
package/dist/clean.js
CHANGED
|
@@ -2,6 +2,7 @@ import { confirm, isCancel } from "@clack/prompts";
|
|
|
2
2
|
import { loadEffectiveConfig } from "./config.js";
|
|
3
3
|
import { isBranchMergedInto, readWorktreeHealth, resolveRemoteDefaultBranch, runGit, } from "./git.js";
|
|
4
4
|
import { isHeadless } from "./headless.js";
|
|
5
|
+
import { releaseWorktreeSlot } from "./slots.js";
|
|
5
6
|
import { finalizeUndoOperation, recordUndoOperation } from "./undo.js";
|
|
6
7
|
import { formatLastCommit, formatUpstreamState, readWorktreeInfos, serializeWorktreeInfo, } from "./worktree-info.js";
|
|
7
8
|
import { deleteBranch, forceDeleteBranch, forceRemoveWorktree, isBranchUnmergedError, isSubmoduleWorktreeRemovalError, isWorktreeDeletionError, isWorktreeForceRemovalError, loadLinkedWorktrees, removeWorktree, } from "./worktree-management.js";
|
|
@@ -167,6 +168,7 @@ export function createCleanCommand(dependencies = {}) {
|
|
|
167
168
|
}
|
|
168
169
|
}
|
|
169
170
|
await finalizeUndoOperation(journal, removedWorktrees);
|
|
171
|
+
await Promise.all(removedWorktrees.map((worktree) => releaseWorktreeSlot(worktree.path)));
|
|
170
172
|
if (options.json) {
|
|
171
173
|
const removed = removedWorktrees.map((worktree) => {
|
|
172
174
|
const info = selectedInfoByPath.get(worktree.path);
|