Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions lib/commands/remove.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ cmd_remove() {
local delete_branch="${_arg_delete_branch:-0}"
local yes_mode="${_arg_yes:-0}"
local force="${_arg_force:-0}"
local had_failure=0

resolve_repo_context || exit 1

Expand All @@ -22,13 +23,17 @@ cmd_remove() {
for identifier in "${_pa_positional[@]}"; do
# Resolve target branch
local is_main worktree_path branch_name
resolve_worktree "$identifier" "$repo_root" "$base_dir" "$prefix" || continue

if ! resolve_worktree "$identifier" "$repo_root" "$base_dir" "$prefix"; then
had_failure=1
continue
fi

is_main="$_ctx_is_main" worktree_path="$_ctx_worktree_path" branch_name="$_ctx_branch"

# Cannot remove main repository
if [ "$is_main" = "1" ]; then
log_error "Cannot remove main repository"
had_failure=1
continue
fi

Expand All @@ -41,6 +46,7 @@ cmd_remove() {
BRANCH="$branch_name"; then
if [ "$force" -eq 0 ]; then
log_error "Pre-remove hook failed for $branch_name. Use --force to skip hooks."
had_failure=1
continue
else
log_warn "Pre-remove hook failed, continuing due to --force"
Expand All @@ -49,6 +55,7 @@ cmd_remove() {

# Remove the worktree
if ! remove_worktree "$worktree_path" "$force"; then
had_failure=1
continue
fi

Expand All @@ -73,4 +80,6 @@ cmd_remove() {
log_warn "Post-remove hook failed for $branch_name"
fi
done
}

return "$had_failure"
}
25 changes: 21 additions & 4 deletions tests/cmd_remove.bats
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,19 @@ teardown() {
[ "$status" -eq 1 ]
}

@test "cmd_remove skips unknown branch and continues" {
# cmd_remove uses 'continue' for individual failures, not 'exit'
@test "cmd_remove fails for an unknown branch" {
run cmd_remove nonexistent
[ "$status" -eq 0 ]
[ "$status" -eq 1 ]
}

@test "git gtr rm propagates a failed exit status" {
run env PATH="$PROJECT_ROOT/bin:$PATH" git gtr rm nonexistent
[ "$status" -eq 1 ]
}

@test "cmd_remove cannot remove main repo" {
run cmd_remove 1
[ "$status" -eq 0 ] # continues past error, doesn't exit
[ "$status" -eq 1 ]
# Main repo should still exist
[ -d "$TEST_REPO" ]
}
Expand All @@ -56,10 +60,22 @@ teardown() {
create_test_worktree "hook-block"
git config --add gtr.hook.preRemove "exit 1"
run cmd_remove hook-block
[ "$status" -eq 1 ]
# Worktree should still exist (hook blocked removal)
[ -d "$TEST_WORKTREES_DIR/hook-block" ]
}

@test "cmd_remove fails when git refuses to remove a dirty worktree" {
create_test_worktree "dirty-rm"
touch "$TEST_WORKTREES_DIR/dirty-rm/untracked"

run cmd_remove dirty-rm

[ "$status" -eq 1 ]
[ -d "$TEST_WORKTREES_DIR/dirty-rm" ]
[[ "$output" == *"contains modified or untracked files"* ]]
}

@test "cmd_remove --force skips failed pre-remove hook" {
create_test_worktree "force-rm"
git config --add gtr.hook.preRemove "exit 1"
Expand All @@ -78,6 +94,7 @@ teardown() {
create_test_worktree "good-rm"
# Try to remove both a nonexistent and existing worktree
run cmd_remove nonexistent good-rm
[ "$status" -eq 1 ]
# The good one should have been removed despite the bad one failing
[ ! -d "$TEST_WORKTREES_DIR/good-rm" ]
}
Loading