git-worktrees 0.4.1__tar.gz → 0.4.2__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 (84) hide show
  1. git_worktrees-0.4.2/.claude/settings.json +6 -0
  2. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/.github/workflows/publish.yml +2 -4
  3. git_worktrees-0.4.2/.releasetools.yaml +23 -0
  4. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/CHANGELOG.md +4 -0
  5. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/PKG-INFO +1 -1
  6. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/docs/DEVELOPMENT.md +28 -14
  7. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/pyproject.toml +1 -1
  8. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/uv.lock +1 -1
  9. git_worktrees-0.4.1/.agents/skills/release/SKILL.md +0 -138
  10. git_worktrees-0.4.1/.claude/settings.json +0 -5
  11. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/.github/workflows/testpypi.yml +0 -0
  12. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/.github/workflows/tests.yml +0 -0
  13. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/.gitignore +0 -0
  14. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/.pre-commit-config.yaml +0 -0
  15. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/.python-version +0 -0
  16. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/AGENTS.md +0 -0
  17. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/LICENSE +0 -0
  18. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/README.md +0 -0
  19. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/completions/gw.fish +0 -0
  20. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/completions/gwa.fish +0 -0
  21. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/completions/gwh.fish +0 -0
  22. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/completions/gwl.fish +0 -0
  23. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/completions/gwm.fish +0 -0
  24. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/completions/gwnb.fish +0 -0
  25. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/completions/gwp.fish +0 -0
  26. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/completions/gwr.fish +0 -0
  27. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/completions/gwrot.fish +0 -0
  28. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/completions/gws.fish +0 -0
  29. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/conf.d/worktrees.fish +0 -0
  30. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/docs/BENCHMARK.md +0 -0
  31. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/docs/REFERENCE.md +0 -0
  32. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/functions/gwa.fish +0 -0
  33. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/functions/gwl.fish +0 -0
  34. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/functions/gwm.fish +0 -0
  35. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/functions/gwr.fish +0 -0
  36. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/hatch_build.py +0 -0
  37. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/renovate.json +0 -0
  38. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/scripts/README.md +0 -0
  39. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/scripts/benchmark.py +0 -0
  40. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/scripts/verify-publish.bash +0 -0
  41. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/src/worktrees/__init__.py +0 -0
  42. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/src/worktrees/cli.py +0 -0
  43. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/src/worktrees/errors.py +0 -0
  44. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/src/worktrees/forge.py +0 -0
  45. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/src/worktrees/git.py +0 -0
  46. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/src/worktrees/layout.py +0 -0
  47. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/src/worktrees/merged.py +0 -0
  48. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/src/worktrees/new_branch.py +0 -0
  49. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/src/worktrees/pick.py +0 -0
  50. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/src/worktrees/prune.py +0 -0
  51. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/src/worktrees/render.py +0 -0
  52. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/src/worktrees/repo.py +0 -0
  53. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/src/worktrees/rotate.py +0 -0
  54. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/src/worktrees/verdicts.py +0 -0
  55. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/src/worktrees/worktree.py +0 -0
  56. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/tests/conftest.py +0 -0
  57. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/tests/test_benchmark.py +0 -0
  58. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/tests/test_cli.py +0 -0
  59. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/tests/test_completions.py +0 -0
  60. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/tests/test_fixture.py +0 -0
  61. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/tests/test_forge.py +0 -0
  62. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/tests/test_gates.py +0 -0
  63. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/tests/test_new_branch.py +0 -0
  64. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/tests/test_render.py +0 -0
  65. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/tests/test_rotate.py +0 -0
  66. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/tests/test_shims.py +0 -0
  67. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/tests/test_spec.py +0 -0
  68. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/tests/test_version.py +0 -0
  69. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/tests/test_worktree.py +0 -0
  70. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/zsh/plugins/worktrees/completions/_gw +0 -0
  71. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/zsh/plugins/worktrees/completions/_gwa +0 -0
  72. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/zsh/plugins/worktrees/completions/_gwh +0 -0
  73. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/zsh/plugins/worktrees/completions/_gwl +0 -0
  74. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/zsh/plugins/worktrees/completions/_gwm +0 -0
  75. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/zsh/plugins/worktrees/completions/_gwnb +0 -0
  76. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/zsh/plugins/worktrees/completions/_gwp +0 -0
  77. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/zsh/plugins/worktrees/completions/_gwr +0 -0
  78. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/zsh/plugins/worktrees/completions/_gwrot +0 -0
  79. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/zsh/plugins/worktrees/completions/_gws +0 -0
  80. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/zsh/plugins/worktrees/functions/gwa +0 -0
  81. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/zsh/plugins/worktrees/functions/gwl +0 -0
  82. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/zsh/plugins/worktrees/functions/gwm +0 -0
  83. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/zsh/plugins/worktrees/functions/gwr +0 -0
  84. {git_worktrees-0.4.1 → git_worktrees-0.4.2}/zsh/plugins/worktrees/worktrees.plugin.zsh +0 -0
@@ -0,0 +1,6 @@
1
+ {
2
+ "enabledPlugins": {
3
+ "release-notes@release-tools": true,
4
+ "release@release-tools": true
5
+ }
6
+ }
@@ -144,8 +144,7 @@ jobs:
144
144
  uses: astral-sh/setup-uv@ae62891fec2bb8e7d6c99fc78c9fec3a63790f8d # v10.0.0
145
145
  with:
146
146
  python-version: "3.14"
147
- enable-cache: true
148
- cache-suffix: ${{ github.workflow }}-${{ github.job }}
147
+ enable-cache: false
149
148
 
150
149
  - name: Download distributions
151
150
  uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
@@ -179,8 +178,7 @@ jobs:
179
178
  uses: astral-sh/setup-uv@ae62891fec2bb8e7d6c99fc78c9fec3a63790f8d # v10.0.0
180
179
  with:
181
180
  python-version: "3.14"
182
- enable-cache: true
183
- cache-suffix: ${{ github.workflow }}-${{ github.job }}
181
+ enable-cache: false
184
182
 
185
183
  - name: Verify it installs from PyPI
186
184
  run: scripts/verify-publish.bash --prod
@@ -0,0 +1,23 @@
1
+ # How this repository releases, read by every releasetools tool.
2
+ #
3
+ # Conventions: https://github.com/releasetools/conventions
4
+ #
5
+ # One project: the distribution is `git-worktrees`, which is not the name of
6
+ # this repository and not the package anything imports. PyPI already holds a
7
+ # `worktrees` belonging to somebody else, so the registry URL names the
8
+ # distribution rather than either of the others.
9
+ projects:
10
+ - path: ./
11
+ manifest: pyproject.toml
12
+ changelog: CHANGELOG.md
13
+ bump: uv version {version}
14
+
15
+ release:
16
+ branch: main
17
+ # GitHub replays the author's commits unsigned on a rebase merge, and the
18
+ # `main` ruleset requires signed commits and linear history, so a squash is
19
+ # the only one it takes. It is signed by GitHub's web-flow key.
20
+ merge: squash
21
+ checks: tests.yml
22
+ publish: publish.yml
23
+ registry: https://pypi.org/pypi/git-worktrees/{version}/json
@@ -17,6 +17,10 @@ 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.2 - 2026-09-22
21
+
22
+ CLI behavior is unchanged from 0.4.1.
23
+
20
24
  ## 0.4.1 - 2026-09-21
21
25
 
22
26
  CLI behavior is unchanged from 0.4.0.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: git-worktrees
3
- Version: 0.4.1
3
+ Version: 0.4.2
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
@@ -152,36 +152,50 @@ network. `GIT_CONFIG_GLOBAL` carries that: without it git still reads
152
152
  ## Publishing a version
153
153
 
154
154
  ```console
155
- /release 0.2.0
155
+ /release:cut 0.2.0
156
156
  ```
157
157
 
158
- The skill at `.agents/skills/release/` does the whole of it: cut
159
- `release/v0.2.0` from `origin/main`, `uv version 0.2.0`, open the pull
160
- request, wait for its checks, merge with `--rebase`, wait for main's own run
161
- on the rebased commit, and only then tag. The tag lands on a commit already
162
- proved green, so it never has to move.
158
+ That does the whole of it: cut `release/v0.2.0` from `origin/main`,
159
+ `uv version 0.2.0`, open the pull request, wait for its checks, squash-merge,
160
+ wait for main's own run on the merged commit, and only then tag. The tag lands
161
+ on a commit already proved green, so it never has to move.
162
+
163
+ What each step needs is in `.releasetools.yaml`: the branch, the squash, the
164
+ workflow that has to be green, the workflow the tag starts, the URL that must
165
+ not already carry the version, and the command that sets it. The keys are the
166
+ [releasetools conventions](https://github.com/releasetools/conventions/blob/main/FORMAT.md),
167
+ so the guards and the release read the same file.
168
+
169
+ The squash is not a preference. The `main` ruleset requires signed commits and
170
+ linear history: GitHub replays the author's commits unsigned on a rebase merge
171
+ and refuses with `Base branch requires signed commits`, and a merge commit is
172
+ not linear. A squash is one commit, signed by GitHub's web-flow key, and its
173
+ subject becomes `Release 0.2.0 (#NN)`.
163
174
 
164
175
  `rt release::prechecks` runs first and refuses a version that is not `x.y.z`,
165
176
  a dirty tree, a tag that already exists on the remote, a version that is not
166
177
  after the newest release tag, a commit that is not on main, and a version PyPI
167
178
  already carries. That last one matters most: PyPI rejects a duplicate at the
168
- very end of a publish run, after everything else has already happened.
179
+ very end of a publish run, after everything else has already happened. The
180
+ distribution is `git-worktrees`; PyPI's `worktrees` belongs to somebody else.
169
181
 
170
182
  `/release-notes:prepare` writes the `CHANGELOG.md` entry on the release branch,
171
- so the notes are reviewed in the same pull request as the version bump. It
172
- comes from the release-tools marketplace:
183
+ so the notes are reviewed in the same pull request as the version bump. Both
184
+ commands come from the release-tools marketplace:
173
185
 
174
186
  ```console
175
187
  claude plugin marketplace add releasetools/agent-plugins --scope project
188
+ claude plugin install release@release-tools --scope project
176
189
  claude plugin install release-notes@release-tools --scope project
177
190
  ```
178
191
 
179
- `--scope project` declares it in this repository rather than in your own
180
- configuration, so the next person to release is offered the same plugin.
192
+ `--scope project` declares them in this repository rather than in your own
193
+ configuration, so the next person to release is offered the same plugins.
194
+ `rt` has to be v0.4.0 or newer, which is where `version::bump` arrived.
181
195
 
182
- `publish.yml` reads that section back out for the GitHub release, and `build`
183
- refuses a tag whose version has no section, before anything is published.
184
- Nothing is generated from pull request titles.
196
+ `publish.yml` reads that changelog section back out for the GitHub release,
197
+ and `build` refuses a tag whose version has no section, before anything is
198
+ published. Nothing is generated from pull request titles.
185
199
 
186
200
  By hand it is the same four commands:
187
201
 
@@ -9,7 +9,7 @@ authors = [
9
9
  ]
10
10
  # Static, and the single source of truth for the version. Bump it in a pull
11
11
  # request and run `uv lock`; the release tag only has to agree with it.
12
- version = "0.4.1"
12
+ version = "0.4.2"
13
13
  # The standard library answers every question this asks. A dependency here
14
14
  # would be paid on every invocation, and an invocation is 67 ms of which 25 ms
15
15
  # is the interpreter starting.
@@ -40,7 +40,7 @@ wheels = [
40
40
 
41
41
  [[package]]
42
42
  name = "git-worktrees"
43
- version = "0.4.1"
43
+ version = "0.4.2"
44
44
  source = { editable = "." }
45
45
 
46
46
  [package.optional-dependencies]
@@ -1,138 +0,0 @@
1
- ---
2
- name: release
3
- description: Release a version of this package to PyPI. Bumps the version on a release branch, opens and merges the pull request once its checks pass, then tags the merged commit so publish.yml uploads it. Use when the user says "release", "cut a release", "ship x.y.z", or "/release x.y.z".
4
- user-invocable: true
5
- allowed-tools: Bash(git:*), Bash(gh:*), Bash(uv:*), Bash(rt:*), Bash(scripts/*.bash:*)
6
- ---
7
-
8
- # release
9
-
10
- Release `$ARGUMENTS` of this package. The argument is the version, with or
11
- without a leading `v`; strip it and use the bare `x.y.z` everywhere below.
12
-
13
- With no argument, ask which version. Do not guess one from the commits.
14
-
15
- Every step is one command. Run them in order, read what each says before
16
- running the next, and stop at the first failure rather than working around
17
- it. Nothing here is worth improvising: a release that goes wrong is on PyPI
18
- forever.
19
-
20
- ## 1. Everything that has to be true first
21
-
22
- ```bash
23
- git fetch --all --prune
24
- rt release::prechecks <version> \
25
- --branch main \
26
- --check-registry-url "https://pypi.org/pypi/$(uv version | cut -d' ' -f1)/<version>/json"
27
- ```
28
-
29
- That checks the shape of the version, a clean working tree, that the tag is
30
- free on the remote, that the version is after the newest release tag, that
31
- HEAD is on main, and that PyPI does not already carry it. If it refuses, say
32
- what it said and stop. Do not fix a dirty tree by stashing on the user's
33
- behalf.
34
-
35
- `rt` is `releasetools/cli`, installed with `brew install releasetools/tap/releasetools-cli`
36
- or the installer in its README. Every check it runs refuses when it cannot
37
- prove what it was asked to prove, so a doubtful answer stops the release
38
- rather than passing it.
39
-
40
- ## 2. The branch, the notes, and the bump
41
-
42
- ```bash
43
- git switch --create release/v<version> --no-track origin/main
44
- ```
45
-
46
- Then run `/release-notes:prepare <version>`, from the ReleaseTools plugin. It
47
- rules on every commit since the previous tag, writes the body to
48
- `.git/RELEASE_EDITMSG`, and puts the entry in `CHANGELOG.md` under
49
- `## <version> - <date>`. It shows the draft and waits before its last step,
50
- so the user changes it there.
51
-
52
- Do not write that entry by hand and do not skip it: `publish.yml` reads the
53
- section back out for the GitHub release, and `build` refuses a tag whose
54
- version has no section.
55
-
56
- ```bash
57
- uv version <version>
58
- git commit --all --message "Release <version>"
59
- git push --set-upstream origin refs/heads/release/v<version>
60
- ```
61
-
62
- `uv version` rewrites `pyproject.toml` and re-locks, so the commit carries
63
- those two files and `CHANGELOG.md`. Check that with `git show --stat`
64
- before pushing: a commit
65
- missing `uv.lock` fails `uv sync --locked` in CI, and it fails after the
66
- merge rather than before it.
67
-
68
- Branch from `origin/main` rather than from `main`, so a stale local copy
69
- cannot become the release.
70
-
71
- ## 3. The pull request, and its checks
72
-
73
- ```bash
74
- gh pr create --base main --title "Release <version>" --body "..."
75
- gh pr checks --watch --fail-fast
76
- ```
77
-
78
- The body is the changelog entry just written. It is already the summary,
79
- already reviewed by the reader, and writing a second one invites the two to
80
- disagree.
81
-
82
- `--watch` blocks. When it reports a failure, report which check failed and
83
- its URL, and stop. The branch and the pull request stay; nothing has been
84
- tagged and nothing published.
85
-
86
- ## 4. Merge, then wait for main
87
-
88
- ```bash
89
- gh pr merge --squash --delete-branch
90
- git switch main && git pull --ff-only
91
- rt github::await_workflow "$(git rev-parse HEAD)" tests.yml
92
- ```
93
-
94
- `--squash`, because the `main` ruleset requires signed commits and linear
95
- history: GitHub cannot sign the commits a rebase merge writes and refuses it
96
- with `Base branch requires signed commits`, and a merge commit is off. A
97
- squash is signed by GitHub's web-flow key, which is expected here and not
98
- something to route around. The subject becomes `Release <version> (#NN)`.
99
-
100
- The wait matters. A squash onto a main that moved is a tree neither the
101
- branch nor main has tested, and the tag must only ever land on a commit
102
- already proved green. `github::await_workflow` blocks until `tests.yml` finishes
103
- on that commit and exits non-zero if it failed.
104
-
105
- If it failed: `main` now carries the version bump and no release exists. Say
106
- so plainly. The fix is another pull request, and then this skill again at the
107
- same version, since no tag was created.
108
-
109
- ## 5. Tag, which is what publishes
110
-
111
- ```bash
112
- git tag --annotate v<version> --message "v<version>"
113
- git push origin refs/tags/v<version>
114
- gh run watch "$(gh run list --workflow publish.yml --limit 1 --json databaseId --jq '.[0].databaseId')" --exit-status
115
- ```
116
-
117
- Pushing the tag is the release. `publish.yml` re-checks the tag against
118
- `pyproject.toml`, that the commit is on `main`, and the tests, then builds
119
- once, installs the wheel it built and uploads it to PyPI. There is no
120
- TestPyPI upload here; `testpypi.yml` published this commit when the merge put
121
- it on `main`.
122
-
123
- `release` needs that upload alone, so the GitHub release appears while
124
- `verify` is still installing from PyPI. A red `verify` under a green
125
- `publish` means the index has not caught up, not that the version is
126
- missing.
127
-
128
- Report the PyPI URL and the GitHub release URL when it finishes.
129
-
130
- ## What this never does
131
-
132
- Move a tag. A tag names one commit forever; a version that needs a second
133
- attempt gets the next number. If `publish.yml` fails *after* the PyPI upload,
134
- in `verify` or `release`, re-run it with
135
- `gh workflow run publish.yml --ref v<version>` rather than re-tagging.
136
-
137
- Delete a release branch that has not merged, stash the user's work, force
138
- anything, or retry a failed check by re-running it in the hope it passes.
@@ -1,5 +0,0 @@
1
- {
2
- "enabledPlugins": {
3
- "release-notes@release-tools": true
4
- }
5
- }
File without changes
File without changes
File without changes
File without changes