Skip to content

git gtr ai/go fails when branch is checked out in main working tree #127

Closed

Description

@echarrod

Description

When a branch is checked out in the main working tree (not a linked worktree), git gtr ai <branch> and git gtr go <branch> fail with "Worktree not found for branch", even though git worktree list correctly shows it.

The root cause is that resolve_target()/resolve_worktree() only searches linked worktrees in the worktrees directory and does not consider the main working tree as a valid match.

This is distinct from #123, which was about discover_repo_root() returning the wrong path when called from inside a linked worktree.

Steps to reproduce

# Main repo has branch checked out
cd ~/Code/my-repo
git checkout my-feature-branch

# git worktree list shows it correctly
git worktree list
# /Users/me/Code/my-repo                abc1234 [my-feature-branch]
# /Users/me/Code/my-repo-worktrees/other def5678 [other-branch]

# But git gtr can't find it
git gtr ai my-feature-branch
# [x] Worktree not found for branch: my-feature-branch

git gtr go my-feature-branch
# [x] Worktree not found for branch: my-feature-branch

Expected behaviour

git gtr should recognise the main working tree when resolving a branch name, falling through to it when no linked worktree matches.

Environment

  • git gtr version 2.3.0 (installed via Homebrew)
  • git version 2.48.1
  • macOS (Apple Silicon)

Activity

  1. traycerai commented on Feb 17, 2026

    @traycerai

    Plan

    Observations

    The issue occurs because resolve_target() in file:lib/core.sh (lines 258-310) doesn't properly recognize when a branch is checked out in the main working tree. While there is code at lines 274-279 that attempts to check if the identifier matches the current branch in the repo root, it appears this logic may not be working correctly or may have edge cases. The function only searches linked worktrees in the worktrees directory (lines 282-300) and doesn't fall back to checking if the branch exists in the main repo when no linked worktree matches.

    Approach

    The fix involves enhancing the resolve_target() function to properly detect when a branch is checked out in the main working tree. The existing check at lines 274-279 should be verified and potentially improved to handle all edge cases. Additionally, we should ensure that git worktree list --porcelain output is properly parsed to identify the main working tree, as Git natively reports it. This aligns with how the list command already handles the main repo (file:lib/commands/list.sh lines 44-47).

    Implementation Steps

    1. Enhance resolve_target() in file:lib/core.sh

    Current Logic Flow:

    flowchart TD
        A[resolve_target called] --> B{identifier == '1'?}
        B -->|Yes| C[Return main repo]
        B -->|No| D{identifier == current branch in repo root?}
        D -->|Yes| E[Return main repo]
        D -->|No| F{Direct path exists?}
        F -->|Yes| G[Return worktree path]
        F -->|No| H{Search worktree dirs}
        H -->|Found| I[Return worktree path]
        H -->|Not found| J[Error: Worktree not found]
    
    Loading

    Modify the resolution logic (lines 274-310):

    • Verify the existing check at lines 274-279 is working correctly by ensuring get_current_branch("$repo_root") properly returns the branch checked out in the main repo
    • Consider using git worktree list --porcelain to get authoritative information about all worktrees including the main one
    • Add fallback logic after the worktree directory search (after line 300) to check if the identifier matches a branch in the main repo using git -C "$repo_root" rev-parse --verify "refs/heads/$identifier"
    • If the branch exists in the main repo and is checked out there, return the main repo path with is_main=1

    Specific changes:

    • After line 279, add debug logging to verify the branch comparison is working
    • After line 300 (before the error at line 306), add a final check using git worktree list --porcelain to parse all worktrees including the main one
    • Parse the porcelain output to find entries where the branch matches the identifier
    • If found and the path matches the repo root, return 1\t$repo_root\t$identifier

    2. Add comprehensive tests in file:tests/core_resolve_target.bats

    Add test cases to verify the fix:

    • Test resolving a branch checked out in main repo when called from main repo
    • Test resolving a branch checked out in main repo when called from inside a linked worktree
    • Test resolving a branch checked out in main repo when called from outside the repo
    • Test that the fix doesn't break existing functionality for linked worktrees
    • Test edge cases like detached HEAD in main repo

    Example test structure:

    @test "resolve_target finds branch in main repo when not current"
    @test "resolve_target finds main repo branch from inside worktree"
    @test "resolve_target prefers linked worktree over main repo for same branch"
    

    3. Update file:tests/cmd_go.bats and file:tests/cmd_ai.bats

    Add integration tests:

    • Test cmd_go with a branch checked out in main repo
    • Test cmd_ai with a branch checked out in main repo
    • Verify error messages are clear when branch truly doesn't exist anywhere

    4. Consider using git worktree list --porcelain for authoritative data

    Alternative approach (more robust):

    Instead of relying on directory scanning and get_current_branch(), parse git worktree list --porcelain output to get all worktrees including the main one. This is what Git itself reports and is the source of truth.

    Implementation:

    • Create a helper function _parse_worktree_list() that parses git worktree list --porcelain
    • Returns a list of worktree entries with path, branch, and status
    • Use this in resolve_target() to find matching branches
    • This approach is more reliable than directory scanning and handles all edge cases

    Porcelain format example:

    worktree /Users/me/Code/my-repo
    HEAD abc1234
    branch refs/heads/my-feature-branch
    
    worktree /Users/me/Code/my-repo-worktrees/other
    HEAD def5678
    branch refs/heads/other-branch
    

    5. Update documentation if needed

    Files to check:

    • file:README.md - Verify examples show that main repo branches can be referenced by name
    • file:CHANGELOG.md - Add entry for the fix in the Unreleased section

    6. Verify related commands work correctly

    Commands that use resolve_target() or resolve_worktree():

    • file:lib/commands/ai.sh (line 34)
    • file:lib/commands/go.sh (line 16)
    • file:lib/commands/run.sh (likely uses similar logic)
    • file:lib/commands/editor.sh (likely uses similar logic)
    • file:lib/commands/remove.sh (likely uses similar logic)

    Ensure all these commands properly handle branches checked out in the main working tree after the fix.

    Import In IDE

    VSCode Icon Cursor Icon Windsurf Icon

    🤖 Prompt for AI Agents
    ## Observations
    
    The issue occurs because `resolve_target()` in `file:lib/core.sh` (lines 258-310) doesn't properly recognize when a branch is checked out in the main working tree. While there is code at lines 274-279 that attempts to check if the identifier matches the current branch in the repo root, it appears this logic may not be working correctly or may have edge cases. The function only searches linked worktrees in the worktrees directory (lines 282-300) and doesn't fall back to checking if the branch exists in the main repo when no linked worktree matches.
    
    ## Approach
    
    The fix involves enhancing the `resolve_target()` function to properly detect when a branch is checked out in the main working tree. The existing check at lines 274-279 should be verified and potentially improved to handle all edge cases. Additionally, we should ensure that `git worktree list --porcelain` output is properly parsed to identify the main working tree, as Git natively reports it. This aligns with how the `list` command already handles the main repo (file:lib/commands/list.sh lines 44-47).
    
    ## Implementation Steps
    
    ### 1. Enhance `resolve_target()` in `file:lib/core.sh`
    
    **Current Logic Flow:**
    ```mermaid
    flowchart TD
        A[resolve_target called] --> B{identifier == '1'?}
        B -->|Yes| C[Return main repo]
        B -->|No| D{identifier == current branch in repo root?}
        D -->|Yes| E[Return main repo]
        D -->|No| F{Direct path exists?}
        F -->|Yes| G[Return worktree path]
        F -->|No| H{Search worktree dirs}
        H -->|Found| I[Return worktree path]
        H -->|Not found| J[Error: Worktree not found]
    ```
    
    **Modify the resolution logic (lines 274-310):**
    
    - Verify the existing check at lines 274-279 is working correctly by ensuring `get_current_branch("$repo_root")` properly returns the branch checked out in the main repo
    - Consider using `git worktree list --porcelain` to get authoritative information about all worktrees including the main one
    - Add fallback logic after the worktree directory search (after line 300) to check if the identifier matches a branch in the main repo using `git -C "$repo_root" rev-parse --verify "refs/heads/$identifier"`
    - If the branch exists in the main repo and is checked out there, return the main repo path with `is_main=1`
    
    **Specific changes:**
    
    - After line 279, add debug logging to verify the branch comparison is working
    - After line 300 (before the error at line 306), add a final check using `git worktree list --porcelain` to parse all worktrees including the main one
    - Parse the porcelain output to find entries where the branch matches the identifier
    - If found and the path matches the repo root, return `1\t$repo_root\t$identifier`
    
    ### 2. Add comprehensive tests in `file:tests/core_resolve_target.bats`
    
    **Add test cases to verify the fix:**
    
    - Test resolving a branch checked out in main repo when called from main repo
    - Test resolving a branch checked out in main repo when called from inside a linked worktree
    - Test resolving a branch checked out in main repo when called from outside the repo
    - Test that the fix doesn't break existing functionality for linked worktrees
    - Test edge cases like detached HEAD in main repo
    
    **Example test structure:**
    ```
    @test "resolve_target finds branch in main repo when not current"
    @test "resolve_target finds main repo branch from inside worktree"
    @test "resolve_target prefers linked worktree over main repo for same branch"
    ```
    
    ### 3. Update `file:tests/cmd_go.bats` and `file:tests/cmd_ai.bats`
    
    **Add integration tests:**
    
    - Test `cmd_go` with a branch checked out in main repo
    - Test `cmd_ai` with a branch checked out in main repo
    - Verify error messages are clear when branch truly doesn't exist anywhere
    
    ### 4. Consider using `git worktree list --porcelain` for authoritative data
    
    **Alternative approach (more robust):**
    
    Instead of relying on directory scanning and `get_current_branch()`, parse `git worktree list --porcelain` output to get all worktrees including the main one. This is what Git itself reports and is the source of truth.
    
    **Implementation:**
    - Create a helper function `_parse_worktree_list()` that parses `git worktree list --porcelain`
    - Returns a list of worktree entries with path, branch, and status
    - Use this in `resolve_target()` to find matching branches
    - This approach is more reliable than directory scanning and handles all edge cases
    
    **Porcelain format example:**
    ```
    worktree /Users/me/Code/my-repo
    HEAD abc1234
    branch refs/heads/my-feature-branch
    
    worktree /Users/me/Code/my-repo-worktrees/other
    HEAD def5678
    branch refs/heads/other-branch
    ```
    
    ### 5. Update documentation if needed
    
    **Files to check:**
    - `file:README.md` - Verify examples show that main repo branches can be referenced by name
    - `file:CHANGELOG.md` - Add entry for the fix in the Unreleased section
    
    ### 6. Verify related commands work correctly
    
    **Commands that use `resolve_target()` or `resolve_worktree()`:**
    - `file:lib/commands/ai.sh` (line 34)
    - `file:lib/commands/go.sh` (line 16)
    - `file:lib/commands/run.sh` (likely uses similar logic)
    - `file:lib/commands/editor.sh` (likely uses similar logic)
    - `file:lib/commands/remove.sh` (likely uses similar logic)
    
    Ensure all these commands properly handle branches checked out in the main working tree after the fix.

    Execution Information

    Branch: main
    Commit: 57e7167


    💡 Tips

    Supported Commands (Inside Comments)

    • Use @traycerai generate to iterate on the previous version of the implementation plan.

    Supported Commands (Inside Description)

    • Add @traycerai ignore anywhere in the ticket description to prevent this ticket from being processed.
    • Add @traycerai branch:<branch-name> anywhere in the ticket description to specify the target branch for the implementation plan.

    Community

    • Join our Discord Community to get help, request features, and share feedback.
    • Follow us on X/Twitter for updates and announcements.
  2. helizaga commented on Feb 17, 2026

    @helizaga
    Contributor

    This was fixed by #123/#126 which updated discover_repo_root() to use --git-common-dir instead of --show-toplevel. The existing fast-path check in resolve_target() (line 275-279) correctly resolves branches checked out in the main working tree — it just needed the correct repo_root value, which the older discover_repo_root() wasn't providing from inside linked worktrees.

    The fix is on main but hasn't been released yet (post v2.3.0).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions