git-worktrees 0.3.1__tar.gz → 0.4.0__tar.gz

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 (82) hide show
  1. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/CHANGELOG.md +27 -0
  2. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/PKG-INFO +33 -5
  3. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/README.md +32 -4
  4. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/docs/DEVELOPMENT.md +3 -1
  5. git_worktrees-0.4.0/docs/REFERENCE.md +438 -0
  6. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/pyproject.toml +1 -1
  7. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/src/worktrees/cli.py +53 -12
  8. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/src/worktrees/forge.py +9 -0
  9. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/src/worktrees/layout.py +37 -0
  10. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/src/worktrees/new_branch.py +4 -1
  11. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/src/worktrees/prune.py +6 -1
  12. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/tests/conftest.py +16 -0
  13. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/tests/test_cli.py +112 -1
  14. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/tests/test_completions.py +45 -0
  15. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/tests/test_forge.py +114 -0
  16. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/tests/test_gates.py +31 -0
  17. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/tests/test_shims.py +28 -0
  18. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/tests/test_worktree.py +40 -0
  19. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/uv.lock +1 -1
  20. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/.agents/skills/release/SKILL.md +0 -0
  21. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/.claude/settings.json +0 -0
  22. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/.github/workflows/publish.yml +0 -0
  23. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/.github/workflows/testpypi.yml +0 -0
  24. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/.github/workflows/tests.yml +0 -0
  25. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/.gitignore +0 -0
  26. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/.pre-commit-config.yaml +0 -0
  27. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/.python-version +0 -0
  28. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/AGENTS.md +0 -0
  29. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/LICENSE +0 -0
  30. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/completions/gw.fish +0 -0
  31. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/completions/gwa.fish +0 -0
  32. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/completions/gwh.fish +0 -0
  33. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/completions/gwl.fish +0 -0
  34. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/completions/gwm.fish +0 -0
  35. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/completions/gwnb.fish +0 -0
  36. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/completions/gwp.fish +0 -0
  37. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/completions/gwr.fish +0 -0
  38. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/completions/gwrot.fish +0 -0
  39. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/completions/gws.fish +0 -0
  40. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/conf.d/worktrees.fish +0 -0
  41. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/docs/BENCHMARK.md +0 -0
  42. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/functions/gwa.fish +0 -0
  43. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/functions/gwl.fish +0 -0
  44. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/functions/gwm.fish +0 -0
  45. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/functions/gwr.fish +0 -0
  46. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/hatch_build.py +0 -0
  47. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/renovate.json +0 -0
  48. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/scripts/README.md +0 -0
  49. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/scripts/benchmark.py +0 -0
  50. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/scripts/verify-publish.bash +0 -0
  51. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/src/worktrees/__init__.py +0 -0
  52. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/src/worktrees/errors.py +0 -0
  53. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/src/worktrees/git.py +0 -0
  54. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/src/worktrees/merged.py +0 -0
  55. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/src/worktrees/pick.py +0 -0
  56. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/src/worktrees/render.py +0 -0
  57. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/src/worktrees/repo.py +0 -0
  58. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/src/worktrees/rotate.py +0 -0
  59. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/src/worktrees/verdicts.py +0 -0
  60. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/src/worktrees/worktree.py +0 -0
  61. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/tests/test_benchmark.py +0 -0
  62. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/tests/test_fixture.py +0 -0
  63. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/tests/test_new_branch.py +0 -0
  64. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/tests/test_render.py +0 -0
  65. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/tests/test_rotate.py +0 -0
  66. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/tests/test_spec.py +0 -0
  67. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/tests/test_version.py +0 -0
  68. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/zsh/plugins/worktrees/completions/_gw +0 -0
  69. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/zsh/plugins/worktrees/completions/_gwa +0 -0
  70. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/zsh/plugins/worktrees/completions/_gwh +0 -0
  71. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/zsh/plugins/worktrees/completions/_gwl +0 -0
  72. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/zsh/plugins/worktrees/completions/_gwm +0 -0
  73. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/zsh/plugins/worktrees/completions/_gwnb +0 -0
  74. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/zsh/plugins/worktrees/completions/_gwp +0 -0
  75. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/zsh/plugins/worktrees/completions/_gwr +0 -0
  76. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/zsh/plugins/worktrees/completions/_gwrot +0 -0
  77. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/zsh/plugins/worktrees/completions/_gws +0 -0
  78. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/zsh/plugins/worktrees/functions/gwa +0 -0
  79. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/zsh/plugins/worktrees/functions/gwl +0 -0
  80. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/zsh/plugins/worktrees/functions/gwm +0 -0
  81. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/zsh/plugins/worktrees/functions/gwr +0 -0
  82. {git_worktrees-0.3.1 → git_worktrees-0.4.0}/zsh/plugins/worktrees/worktrees.plugin.zsh +0 -0
@@ -17,6 +17,33 @@ not in here, whatever it cost to build.
17
17
  A release closes with a `### Choices` section when a decision in it is worth
18
18
  the reader's time: what was chosen, and what the alternative failed to do.
19
19
 
20
+ ## 0.4.0 - 2026-09-21
21
+
22
+ ### Security
23
+
24
+ Forge queries ignore `GH_REPO` and `GITLAB_REPO`, so a merged request in
25
+ another repository cannot authorize removal here.
26
+
27
+ Printed branch restoration commands and `gwnb` checkout hints quote branch
28
+ names so shell metacharacters are treated as part of the name.
29
+
30
+ ### Added
31
+
32
+ `gws` reports how many worktrees under the shared `.worktrees` directory
33
+ belong to other repositories, with the count in `gws --json` as `neighbours`.
34
+
35
+ ### Fixed
36
+
37
+ After a failed fetch, worktree assessments use local refs and skip forge
38
+ queries.
39
+
40
+ `gwl` and `gwr` shell completions omit paths containing newlines, which
41
+ cannot fit their one-row-per-line format; those worktrees remain reachable
42
+ by name or path.
43
+
44
+ Pressing Ctrl-C at a worktree selection or removal prompt exits with code
45
+ 130 and no traceback. No worktree is selected or removed.
46
+
20
47
  ## 0.3.1 - 2026-09-20
21
48
 
22
49
  `gws` and `gwp` list the main checkout, and `gwl`'s picker shows the
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: git-worktrees
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: Git worktree commands that refuse to lose work.
5
5
  Project-URL: Bug reports, https://github.com/MihaiBojin/worktrees/issues/new
6
6
  Project-URL: Source, https://github.com/MihaiBojin/worktrees
@@ -64,6 +64,10 @@ function, because a binary cannot change its caller's directory.
64
64
 
65
65
  `worktrees` is the same program under its long name.
66
66
 
67
+ Ctrl-C interrupts a running command with exit code 130 and no traceback.
68
+ At a selection or removal prompt, it cancels without choosing or removing
69
+ a worktree.
70
+
67
71
  `gws` and `gwp` are what this tool is for and their behaviour is settled.
68
72
 
69
73
  **`gwnb` and `gwrot` are alpha and may go.** They start branches rather than
@@ -160,6 +164,12 @@ subcommand and shorthand, `gwl --complete` prints every worktree, and both
160
164
  shells narrow what those return, so the matching stays in one place and a
161
165
  command added to the table needs no edit in either shell.
162
166
 
167
+ One row a line, `label<TAB>path`. A worktree whose path holds a newline is
168
+ left out of that listing, because both shells would read it as two rows and
169
+ offer the tail as a worktree of its own. `gwa` cannot make such a path, since
170
+ it derives from a branch name and git refuses a newline in a ref, and the
171
+ worktree is still reachable by name or path.
172
+
163
173
  Neither manager puts a binary on `$PATH`, which is why the two installs stay
164
174
  separate.
165
175
 
@@ -175,6 +185,7 @@ unknown never-pushed not merged into origin/main, and no upstream says whethe
175
185
  remove squash-merged squash-merged /home/you/git/.worktrees/squash-merged/repo
176
186
 
177
187
  1 removable, 3 kept, 1 unclear
188
+ 2 worktree(s) under /home/you/git/.worktrees belong to another repository
178
189
  unclear, and gwp does not touch these: never-pushed
179
190
  gwp removes the 1 marked removable
180
191
  ```
@@ -184,7 +195,13 @@ so the table shows what `git worktree list` shows; nothing proposes it, and
184
195
  `git worktree remove` answers `fatal: '<path>' is a main working tree`
185
196
  whatever flag it is given. Paths are absolute wherever this
186
197
  prints one, so a row can be pasted into the next command. The table and the
187
- count are on stdout; the two lines after them are on stderr.
198
+ count are on stdout; everything after them is on stderr.
199
+
200
+ Every repository in the same parent directory keeps its worktrees under that
201
+ one `.worktrees` root, so some of the directories in there are a sibling's.
202
+ `gws` counts those and says so, because nothing else does, and `--json`
203
+ carries the same count as `neighbours`. No command here reads or removes
204
+ them, and the count comes from walking the root rather than from asking git.
188
205
 
189
206
  On a terminal the verdict carries its own colour, `remove` green, `keep` blue
190
207
  and `unknown` yellow, with the branch in bold and the path dimmed. That
@@ -208,7 +225,13 @@ squashes, so the intermediate state it holds differs from the final one in
208
225
  the same regions, and a diff cannot separate a stale branch from one with
209
226
  work left. A merged pull request settles it, cross-checked against the
210
227
  commits an upstream has not got, because a request speaks for what reached
211
- it and nothing about what never did. `--no-forge` decides from git alone.
228
+ it and nothing about what never did. `--no-forge` decides from git alone, and
229
+ so does a run whose fetch just failed.
230
+
231
+ The question goes to the repository the command is standing in and nowhere
232
+ else. `GH_REPO` and `GITLAB_REPO` beat that directory, so both are dropped
233
+ before `gh` or `glab` runs; everything else in the environment, the token
234
+ included, is passed through.
212
235
 
213
236
  A record left behind by a directory somebody deleted by hand is nobody's
214
237
  verdict. `gws` names how many there are; clearing them is `git worktree prune`,
@@ -452,7 +475,10 @@ print one thing each and have nothing to be quiet about, takes `--json`, `-q`,
452
475
 
453
476
  A remote that cannot be reached is not fatal anywhere. The fetch fails, the
454
477
  command says so on stderr, and it answers from the refs already here, which is
455
- where `--no-fetch` sends it on request.
478
+ where `--no-fetch` sends it on request. The forge is not asked either: it is
479
+ over the same network, and `gh` waits 30 seconds before saying so, once per
480
+ branch. `--no-fetch` alone says nothing about the network, so it leaves the
481
+ forge asked.
456
482
 
457
483
  Data goes to stdout and diagnostics to stderr, the prompt included, so `--json`
458
484
  is parseable in every mode. Colour is decided per stream and only for a
@@ -507,7 +533,9 @@ is refused with them: it deletes refs without `-d` appearing at all.
507
533
  The Python, the tests and the release procedure are in
508
534
  [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md). The rules the code follows are in
509
535
  [AGENTS.md](AGENTS.md). What changed in each release is in
510
- [CHANGELOG.md](CHANGELOG.md).
536
+ [CHANGELOG.md](CHANGELOG.md). What was decided and what must not break,
537
+ including the alternatives that were closed, is in
538
+ [docs/REFERENCE.md](docs/REFERENCE.md).
511
539
 
512
540
  ## Licence
513
541
 
@@ -38,6 +38,10 @@ function, because a binary cannot change its caller's directory.
38
38
 
39
39
  `worktrees` is the same program under its long name.
40
40
 
41
+ Ctrl-C interrupts a running command with exit code 130 and no traceback.
42
+ At a selection or removal prompt, it cancels without choosing or removing
43
+ a worktree.
44
+
41
45
  `gws` and `gwp` are what this tool is for and their behaviour is settled.
42
46
 
43
47
  **`gwnb` and `gwrot` are alpha and may go.** They start branches rather than
@@ -134,6 +138,12 @@ subcommand and shorthand, `gwl --complete` prints every worktree, and both
134
138
  shells narrow what those return, so the matching stays in one place and a
135
139
  command added to the table needs no edit in either shell.
136
140
 
141
+ One row a line, `label<TAB>path`. A worktree whose path holds a newline is
142
+ left out of that listing, because both shells would read it as two rows and
143
+ offer the tail as a worktree of its own. `gwa` cannot make such a path, since
144
+ it derives from a branch name and git refuses a newline in a ref, and the
145
+ worktree is still reachable by name or path.
146
+
137
147
  Neither manager puts a binary on `$PATH`, which is why the two installs stay
138
148
  separate.
139
149
 
@@ -149,6 +159,7 @@ unknown never-pushed not merged into origin/main, and no upstream says whethe
149
159
  remove squash-merged squash-merged /home/you/git/.worktrees/squash-merged/repo
150
160
 
151
161
  1 removable, 3 kept, 1 unclear
162
+ 2 worktree(s) under /home/you/git/.worktrees belong to another repository
152
163
  unclear, and gwp does not touch these: never-pushed
153
164
  gwp removes the 1 marked removable
154
165
  ```
@@ -158,7 +169,13 @@ so the table shows what `git worktree list` shows; nothing proposes it, and
158
169
  `git worktree remove` answers `fatal: '<path>' is a main working tree`
159
170
  whatever flag it is given. Paths are absolute wherever this
160
171
  prints one, so a row can be pasted into the next command. The table and the
161
- count are on stdout; the two lines after them are on stderr.
172
+ count are on stdout; everything after them is on stderr.
173
+
174
+ Every repository in the same parent directory keeps its worktrees under that
175
+ one `.worktrees` root, so some of the directories in there are a sibling's.
176
+ `gws` counts those and says so, because nothing else does, and `--json`
177
+ carries the same count as `neighbours`. No command here reads or removes
178
+ them, and the count comes from walking the root rather than from asking git.
162
179
 
163
180
  On a terminal the verdict carries its own colour, `remove` green, `keep` blue
164
181
  and `unknown` yellow, with the branch in bold and the path dimmed. That
@@ -182,7 +199,13 @@ squashes, so the intermediate state it holds differs from the final one in
182
199
  the same regions, and a diff cannot separate a stale branch from one with
183
200
  work left. A merged pull request settles it, cross-checked against the
184
201
  commits an upstream has not got, because a request speaks for what reached
185
- it and nothing about what never did. `--no-forge` decides from git alone.
202
+ it and nothing about what never did. `--no-forge` decides from git alone, and
203
+ so does a run whose fetch just failed.
204
+
205
+ The question goes to the repository the command is standing in and nowhere
206
+ else. `GH_REPO` and `GITLAB_REPO` beat that directory, so both are dropped
207
+ before `gh` or `glab` runs; everything else in the environment, the token
208
+ included, is passed through.
186
209
 
187
210
  A record left behind by a directory somebody deleted by hand is nobody's
188
211
  verdict. `gws` names how many there are; clearing them is `git worktree prune`,
@@ -426,7 +449,10 @@ print one thing each and have nothing to be quiet about, takes `--json`, `-q`,
426
449
 
427
450
  A remote that cannot be reached is not fatal anywhere. The fetch fails, the
428
451
  command says so on stderr, and it answers from the refs already here, which is
429
- where `--no-fetch` sends it on request.
452
+ where `--no-fetch` sends it on request. The forge is not asked either: it is
453
+ over the same network, and `gh` waits 30 seconds before saying so, once per
454
+ branch. `--no-fetch` alone says nothing about the network, so it leaves the
455
+ forge asked.
430
456
 
431
457
  Data goes to stdout and diagnostics to stderr, the prompt included, so `--json`
432
458
  is parseable in every mode. Colour is decided per stream and only for a
@@ -481,7 +507,9 @@ is refused with them: it deletes refs without `-d` appearing at all.
481
507
  The Python, the tests and the release procedure are in
482
508
  [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md). The rules the code follows are in
483
509
  [AGENTS.md](AGENTS.md). What changed in each release is in
484
- [CHANGELOG.md](CHANGELOG.md).
510
+ [CHANGELOG.md](CHANGELOG.md). What was decided and what must not break,
511
+ including the alternatives that were closed, is in
512
+ [docs/REFERENCE.md](docs/REFERENCE.md).
485
513
 
486
514
  ## Licence
487
515
 
@@ -24,7 +24,9 @@ invisible to it, so CI is the first thing to format a file you just wrote.
24
24
 
25
25
 
26
26
  The rules this code follows, and the reasoning behind them, are in
27
- [AGENTS.md](../AGENTS.md). This file is what to run.
27
+ [AGENTS.md](../AGENTS.md). What was decided, what must not break and which
28
+ failure classes have a test are in [REFERENCE.md](REFERENCE.md). This file is
29
+ what to run.
28
30
 
29
31
  ## Layout
30
32