Feature: GitCheckoutHandler coverage for uncovered lines
  As a developer
  I want to exercise every uncovered code path in git_checkout.py
  So that test coverage is complete for the GitCheckoutHandler

  # -- read() with empty path → returns listing via list_children (L82-84) --

  Scenario: Read with empty path returns file listing
    Given gcov a handler with a git repo containing tracked files
    When gcov read is called with empty path
    Then gcov the result should be a Content with newline-joined file listing

  # -- read() with binary file via git show (L105-106) --

  Scenario: Read detects binary content via git show
    Given gcov a handler with a git repo location
    And gcov git show returns binary data for path "image.png"
    When gcov read is called with path "image.png"
    Then gcov the result encoding should be None

  # -- read() when git show raises TimeoutExpired (L108-109) --

  Scenario: Read falls back to filesystem when git show times out
    Given gcov a handler with a git repo and a real file "notes.txt"
    And gcov subprocess run is mocked to raise TimeoutExpired for git show
    When gcov read is called with path "notes.txt"
    Then gcov the result data should match the file contents of "notes.txt"

  # -- read() when git show raises OSError (L108-109) --

  Scenario: Read falls back to filesystem when git show raises OSError
    Given gcov a handler with a git repo and a real file "data.txt"
    And gcov subprocess run is mocked to raise OSError for git show
    When gcov read is called with path "data.txt"
    Then gcov the result data should match the file contents of "data.txt"

  # -- read() fallback: file not found (L112-114) --

  Scenario: Read fallback raises FileNotFoundError for missing file
    Given gcov a handler with a git repo location
    And gcov subprocess run is mocked to fail git show with nonzero rc
    When gcov read is called with path "nonexistent.py" expecting error
    Then gcov a FileNotFoundError should be stored

  # -- read() fallback: direct filesystem read with UTF-8 content (L116-123) --

  Scenario: Read fallback reads UTF-8 file from filesystem
    Given gcov a handler with a git repo and a real file "hello.txt"
    And gcov subprocess run is mocked to fail git show with nonzero rc
    When gcov read is called with path "hello.txt"
    Then gcov the result encoding should be "utf-8"
    And gcov the result should have a content_hash

  # -- read() fallback: direct filesystem read with binary content (L121-122) --

  Scenario: Read fallback detects binary file from filesystem
    Given gcov a handler with a git repo and a real binary file "pic.bin"
    And gcov subprocess run is mocked to fail git show with nonzero rc
    When gcov read is called with path "pic.bin"
    Then gcov the result encoding should be None

  # -- delete() with empty path → PermissionError (L166) --

  Scenario: Delete with empty path raises PermissionError
    Given gcov a handler with a git repo location
    When gcov delete is called with empty path expecting error
    Then gcov a PermissionError should be stored

  # -- delete() when target does not exist → FileNotFoundError (L171-172) --

  Scenario: Delete raises FileNotFoundError for missing path
    Given gcov a handler with a git repo location
    When gcov delete is called with path "ghost.txt" expecting error
    Then gcov a FileNotFoundError should be stored

  # -- delete() when target is a directory → shutil.rmtree (L176, 178) --

  Scenario: Delete removes a directory via shutil.rmtree
    Given gcov a handler with a git repo containing subdirectory "subdir"
    When gcov delete is called with path "subdir"
    Then gcov the delete result should indicate success
    And gcov the directory "subdir" should no longer exist

  # -- list_children() when git ls-tree fails → os.listdir fallback (L217-224) --

  Scenario: List children falls back to os.listdir when git ls-tree fails
    Given gcov a handler with a git repo location
    And gcov subprocess run is mocked so git ls-tree returns nonzero
    When gcov list_children is called
    Then gcov the result should be a sorted list of filesystem entries

  # -- diff() with no changes (L271) --

  Scenario: Diff reports no changes when locations are identical
    Given gcov a handler with a git repo location
    And gcov subprocess run is mocked for diff with no changes
    When gcov diff is called with the same location as other
    Then gcov the diff result has_changes should be False
    And gcov the diff result unified_diff should be empty

  # -- discover_children() when git ls-tree fails → empty list (L328) --

  Scenario: Discover children returns empty list when git ls-tree fails
    Given gcov a handler with a git repo location
    And gcov subprocess run is mocked so git ls-tree -d returns nonzero
    When gcov discover_children is called
    Then gcov the result should be an empty list

  # -- discover_children() with empty dirname in output (L333) --

  Scenario: Discover children skips empty directory names in output
    Given gcov a handler with a git repo location
    And gcov subprocess run is mocked so git ls-tree -d returns blank lines
    When gcov discover_children is called
    Then gcov the result should contain only non-empty directory resources

  # -- create_checkpoint() with no active sandbox → RuntimeError (L365-367) --

  Scenario: Create checkpoint raises RuntimeError when no sandbox exists
    Given gcov a handler and a resource with location
    And gcov a sandbox manager that returns None for get_sandbox
    When gcov create_checkpoint is called expecting error
    Then gcov a RuntimeError should be stored with message "No active sandbox"

  # -- create_checkpoint() when git tag fails (L382) --

  Scenario: Create checkpoint raises RuntimeError when git tag fails
    Given gcov a handler and a resource with location
    And gcov a sandbox manager that returns a sandbox with context
    And gcov subprocess run is mocked so git tag returns nonzero
    When gcov create_checkpoint is called expecting error
    Then gcov a RuntimeError should be stored with message "git tag failed"

  # -- rollback_to() with no active sandbox → RuntimeError (L407-409) --

  Scenario: Rollback raises RuntimeError when no sandbox exists
    Given gcov a handler and a resource with location
    And gcov a sandbox manager that returns None for get_sandbox
    When gcov rollback_to is called expecting error
    Then gcov a RuntimeError should be stored with message "No active sandbox"

  # -- rollback_to() when git reset fails → RollbackResult(success=False) (L423-426) --

  Scenario: Rollback returns failure result when git reset fails
    Given gcov a handler and a resource with location
    And gcov a sandbox manager that returns a sandbox with context
    And gcov subprocess run is mocked so git reset returns nonzero
    When gcov rollback_to is called
    Then gcov the rollback result success should be False
    And gcov the rollback result message should contain "git reset --hard failed"
