From a609306d3bcdad02c2dbf83754a0dcf2ee7c9ae6 Mon Sep 17 00:00:00 2001 From: Tom Elizaga Date: Mon, 14 Sep 2026 11:34:11 -0700 Subject: [PATCH 1/2] fix: make GTR_DEBUG actually report the failing location bin/git-gtr installed an ERR trap when GTR_DEBUG was set, but ran under `set -e` alone. An ERR trap is inherited by functions, command substitutions and subshells only under `set -E`, and every command runs inside main() and then a cmd_* handler, so the trap never fired and GTR_DEBUG produced no output at all. The comment above it promised behavior the code did not deliver. Switch the option line to `set -eE`. With no ERR trap installed the option has no effect, so the default path is unchanged; only the GTR_DEBUG path gains behavior. Verified against a matrix of set -e/-eE with and without the trap: output is identical in all configurations except `set -eE` plus trap, which reports the failure. Guarded failures (`|| true`, `if cmd`, guarded command substitutions) still do not fire the trap, so debug mode does not become noisy; six ordinary invocations, including handled error paths, emit nothing. Add tests/debug_trap.bats, which runs the real binary as a subprocess: an unguarded failure reports file, line and function; nothing is reported without GTR_DEBUG, on success, or on a handled error path. Reverting the option line makes the first case fail. --- CHANGELOG.md | 4 +++ bin/git-gtr | 6 +++- tests/debug_trap.bats | 66 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 tests/debug_trap.bats diff --git a/CHANGELOG.md b/CHANGELOG.md index 08c4d93..ff122a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this ## [Unreleased] +### Fixed + +- `GTR_DEBUG=1` now reports the file, line and function of an unexpected failure. `bin/git-gtr` installed an `ERR` trap but ran under `set -e` alone, so the trap was never inherited by functions; since every command runs inside `main()` and a `cmd_*` handler, the variable had no observable effect. The script now uses `set -eE`, which changes nothing when the trap is not installed. + ## [2.11.0] - 2026-08-19 ### Added diff --git a/bin/git-gtr b/bin/git-gtr index 2b8e94b..24ae27d 100755 --- a/bin/git-gtr +++ b/bin/git-gtr @@ -3,7 +3,11 @@ # Portable, cross-platform git worktree management # Invoked as: git gtr (git subcommand via PATH discovery) -set -e +# -E propagates the ERR trap below into functions, command substitutions and +# subshells. Without it the GTR_DEBUG trap never fires, because every command +# runs inside main() and a cmd_* handler. With no ERR trap installed, -E has no +# effect, so the default path behaves exactly as it did with plain -e. +set -eE # Debug: show file:line:function on set -e failures if [ -n "${GTR_DEBUG:-}" ]; then diff --git a/tests/debug_trap.bats b/tests/debug_trap.bats new file mode 100644 index 0000000..e386144 --- /dev/null +++ b/tests/debug_trap.bats @@ -0,0 +1,66 @@ +#!/usr/bin/env bats +# Tests for the GTR_DEBUG error trap in bin/git-gtr +# +# The trap is only useful when bin/git-gtr enables errtrace. An ERR trap is +# inherited by functions, command substitutions and subshells only under +# 'set -E'; with plain 'set -e' it never fires, because every command runs +# inside main() and then a cmd_* handler. These tests run the real binary as a +# subprocess so that the option line in bin/git-gtr is actually exercised. + +load test_helper + +setup() { + setup_integration_repo + + # A git shim that fails one specific config write and passes everything else + # through, standing in for an unexpected git failure at an unguarded call + # site (cfg_set in lib/config.sh). + REAL_GIT=$(command -v git) + SHIM_DIR=$(mktemp -d) + cat > "$SHIM_DIR/git" <