Skip to content

Conversation

@damianlewis
Copy link
Contributor

@damianlewis damianlewis commented Dec 16, 2025

Pull Request

Description

Add gtr.hook.preRemove configuration for hooks that run before worktree deletion, allowing cleanup tasks that need directory access (e.g., stopping services, saving state). Hooks run with cwd set to the worktree directory. Hook failures abort removal unless --force is used.

Motivation

Currently, postRemove hooks run after the worktree is deleted, so they cannot access files in the worktree. Users need a way to run cleanup scripts before deletion.

Fixes #47

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code refactoring (no functional changes)
  • Other (please describe):

Testing

Manual Testing Checklist

Tested on:

  • macOS
  • Linux (specify distro: _______)
  • Windows (Git Bash)

Core functionality tested:

  • git gtr new <branch> - Create worktree
  • git gtr go <branch> - Navigate to worktree
  • git gtr editor <branch> - Open in editor (if applicable)
  • git gtr ai <branch> - Start AI tool (if applicable)
  • git gtr rm <branch> - Remove worktree
  • git gtr list - List worktrees
  • git gtr config - Configuration commands (if applicable)
  • Other commands affected by this change: N/A

Test Steps

  1. Configure preRemove hook: git gtr config add gtr.hook.preRemove "echo 'Running cleanup'"
  2. Create a worktree: git gtr new test-preremove
  3. Remove the worktree: git gtr rm test-preremove
  4. Verify hook message appears before removal confirmation

Expected behavior: Hook runs before worktree is deleted, with cwd in the worktree directory.

Actual behavior: Hook runs before worktree is deleted, with cwd in the worktree directory.

Additional tests:

  • Hook failure aborts removal (verified)
  • --force flag bypasses hook failure (verified)

Breaking Changes

  • This PR introduces breaking changes
  • I have discussed this in an issue first
  • Migration guide is included in documentation

Checklist

Before submitting this PR, please check:

  • I have read CONTRIBUTING.md
  • My code follows the project's style guidelines
  • I have performed manual testing on at least one platform
  • I have updated documentation (README.md, CLAUDE.md, etc.) if needed
  • My changes work on multiple platforms (or I've noted platform-specific behavior)
  • I have added/updated shell completions (if adding new commands or flags)
  • I have tested with both git gtr (production) and ./bin/gtr (development)
  • No new external dependencies are introduced (Bash + git only)
  • All existing functionality still works

Additional Context

Hook execution order for git gtr rm:

  1. preRemove hooks run (cwd = worktree directory)
  2. Worktree is deleted
  3. postRemove hooks run (cwd = repo root)

License Acknowledgment

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache License 2.0.

Summary by CodeRabbit

  • New Features

    • Added pre-remove hooks that execute before worktree removal, aborting the operation on failure unless --force is used.
    • Introduced hook execution order documentation with timing and use case details.
  • Documentation

    • Clarified hook semantics from "after" to "during" worktree operations.
    • Added pre-remove hook examples and configuration guidance.
    • Updated configuration precedence and environment variable references.

✏️ Tip: You can customize this high-level summary in your review settings.

Add gtr.hook.preRemove configuration for hooks that run before
worktree deletion, allowing cleanup tasks that need directory access.
Hook failures abort removal unless --force is used.
Add commented preRemove hook examples to both .gtrconfig.example
and gtr.config.example template files.
Add gtr.hook.preRemove to tab completion for bash, zsh, and fish.
Add preRemove hook configuration examples and document hook
execution order (preRemove runs before deletion, postRemove after).
Note that --force bypasses hook failures.
Add preRemove hook to configuration reference, key mapping table,
environment variables section, and manual testing checklist.
@coderabbitai
Copy link

coderabbitai bot commented Dec 16, 2025

Walkthrough

This pull request implements pre-remove hooks (preRemove) for the git-gtr tool, allowing users to run custom commands before worktree deletion. The feature adds configuration option gtr.hook.preRemove, hook execution logic in the remove flow with failure-abort behavior (unless --force is used), documentation, completion support, and example configurations.

Changes

Cohort / File(s) Summary
Documentation & Examples
CLAUDE.md, README.md
Updated documentation to describe preRemove hook semantics, execution order relative to postCreate and postRemove, environment variables, and abort-on-failure behavior. Added clarifications on --force flag behavior and hook execution timing.
Core Feature Implementation
bin/gtr
Added preRemove hook execution in the remove flow before worktree deletion; hooks receive REPO_ROOT, WORKTREE_PATH, and BRANCH variables; removal aborts on hook failure unless --force is specified; added configuration option definition for gtr.hook.preRemove.
Completion Support
completions/_git-gtr, completions/gtr.bash, completions/gtr.fish
Extended shell completion configurations to include gtr.hook.preRemove as a valid config key with descriptive text 'Pre-remove hook (abort on failure)'.
Configuration Examples
templates/.gtrconfig.example, templates/gtr.config.example
Added sample preRemove hook blocks demonstrating configuration and behavior; includes explanatory comments about abort-on-failure semantics and --force override.

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as git gtr rm
    participant Hooks as Hook System
    participant FS as Filesystem
    
    User->>CLI: git gtr rm worktree [--force]
    CLI->>CLI: Validate worktree exists
    CLI->>Hooks: Run preRemove hooks<br/>(REPO_ROOT, WORKTREE_PATH, BRANCH)
    
    alt Hook Success or --force flag
        Hooks-->>CLI: Hook(s) completed/skipped
        CLI->>FS: Remove worktree directory
        FS-->>CLI: Removal complete
        CLI->>Hooks: Run postRemove hooks<br/>(notifications/logging)
        Hooks-->>CLI: postRemove complete
        CLI-->>User: Success
    else Hook Failure (no --force)
        Hooks-->>CLI: Non-zero exit code
        CLI-->>User: Abort removal with error message
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • The bin/gtr implementation introduces new control flow with hook execution and conditional abort logic that should be verified against the documented behavior and existing hook system patterns
  • Verify preRemove hook environment variables, error handling, and --force flag interaction are correctly implemented
  • Documentation updates are extensive but straightforward; confirm alignment between README, CLAUDE.md, and code behavior
  • Completion files follow existing patterns but should be spot-checked for consistency across shells (bash, fish, zsh-completion script)

Poem

🐰 A hook before the worktree's gone,
Now cleanup happens ere removal's dawn,
With --force to override the fray,
Git-gtr hooks just found new ways to play! ✨

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add preRemove hooks' directly and concisely describes the main feature addition in the changeset.
Linked Issues check ✅ Passed All core requirements from issue #47 are met: preRemove configuration option added, hooks execute before worktree deletion with correct environment variables, failure handling with --force bypass implemented, and documentation updated.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing preRemove hooks: bin/gtr adds hook execution logic, completions support the new config key, documentation explains the feature, and templates provide examples.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9fd4e85 and c898fcc.

📒 Files selected for processing (8)
  • CLAUDE.md (5 hunks)
  • README.md (1 hunks)
  • bin/gtr (2 hunks)
  • completions/_git-gtr (1 hunks)
  • completions/gtr.bash (1 hunks)
  • completions/gtr.fish (1 hunks)
  • templates/.gtrconfig.example (1 hunks)
  • templates/gtr.config.example (1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
completions/*

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Shell completion files must be updated for bash, zsh, and fish when commands or adapters are added

Files:

  • completions/gtr.fish
  • completions/_git-gtr
  • completions/gtr.bash
completions/{gtr.bash,_git-gtr,gtr.fish}

📄 CodeRabbit inference engine (.github/instructions/completions.instructions.md)

completions/{gtr.bash,_git-gtr,gtr.fish}: Always update all three completion files (gtr.bash, _git-gtr, gtr.fish) when adding new commands, flags, editors, or AI adapters
Implement command completion in all three completion files to support top-level commands (new, rm, editor, ai, list, etc.) with appropriate tab-completion
Implement flag completion in all three completion files to support command-specific flags (e.g., --from, --force, --editor) with appropriate tab-completion
Implement adapter name completion in all three completion files, listing available editor names (cursor, vscode, zed) and AI tool names (aider, claude, codex) for --editor and --ai flags

Files:

  • completions/gtr.fish
  • completions/_git-gtr
  • completions/gtr.bash
completions/gtr.fish

📄 CodeRabbit inference engine (.github/instructions/completions.instructions.md)

completions/gtr.fish: In completions/gtr.fish, use custom predicates (__fish_git_gtr_needs_command, __fish_git_gtr_using_command) to handle git subcommand context and detect 'git gtr' usage
In completions/gtr.fish, support dynamic branch completion using 'git branch --format='%(refname:short)' and include special ID '1' for main repo

Files:

  • completions/gtr.fish
**/*.{bash,fish,sh}

📄 CodeRabbit inference engine (.github/instructions/sh.instructions.md)

**/*.{bash,fish,sh}: Bash 3.2+ compatible (macOS default), but 4.0+ features allowed where appropriate
Always quote variables: use "$var" not $var
Use function-scoped variables: local var="value"
Check return codes; functions return 1 on failure
Use snake_case for functions and variables, UPPER_CASE for constants
Prefer [ ] over [[ ]] for POSIX portability; use [[ only when needed
Always quote glob inputs; disable unintended globbing with set -f temporarily if required
Avoid associative arrays in shell scripts; use simple string/loop constructs for Bash 3.2+ compatibility
Avoid readarray and process substitution unsupported in older Bash
Debug with bash -x ./bin/gtr <cmd> or wrap suspicious blocks with set -x / set +x
Check function presence with declare -f create_worktree or declare -f resolve_target
Use stderr for variable inspection: echo "DEBUG var=$var" >&2 to keep stdout clean for command substitution
Keep dependencies minimal: only use git, sed, awk, find, grep; avoid jq/curl unless justified
Check availability of external commands before use when adding new tools
Use "${var}" for variable expansion; for line loops use while IFS= read -r line; do ... done to preserve spaces
Sanitize branch names via sanitize_branch_name function; do NOT duplicate logic elsewhere
Everything is sourced at startup with set -e enabled; functions call each other directly; no subshells except for hooks and AI tools

Files:

  • completions/gtr.fish
  • completions/gtr.bash
bin/gtr

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

bin/gtr: Dispatch commands through cmd_* functions in bin/gtr (case block lines 36‑77)
Update GTR_VERSION on line 8 of bin/gtr when releasing; this affects gtr version / --version output

Global set -e in bin/gtr: guard non-critical commands with || true

list --porcelain output must remain stable for scripting purposes

Update bin/gtr version constant when releasing a new version

Files:

  • bin/gtr
{bin/gtr,lib/**/*.sh,adapters/**/*.sh}

📄 CodeRabbit inference engine (.github/instructions/testing.instructions.md)

{bin/gtr,lib/**/*.sh,adapters/**/*.sh}: All commands must exit 0 (except intentional failures) and produce expected side-effects
No unquoted path errors; spaces must be handled in file paths
Hooks must run only once per creation/removal event

Files:

  • bin/gtr
completions/_git-gtr

📄 CodeRabbit inference engine (.github/instructions/completions.instructions.md)

completions/_git-gtr: In completions/_git-gtr, use Zsh completion framework with _arguments and _describe/_values for sophisticated completion logic with descriptions and grouping
In completions/_git-gtr, support dynamic branch completion using 'git branch --format='%(refname:short)' and include special ID '1' for main repo

Files:

  • completions/_git-gtr
completions/gtr.bash

📄 CodeRabbit inference engine (.github/instructions/completions.instructions.md)

completions/gtr.bash: In completions/gtr.bash, implement command completion using COMPREPLY array and compgen filtering for the current word ($cur)
In completions/gtr.bash, support dynamic branch completion using 'git branch --format='%(refname:short)' and include special ID '1' for main repo

Files:

  • completions/gtr.bash
🪛 Shellcheck (0.11.0)
completions/gtr.bash

[warning] 71-71: Prefer mapfile or read -a to split command output (or quote to avoid splitting).

(SC2207)

🔇 Additional comments (12)
completions/_git-gtr (1)

114-114: LGTM! Completion key added correctly.

The addition of gtr.hook.preRemove to the config completions is consistent with existing hook options and properly ordered.

templates/gtr.config.example (1)

62-64: LGTM! Clear documentation and example.

The preRemove hook example is well-documented with clear explanation of the abort-on-failure behavior and --force override. The positioning between postCreate and postRemove hooks is logical.

completions/gtr.bash (1)

71-71: LGTM! Completion option added correctly.

The addition of gtr.hook.preRemove to the bash completion list is consistent with the other completion files in this PR.

Note: The shellcheck warning SC2207 about the entire line is a false positive for bash completion patterns and can be safely ignored.

templates/.gtrconfig.example (1)

45-48: LGTM! Comprehensive documentation.

The preRemove hook section is well-documented with clear explanation of execution context (runs in worktree directory), failure behavior (abort unless --force), and a practical example.

bin/gtr (2)

354-365: LGTM! PreRemove hook implementation is correct.

The implementation properly:

  • Executes preRemove hooks before worktree removal with correct working directory
  • Provides appropriate environment variables (REPO_ROOT, WORKTREE_PATH, BRANCH)
  • Aborts removal on hook failure unless --force is used
  • Shows clear error messages and warnings

The execution order (preRemove → remove worktree → postRemove) matches the documented behavior.


1306-1306: LGTM! Help text accurately describes preRemove behavior.

The help text addition clearly communicates the abort-on-failure semantics, helping users understand the hook's behavior.

completions/gtr.fish (1)

83-83: LGTM! Fish completion added with clear description.

The preRemove hook completion includes a helpful description "(abort on failure)" that informs users of the hook's behavior during tab completion.

CLAUDE.md (2)

176-187: LGTM! Comprehensive testing checklist for preRemove hooks.

The manual testing section includes appropriate test cases for:

  • Hook execution
  • Abort-on-failure behavior
  • --force override

This provides good coverage for the new feature.


452-453: LGTM! Documentation thoroughly updated.

All configuration references, key mappings, environment variable descriptions, and multi-value configuration patterns have been consistently updated to include preRemove hooks with accurate behavior descriptions.

Also applies to: 469-470, 485-492, 509-509

README.md (3)

457-457: Good terminology improvement.

Changing "after worktree operations" to "during worktree operations" more accurately reflects that hooks can run before, during, and after operations.


464-479: LGTM! Excellent documentation for preRemove hooks.

The new section provides:

  • Clear example of preRemove hook usage
  • Helpful execution order table showing timing of all hooks
  • Important note about abort-on-failure and --force override

This gives users comprehensive understanding of the feature.


484-484: Good clarification of environment variable terminology.

Changing "New worktree path" to "Worktree path" is more accurate since this variable is available in all hooks, not just for new worktrees.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@helizaga helizaga merged commit 35d8119 into coderabbitai:main Dec 17, 2025
1 check passed
@helizaga
Copy link
Collaborator

good idea, lgtm

@damianlewis damianlewis deleted the feat/pre-remove-hooks branch December 17, 2025 10:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add preRemove hooks for cleanup before worktree deletion

2 participants