Skip to content

v1.0.0#42

Merged
leogdion merged 8 commits into
mainfrom
v1.0.0-integration
Jul 25, 2026
Merged

v1.0.0#42
leogdion merged 8 commits into
mainfrom
v1.0.0-integration

Conversation

@leogdion

@leogdion leogdion commented Jul 25, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features
    • Added --no-push/TREES_NO_PUSH controls for upstream/remote push behavior (for add and track).
    • Added safe handling for branch names with slashes via deterministic directory slugging, including collision detection.
  • Bug Fixes
    • Hardened init/add/track behaviors with improved validation, safer worktree layout, and clearer failure handling.
  • Documentation
    • Expanded git trees documentation (usage, concepts, env vars/limitations) and added v1.0.0 release notes.
  • Tests
    • Added tests/smoke.sh end-to-end coverage and expanded CI checks (bash syntax, ShellCheck).
  • Chores
    • Improved install.sh uninstall behavior and reporting.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@leogdion, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 12 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 123dded8-739f-405b-9ed7-fa0011fb9f21

📥 Commits

Reviewing files that changed from the base of the PR and between b6c62fa and fc9733b.

📒 Files selected for processing (4)
  • .claude/agent-notes.md
  • README.md
  • install.sh
  • tests/smoke.sh
📝 Walkthrough

Walkthrough

The PR updates branch-directory slugging, push controls, initialization cleanup, agent seeding, installation and uninstall behavior, JSON output, smoke-test coverage, CI wiring, contributor guidance, README documentation, and v1.0.0 release notes.

Changes

git-trees update

Layer / File(s) Summary
Branch layout and tracking controls
git-trees
Slash-containing branches use slugged directories with collision detection; add and track support --no-push and TREES_NO_PUSH; JSON output escapes control characters; clean is no longer dispatched.
Initialization, agent seeding, and installation safety
git-trees, install.sh
Initialization validates missing option values and removes failed partial clones; agent seeding handles occupied paths safely; uninstall supports custom destinations and reports missing files.
Offline smoke-test and CI validation
tests/smoke.sh, .github/workflows/ci.yml
The smoke suite validates CLI, initialization, root seeding, add/track, no-push, collision, failure, and JSON behavior; CI runs syntax checks, ShellCheck, and the suite.
Contributor guidance and release documentation
README.md, AGENTS.md, AGENTS.md.template, CHANGELOG.md, .claude/agent-notes.md
Documentation describes updated commands, layout rules, testing guidance, contributor roles, branch slugging, and the v1.0.0 release.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title identifies a release version but does not describe the actual changes in the pull request. Use a short descriptive title that summarizes the main change, such as the new v1.0.0 release and its key behavior updates.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v1.0.0-integration

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@git-trees`:
- Around line 141-150: Update the agent-seeding failure path around the visible
write logic and its caller cmd_init so a genuine failure to create AGENTS.md
removes the newly initialized container before returning nonzero. Preserve the
successful and concurrent-creation cases, and ensure cleanup occurs only for the
failed initialization path so retries can run normally.
- Around line 485-506: Update the worktree porcelain parsing and rows
construction to use git worktree list --porcelain -z with NUL-delimited records,
preserving raw path bytes—including newlines—before CSV/JSON encoding. Adjust
tab, newline, and NUL boundary handling so fields remain correctly separated,
then keep the existing jesc JSON escaping in the awk output.
- Around line 168-180: Update the positional-argument handling in the init
option parser to reject a second target instead of overwriting or accepting it.
When a positional argument is already set, print the init usage to stderr and
return failure; preserve the existing handling for a single target and option
validation.

In `@install.sh`:
- Around line 25-36: Update the uninstall loop in install.sh to track targets
found independently from successfully removed targets: when git-trees exists,
mark it as discovered before attempting rm, and report any rm failure. Use the
discovered-target count for the “no git-trees found” message, retain successful
removal reporting, and exit nonzero if any existing target could not be removed.

In `@README.md`:
- Around line 120-125: Update the README convenience curl installation snippet
to create ~/.local/bin before downloading git-trees. Add a mkdir -p step before
the curl command, while preserving the existing download and chmod commands.
- Around line 223-255: The README’s `add` documentation overstates that upstream
setup and pushing always occur. Update the opening `add` paragraphs to qualify
these statements as applying by default or when pushing is enabled, while
preserving the existing `--no-push` and `TREES_NO_PUSH` behavior describing an
unset upstream when the remote branch is absent.
- Around line 75-84: Label the fenced directory-layout block in the README with
the text language by changing its opening fence to ```text, while leaving the
tree contents unchanged.

In `@tests/smoke.sh`:
- Around line 95-96: Update the smoke suite’s Git setup to avoid reading or
writing the user’s global configuration: set temporary author and committer
identity variables and configure Git to use a temporary global config file under
TMP. Remove the git config --global fallback commands while preserving the test
identity values.
- Around line 375-381: Add a positive assertion after the `add --no-push`
invocation to verify that the `solo` worktree and its local branch were created
successfully, such as checking the worktree path or branch reference. Keep the
existing negative remote/upstream assertions and push-command output check
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f92d4440-8b21-41c7-845f-2ccf7e2cc08f

📥 Commits

Reviewing files that changed from the base of the PR and between 86d6058 and d3e5c11.

📒 Files selected for processing (10)
  • .claude/agent-notes.md
  • .github/workflows/ci.yml
  • AGENTS.md
  • AGENTS.md.template
  • CHANGELOG.md
  • README.md
  • git-trees
  • install.sh
  • lint.yml
  • tests/smoke.sh
💤 Files with no reviewable changes (1)
  • lint.yml

Comment thread git-trees
Comment on lines 141 to +150
if (set -C; cat -- "$TREES_AGENTS_TEMPLATE" > "$1/AGENTS.md"); then
echo "wrote $1/AGENTS.md" >&2
return 0
fi
[ -e "$1/AGENTS.md" ] || [ -L "$1/AGENTS.md" ] && return 0
# The write failed. Benign if another process won the race and created it;
# a real failure (read error, full disk) otherwise.
if [ -e "$1/AGENTS.md" ] || [ -L "$1/AGENTS.md" ]; then
return 0
fi
echo "git trees: could not write $1/AGENTS.md" >&2

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Roll back the container when agent seeding fails.

A real write failure returns nonzero here, then cmd_init returns at Line 241 without removing the newly initialized directory. Retrying init subsequently fails on “already exists,” leaving manual cleanup as the only recovery.

Proposed fix
-  _seed_agents "$dir" || return 1
+  if ! _seed_agents "$dir"; then
+    rm -rf "$dir"
+    return 1
+  fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@git-trees` around lines 141 - 150, Update the agent-seeding failure path
around the visible write logic and its caller cmd_init so a genuine failure to
create AGENTS.md removes the newly initialized container before returning
nonzero. Preserve the successful and concurrent-creation cases, and ensure
cleanup occurs only for the failed initialization path so retries can run
normally.

Comment thread git-trees
Comment on lines 168 to 180
while [ $# -gt 0 ]; do
case "$1" in
--host) host="${2:-}"; host_set=1; shift 2 ;;
--dir) dir="${2:-}"; shift 2 ;;
# `shift 2` with one argument left fails and leaves $1 in place, so the
# while loop spins forever. Check arity before shifting.
--host)
[ $# -ge 2 ] || { echo "git trees init: --host needs a value" >&2; return 1; }
host="$2"; host_set=1; shift 2 ;;
--dir)
[ $# -ge 2 ] || { echo "git trees init: --dir needs a value" >&2; return 1; }
dir="$2"; shift 2 ;;
-*) echo "git trees init: unknown option $1" >&2; return 1 ;;
*) arg="$1"; shift ;;
esac

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reject multiple init targets.

cmd_init owner/repo accidental silently initializes accidental, despite usage allowing one target. Reject a second positional argument and print usage. As per coding guidelines, “Every subcommand must validate its own arguments and print usage to stderr when validation fails.”

Proposed fix
-      *)      arg="$1";      shift ;;
+      *)
+        [ -z "$arg" ] || {
+          echo "git trees init: unexpected argument $1" >&2
+          return 1
+        }
+        arg="$1"; shift ;;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
while [ $# -gt 0 ]; do
case "$1" in
--host) host="${2:-}"; host_set=1; shift 2 ;;
--dir) dir="${2:-}"; shift 2 ;;
# `shift 2` with one argument left fails and leaves $1 in place, so the
# while loop spins forever. Check arity before shifting.
--host)
[ $# -ge 2 ] || { echo "git trees init: --host needs a value" >&2; return 1; }
host="$2"; host_set=1; shift 2 ;;
--dir)
[ $# -ge 2 ] || { echo "git trees init: --dir needs a value" >&2; return 1; }
dir="$2"; shift 2 ;;
-*) echo "git trees init: unknown option $1" >&2; return 1 ;;
*) arg="$1"; shift ;;
esac
while [ $# -gt 0 ]; do
case "$1" in
# `shift 2` with one argument left fails and leaves $1 in place, so the
# while loop spins forever. Check arity before shifting.
--host)
[ $# -ge 2 ] || { echo "git trees init: --host needs a value" >&2; return 1; }
host="$2"; host_set=1; shift 2 ;;
--dir)
[ $# -ge 2 ] || { echo "git trees init: --dir needs a value" >&2; return 1; }
dir="$2"; shift 2 ;;
-*) echo "git trees init: unknown option $1" >&2; return 1 ;;
*)
[ -z "$arg" ] || {
echo "git trees init: unexpected argument $1" >&2
return 1
}
arg="$1"; shift ;;
esac
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@git-trees` around lines 168 - 180, Update the positional-argument handling in
the init option parser to reject a second target instead of overwriting or
accepting it. When a positional argument is already set, print the init usage to
stderr and return failure; preserve the existing handling for a single target
and option validation.

Source: Coding guidelines

Comment thread git-trees
Comment on lines 485 to +506
printf '%s' "$rows" | awk -F'\t' '
BEGIN { print "["; sep = "" }
function jesc(s, out, i, n, c) {
out = ""; n = length(s)
for (i = 1; i <= n; i++) {
c = substr(s, i, 1)
if (c == "\\") out = out "\\\\"
else if (c == "\"") out = out "\\\""
else if (c in ctl) out = out ctl[c]
else out = out c
}
return out
}
BEGIN {
# Control characters are not legal raw in a JSON string.
for (i = 1; i < 32; i++) ctl[sprintf("%c", i)] = sprintf("\\u%04x", i)
ctl["\b"] = "\\b"; ctl["\f"] = "\\f"; ctl["\n"] = "\\n"
ctl["\r"] = "\\r"; ctl["\t"] = "\\t"
print "["; sep = ""
}
NF {
for (i = 1; i <= NF; i++) gsub(/"/, "\\\"", $i)
printf "%s {\"branch\":\"%s\",\"upstream\":\"%s\",\"track\":\"%s\",\"date\":\"%s\",\"state\":\"%s\",\"path\":\"%s\"}\n", \
sep, $1, $2, $3, $4, $5, $6
sep, jesc($1), jesc($2), jesc($3), jesc($4), jesc($5), jesc($6)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -uo pipefail

tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT

repo="$tmp/repo"
git init -q "$repo"
git -C "$repo" config user.email test@example.invalid
git -C "$repo" config user.name test
: > "$repo/file"
git -C "$repo" add file
git -C "$repo" commit -qm init

wt=$tmp/$'worktree\nwith-newline'
git -C "$repo" worktree add -q -b newline-path "$wt" HEAD

printf '%s\n' 'Without -z:'
git -C "$repo" worktree list --porcelain

printf '%s\n' 'With -z:'
git -C "$repo" worktree list --porcelain -z | od -An -t x1

git --version

Repository: brightdigit/git-trees

Length of output: 533


🏁 Script executed:

#!/bin/bash
set -uo pipefail

printf 'Locate git-trees and relevant command references:\n'
fd -a '^git-trees$' . | sed -e 's#^\./##'

printf '\nRelevant occurrences:\n'
rg -n "worktree list --porcelain|awk -F|printf '%s', \"\\$rows\"|cmd_.*tree|cmd_.*output|--json|json" git-trees || true

echo
printf 'Inspect git-trees outline around candidate functions:\n'
ast-grep outline git-trees --match cmd --view expanded | sed -n '1,220p' || true

echo
printf 'Inspect git-trees lines 440-520:\n'
cat -n git-trees | sed -n '440,520p'

Repository: brightdigit/git-trees

Length of output: 298


🏁 Script executed:

#!/bin/bash
set -u

printf 'Relevant occurrences:\n'
rg -n "worktree list --porcelain|awk -F|printf '%s', \\\"\\$rows\\\"|cmd_.*tree|cmd_.*output|--json|json" git-trees || true

echo
printf 'Inspect git-trees lines 440-520:\n'
cat -n git-trees | sed -n '440,520p'

printf '\nInspect command parsing/usage functions mentioning worktree/json/output:\n'
rg -n "usage|cmd_|worktree|json|output" git-trees | sed -n '1,160p'

Repository: brightdigit/git-trees

Length of output: 218


🏁 Script executed:

#!/usr/bin/env bash
set -u

printf 'Relevant occurrences:\n'
grep -nE 'worktree list --porcelain|awk -F|printf '\''%s'\'', "\$rows"|cmd_[A-Za-z_]+|json|output' git-trees || true

echo
printf 'Inspect git-trees lines 440-520:\n'
sed -n '440,520p' git-trees | nl -ba -v440

printf '\nInspect command parsing/usage functions mentioning worktree/json/output:\n'
grep -nE 'usage|cmd_|worktree|json|output' git-trees | sed -n '1,200p'

Repository: brightdigit/git-trees

Length of output: 4147


🏁 Script executed:

#!/usr/bin/env bash
set -u

printf 'Inspect cmd_list body:\n'
sed -n '448,522p' git-trees | cat -n

printf '\nBehavioral probe from repo root; preserve path containing literal tab and newline, but not NUL:\n'
tmp=$(mktemp -d -p "$PWD" git-trees-test-XXXXXX)
trap 'rm -rf "$tmp"' EXIT
repo="$tmp/repo"
git init -q "$repo"
git -C "$repo" config user.email test@example.invalid
git -C "$repo" config user.name test
: > "$repo/file"
git -C "$repo" add file
git -C "$repo" commit -qm init

printf '%s\n' 'Worktree path containing newline and tab:'
git -C "$repo" worktree add -q -b "newline\ttab-path" "$tmp/$'worktree\nwith\tchars'" HEAD

printf '%s\n' 'git worktier list --porcelain around new worktree:'
git -C "$repo" worktree list --porcelain | grep -A2 '^worktree '"$tmp/$'worktree\nwith\tchars'" || true

printf '\nCommand output for list --json contains newline path broken across rows?\n'
bash git-trees -C "$repo" list --json 2>/proc/null || true

printf '\nWithout --json around new worktree:\n'
bash git-trees -C "$repo" list 2>/proc/null | sed -n '/^[A-Z]/,/----/p' | grep -A2 "$tmp/$'worktree\nwith\tchars'" || true

Repository: brightdigit/git-trees

Length of output: 3878


🏁 Script executed:

#!/usr/bin/env bash
set -u

printf 'Check git availability/version:\n'
if command -v git >/dev/null 2>&1; then git --version; else echo "git unavailable"; fi

printf '\nBehavioral probe with valid branch, path containing newline and tab:\n'
tmp=$(mktemp -d -p "$PWD" git-trees-test-XXXXXX)
trap 'rm -rf "$tmp"' EXIT
repo="$tmp/repo"
git init -q "$repo"
git -C "$repo" config user.email test@example.invalid
git -C "$repo" config user.name test
: > "$repo/file"
git -C "$repo" add file
git -C "$repo" commit -qm init

printf '%s\n' 'Worktree path containing newline and tab:'
git -C "$repo" worktree add -q -b "newline-tab-path" "$tmp/worktree$(printf '\n')with$(printf '\t')chars" "$repo"

printf '%s\n' 'git worktree list --porcelain for new worktree:'
git -C "$repo" worktree list --porcelain | sed "/$tmp\\/worktree/Np;q" | sed 's/^/P:'
printf '%s\\n' 'Hex bytes for worktree line:'
git -C "$repo" worktree list --porcelain | awk 'NR==2{for(i=1;i<=length($0);i++)printf "%02x ", sprintf("%d", substr($0,i,1)); print ""}'

printf '\nCommand output for list --json with newline/tab path:\n'
git trees -C "$repo" list --json

printf '\nCommand output for list without --json around new worktree:\n'
git trees -C "$repo" list | awk '
  BEGIN{p=0}
  /worktree/ {p=1}
  p
' | sed -n '/^[A-Za-z][A-Za-z0-9\/._-]*$/,/--- /p'

Repository: brightdigit/git-trees

Length of output: 1090


🌐 Web query:

Git worktree list --porcelain -z NUL delimited documentation

💡 Result:

When using the git worktree list command, the --porcelain option provides a machine-readable output format that is stable across different Git versions and user configurations [1][2]. To handle paths that contain newline characters or other unusual characters, you should combine --porcelain with the -z option [1][2]. When -z is specified, each line of the output is terminated with a NUL character (ASCII 0) instead of a standard newline character [1][2]. This is the recommended practice for robust script parsing of the worktree list output [1][2]. In the porcelain format: - Attributes are listed with a label and value separated by a space [1][2]. - Boolean attributes (such as bare and detached) appear as a label only when the value is true [1][2]. - The first attribute for every worktree record is always worktree [1][2]. - Records are separated by an empty line (or, if -z is used, the NUL terminator marks the end of each attribute line) [1][2].

Citations:


Preserve raw porcelain paths before JSON encoding.

git worktree list --porcelain tokenizes worktree <path> by unquoted newlines, so a worktree path containing a newline is emitted as worktree /path\nwith-newline, splitting one record across two lines. Use git worktree list --porcelain -z and NUL-delimited parsing so raw path bytes are stored before writing CSV/JSON, and adjust the tab-delimited rows construction for NUL-delimiter/tab/newline boundaries.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@git-trees` around lines 485 - 506, Update the worktree porcelain parsing and
rows construction to use git worktree list --porcelain -z with NUL-delimited
records, preserving raw path bytes—including newlines—before CSV/JSON encoding.
Adjust tab, newline, and NUL boundary handling so fields remain correctly
separated, then keep the existing jesc JSON escaping in the awk output.

Comment thread install.sh Outdated
Comment on lines +25 to +36
if [ -e "$d/git-trees" ]; then
rm -f "$d/git-trees" && echo "removed $d/git-trees"
if rm -f "$d/git-trees"; then
echo "removed $d/git-trees"
removed=1
fi
fi
done

if [ "$removed" -eq 0 ]; then
echo "install.sh: no git-trees found in $*" >&2
echo " if you installed elsewhere, pass it: ./install.sh --uninstall <dir>" >&2
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fail uninstall when an existing target cannot be removed.

If rm fails, this reports that no file was found and exits 0, even though the executable remains installed. Track discovered targets separately, report removal failures, and exit nonzero.

Proposed fix
-  removed=0
+  found=0 failed=0
   for d in "$@"; do
-    if [ -e "$d/git-trees" ]; then
-      if rm -f "$d/git-trees"; then
+    if [ -e "$d/git-trees" ] || [ -L "$d/git-trees" ]; then
+      found=1
+      if rm -f -- "$d/git-trees"; then
         echo "removed $d/git-trees"
-        removed=1
+      else
+        echo "install.sh: could not remove $d/git-trees" >&2
+        failed=1
       fi
     fi
   done
 
-  if [ "$removed" -eq 0 ]; then
+  if [ "$found" -eq 0 ]; then
     echo "install.sh: no git-trees found in $*" >&2
     echo "  if you installed elsewhere, pass it: ./install.sh --uninstall <dir>" >&2
   fi
+  [ "$failed" -eq 0 ] || exit 1
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [ -e "$d/git-trees" ]; then
rm -f "$d/git-trees" && echo "removed $d/git-trees"
if rm -f "$d/git-trees"; then
echo "removed $d/git-trees"
removed=1
fi
fi
done
if [ "$removed" -eq 0 ]; then
echo "install.sh: no git-trees found in $*" >&2
echo " if you installed elsewhere, pass it: ./install.sh --uninstall <dir>" >&2
fi
if [ -e "$d/git-trees" ] || [ -L "$d/git-trees" ]; then
found=1
if rm -f -- "$d/git-trees"; then
echo "removed $d/git-trees"
else
echo "install.sh: could not remove $d/git-trees" >&2
failed=1
fi
fi
done
if [ "$found" -eq 0 ]; then
echo "install.sh: no git-trees found in $*" >&2
echo " if you installed elsewhere, pass it: ./install.sh --uninstall <dir>" >&2
fi
[ "$failed" -eq 0 ] || exit 1
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@install.sh` around lines 25 - 36, Update the uninstall loop in install.sh to
track targets found independently from successfully removed targets: when
git-trees exists, mark it as discovered before attempting rm, and report any rm
failure. Use the discovered-target count for the “no git-trees found” message,
retain successful removal reporting, and exit nonzero if any existing target
could not be removed.

Comment thread README.md Outdated
Comment thread README.md
Comment thread README.md Outdated
Comment thread tests/smoke.sh Outdated
Comment thread tests/smoke.sh
@leogdion
leogdion merged commit 9717fb8 into main Jul 25, 2026
4 checks passed
@leogdion
leogdion deleted the v1.0.0-integration branch July 25, 2026 21:11
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.

1 participant