carson 2.31.0 → 2.32.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.
- checksums.yaml +4 -4
- data/RELEASE.md +11 -0
- data/VERSION +1 -1
- data/lib/carson/runtime/local/prune.rb +41 -6
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 99666417783ceb949cdef39bbf1595465bf0a5f674607229b4b937a4ae8b6197
|
|
4
|
+
data.tar.gz: a8e55f943e2ab34a26d50b0468e10cecbdbf5879eaeef1a7323e99e80715dac3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2342dcf7bde01d3632741e76adaefe6c499a03a36d11bda476870419e43f87caa51ae9837fc5f1cdbbc9b5c083b4b2058824fc5c0f346788ca7f2658aecbe2ab
|
|
7
|
+
data.tar.gz: f0f8fe556fa65044b3789a45cd25d1fc354e2865a5b923843bf3249a30259bac989eb74f0cb5bb1ff2072c4dc548911ca5f5d26d13da933baceb70161a527993
|
data/RELEASE.md
CHANGED
|
@@ -5,6 +5,17 @@ Release-note scope rule:
|
|
|
5
5
|
- `RELEASE.md` records only version deltas, breaking changes, and migration actions.
|
|
6
6
|
- Operational usage guides live in `MANUAL.md` and `API.md`.
|
|
7
7
|
|
|
8
|
+
## 2.32.0 — Worktree-Aware Pruning
|
|
9
|
+
|
|
10
|
+
### What changed
|
|
11
|
+
|
|
12
|
+
- **Prune now clears worktrees that block branch deletion.** When a branch is checked out in a worktree, `carson prune` safely removes the worktree first (refuses if uncommitted changes exist), then deletes the branch. Previously, these branches were silently skipped.
|
|
13
|
+
- **Honest skip reporting.** Non-verbose output no longer says "No stale branches" when branches were detected but couldn't be pruned. Shows "Skipped N branch(es)" or "Pruned N, skipped M" as appropriate, with a `--verbose` hint.
|
|
14
|
+
|
|
15
|
+
### Migration
|
|
16
|
+
|
|
17
|
+
- No action required. Existing prune behaviour is strictly improved.
|
|
18
|
+
|
|
8
19
|
## 2.31.0 — Worktree Lifecycle + Prune --all
|
|
9
20
|
|
|
10
21
|
### What changed
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.
|
|
1
|
+
2.32.0
|
|
@@ -25,11 +25,15 @@ module Carson
|
|
|
25
25
|
puts_verbose "prune_summary: deleted=#{counters.fetch( :deleted )} skipped=#{counters.fetch( :skipped )}"
|
|
26
26
|
unless verbose?
|
|
27
27
|
deleted_count = counters.fetch( :deleted )
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
skipped_count = counters.fetch( :skipped )
|
|
29
|
+
message = if deleted_count > 0 && skipped_count > 0
|
|
30
|
+
"Pruned #{deleted_count}, skipped #{skipped_count} (--verbose for details)."
|
|
31
|
+
elsif deleted_count > 0
|
|
32
|
+
"Pruned #{deleted_count} stale branch#{plural_suffix( count: deleted_count )}."
|
|
30
33
|
else
|
|
31
|
-
|
|
34
|
+
"Skipped #{skipped_count} branch#{plural_suffix( count: skipped_count )} (--verbose for details)."
|
|
32
35
|
end
|
|
36
|
+
puts_line message
|
|
33
37
|
end
|
|
34
38
|
EXIT_OK
|
|
35
39
|
end
|
|
@@ -93,7 +97,7 @@ module Carson
|
|
|
93
97
|
)
|
|
94
98
|
return prune_force_delete_skipped( branch: branch, upstream: upstream, delete_error_text: delete_error_text, force_error: force_error ) if merged_pr.nil?
|
|
95
99
|
|
|
96
|
-
force_stdout, force_stderr, force_success
|
|
100
|
+
force_stdout, force_stderr, force_success = force_delete_local_branch( branch: branch )
|
|
97
101
|
return prune_force_delete_success( branch: branch, upstream: upstream, merged_pr: merged_pr, force_stdout: force_stdout ) if force_success
|
|
98
102
|
|
|
99
103
|
prune_force_delete_failed( branch: branch, upstream: upstream, force_stderr: force_stderr )
|
|
@@ -122,6 +126,37 @@ module Carson
|
|
|
122
126
|
text.empty? ? "unknown error" : text
|
|
123
127
|
end
|
|
124
128
|
|
|
129
|
+
# Attempts git branch -D. If blocked by a worktree, safely removes the worktree
|
|
130
|
+
# first (no --force — refuses if worktree has uncommitted changes) and retries.
|
|
131
|
+
def force_delete_local_branch( branch: )
|
|
132
|
+
stdout, stderr, success, = git_run( "branch", "-D", branch )
|
|
133
|
+
return [ stdout, stderr, success ] if success
|
|
134
|
+
return [ stdout, stderr, false ] unless worktree_blocked_error?( error_text: stderr )
|
|
135
|
+
|
|
136
|
+
wt_path = worktree_path_for_branch( branch: branch )
|
|
137
|
+
return [ stdout, stderr, false ] if wt_path.nil?
|
|
138
|
+
|
|
139
|
+
rm_stdout, rm_stderr, rm_success, = git_run( "worktree", "remove", wt_path )
|
|
140
|
+
unless rm_success
|
|
141
|
+
error_text = rm_stderr.to_s.strip
|
|
142
|
+
puts_verbose "skip_worktree_remove: #{wt_path} (branch=#{branch}) reason=#{error_text}"
|
|
143
|
+
return [ stdout, stderr, false ]
|
|
144
|
+
end
|
|
145
|
+
puts_verbose "worktree_removed_for_prune: #{wt_path} (branch=#{branch})"
|
|
146
|
+
|
|
147
|
+
git_run( "branch", "-D", branch )
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def worktree_blocked_error?( error_text: )
|
|
151
|
+
error_text.to_s.downcase.include?( "used by worktree" )
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Returns the worktree path for a branch, or nil if not checked out in any worktree.
|
|
155
|
+
def worktree_path_for_branch( branch: )
|
|
156
|
+
entry = worktree_list.find { |wt| wt.fetch( :branch, nil ) == branch }
|
|
157
|
+
entry&.fetch( :path, nil )
|
|
158
|
+
end
|
|
159
|
+
|
|
125
160
|
# Detects local branches whose upstream tracking is marked [gone] after fetch --prune.
|
|
126
161
|
def stale_local_branches
|
|
127
162
|
git_capture!( "for-each-ref", "--format=%(refname:short)\t%(upstream:short)\t%(upstream:track)", "refs/heads" ).lines.map do |line|
|
|
@@ -218,7 +253,7 @@ module Carson
|
|
|
218
253
|
return :skipped
|
|
219
254
|
end
|
|
220
255
|
|
|
221
|
-
force_stdout, force_stderr, force_success
|
|
256
|
+
force_stdout, force_stderr, force_success = force_delete_local_branch( branch: branch )
|
|
222
257
|
unless force_success
|
|
223
258
|
error_text = normalise_branch_delete_error( error_text: force_stderr )
|
|
224
259
|
puts_verbose "fail_delete_absorbed_branch: #{branch} reason=#{error_text}"
|
|
@@ -287,7 +322,7 @@ module Carson
|
|
|
287
322
|
return :skipped
|
|
288
323
|
end
|
|
289
324
|
|
|
290
|
-
force_stdout, force_stderr, force_success
|
|
325
|
+
force_stdout, force_stderr, force_success = force_delete_local_branch( branch: branch )
|
|
291
326
|
if force_success
|
|
292
327
|
out.print force_stdout if verbose? && !force_stdout.empty?
|
|
293
328
|
puts_verbose "deleted_orphan_branch: #{branch} merged_pr=#{merged_pr.fetch( :url )}"
|