Skip to content

Conversation

@tony
Copy link
Member

@tony tony commented Jan 31, 2026

Summary

Resolves #507

  • Config format: Define worktrees per repository targeting tags, branches, or commits
  • New CLI: vcspull worktree list|sync|prune subcommand
  • Integration: --include-worktrees flag added to sync, list, status, search, discover
  • Safety: Dirty worktrees block sync operations (BLOCKED action)
  • Discovery: Worktrees excluded by default (.git file detection)

Changes

File Description
types.py Add WorktreeConfigDict, extend ConfigDict
exc.py Add worktree exceptions
_internal/worktree_sync.py Core sync/prune/planning logic
config.py Parse and validate worktrees config
cli/worktree.py New worktree subcommand
cli/*.py Add --include-worktrees flag
cli/discover.py Add is_git_worktree() helper
test_worktree.py 30 comprehensive tests

Example Config

~/repos/:
  myproject:
    repo: 'git+https://github.com/user/project'
    worktrees:
      - dir: ../myproject-v1.2.3
        tag: v1.2.3
      - dir: ../myproject-develop
        branch: develop

Test plan

  • All 767 tests pass
  • mypy passes
  • ruff check/format passes
  • Manual testing with real repositories

@codecov
Copy link

codecov bot commented Jan 31, 2026

Codecov Report

❌ Patch coverage is 84.79853% with 83 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.29%. Comparing base (bcfb4bb) to head (7b906d8).

Files with missing lines Patch % Lines
src/vcspull/cli/sync.py 14.81% 22 Missing and 1 partial ⚠️
src/vcspull/config.py 56.81% 11 Missing and 8 partials ⚠️
src/vcspull/cli/list.py 26.31% 12 Missing and 2 partials ⚠️
src/vcspull/_internal/worktree_sync.py 96.06% 5 Missing and 5 partials ⚠️
src/vcspull/cli/discover.py 61.90% 6 Missing and 2 partials ⚠️
src/vcspull/exc.py 55.55% 8 Missing ⚠️
src/vcspull/cli/worktree.py 99.30% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #508      +/-   ##
==========================================
+ Coverage   80.52%   81.29%   +0.77%     
==========================================
  Files          16       18       +2     
  Lines        2192     2727     +535     
  Branches      454      552      +98     
==========================================
+ Hits         1765     2217     +452     
- Misses        277      341      +64     
- Partials      150      169      +19     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request adds comprehensive git worktree support to vcspull, enabling users to manage multiple checkouts of the same repository at different branches, tags, or commits. The feature addresses issue #507, which requested the ability to rapidly clone repositories at different refs for LLM context harvesting and parallel work.

Changes:

  • Adds new WorktreeConfigDict type for worktree configuration with support for tags, branches, commits, detachment, and locking options
  • Introduces comprehensive worktree sync logic including planning, creation, updating, pruning, and dirty state detection
  • Adds new vcspull worktree CLI command with list, sync, and prune subcommands
  • Integrates --include-worktrees flag across existing commands (sync, list, status, search, discover)
  • Implements worktree detection to exclude them from discovery by default
  • Adds 30 tests covering config parsing, path resolution, sync planning, execution, and pruning

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/vcspull/types.py Defines WorktreeConfigDict with fields for dir, tag/branch/commit refs, detach, lock, and lock_reason
src/vcspull/exc.py Adds worktree-specific exception classes (WorktreeError, WorktreeExistsError, WorktreeRefNotFoundError, WorktreeConfigError, WorktreeDirtyError)
src/vcspull/_internal/worktree_sync.py Core worktree synchronization logic including planning, creation, update, pruning, and validation functions
src/vcspull/config.py Adds _validate_worktrees_config function to parse and validate worktree configuration from YAML/JSON
src/vcspull/cli/worktree.py New CLI command with list/sync/prune subcommands, output formatting, and color-coded status indicators
src/vcspull/cli/__init__.py Integrates worktree command into main CLI parser and routing
src/vcspull/cli/sync.py Adds --include-worktrees flag and integrates worktree sync after main repo sync
src/vcspull/cli/list.py Adds --include-worktrees flag to display worktrees in flat and tree views
src/vcspull/cli/status.py Adds --include-worktrees flag stub for future status integration
src/vcspull/cli/search.py Adds --include-worktrees flag stub for future search integration
src/vcspull/cli/discover.py Adds is_git_worktree() helper and --include-worktrees flag to control worktree discovery
tests/test_worktree.py Comprehensive test suite with 30 tests covering config parsing, validation, sync, prune, and CLI integration
tests/test_log.py Updates logger name list to include vcspull.cli.worktree

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@tony

This comment has been minimized.

@tony

This comment has been minimized.

@tony

This comment has been minimized.

tony added 19 commits February 1, 2026 05:49
why: Enable LLMs and developers to access repositories at multiple versions
simultaneously for context harvesting and parallel work (Issue #507).

what:
- Add WorktreeConfigDict type and extend ConfigDict in types.py
- Add worktree exceptions (WorktreeError, WorktreeExistsError, etc.) in exc.py
- Create worktree_sync.py module with sync/prune/planning logic
- Add worktree config validation in extract_repos()
- Create vcspull worktree CLI subcommand (list, sync, prune actions)
- Add --include-worktrees flag to sync, list, status, search, discover
- Add is_git_worktree() helper to filter worktrees from discovery
- Add 30 comprehensive tests for worktree functionality
why: The flags were added but never implemented - silently ignored.
what:
- Remove --include-worktrees from search subparser
- Remove --include-worktrees from status subparser
…ent comparison

why: Path mismatch between resolved configured paths and unresolved git paths
could cause valid worktrees to be incorrectly identified as orphaned.
what:
- Resolve worktree paths in list_existing_worktrees() before returning
why: CLAUDE.md requires all functions have working doctests.
what:
- Add doctest examples to all 14 functions
- Use doctest_namespace fixtures where git operations needed
why: Improve test coverage from 75.57% to 82%.
what:
- Add CLI tests for worktree list, sync, prune commands
- Add edge case tests for _is_worktree_dirty, _ref_exists, _get_worktree_head
- Add tests for validate_worktree_config edge cases
- Add test for plan_worktree_sync with invalid config
- Add test for sync_worktree branch UPDATE action
why: Fill 5 specific coverage gaps identified by analysis to improve
worktree module coverage from 81%→88% and CLI from 78%→83%.
what:
- Add test_sync_worktree_executes_update for UPDATE execution path
- Add test_sync_all_worktrees_counts_mixed for action counting
- Add test_cli_worktree_sync_no_repos for empty repos path
- Add test_cli_worktree_prune_no_repos for empty repos path
- Add test_cli_worktree_prune_no_orphans for no-orphans path
… CLI

why: Improve test coverage for worktree modules from 88%/83% toward 95%.
what:
- Add CreateWorktreeOptionsFixture for lock/detach options (lines 606-619)
- Add CLIFilteringFixture for pattern/workspace filtering (lines 133-153)
- Add test_worktree_exists_path_no_git for edge case (line 346)
- Add test_prune_worktree_failure for error handling (lines 824-826)
- Add test_cli_sync_skips_empty_worktrees (lines 201, 288)
- Add exception handling tests for _ref_exists, _is_worktree_dirty, _get_worktree_head
why: Improve test coverage from 94% toward 98%.
what:
- Add WorktreeActionOutputFixture for color branch coverage (lines 227-231)
- Add test_sync_worktree_unchanged_execution (lines 549-552)
- Add test_sync_worktree_oserror_exception (lines 557-559)
- Add test_handle_list_with_empty_worktrees_direct (line 201)
- Add test_handle_sync_with_empty_worktrees_direct (line 288)
- Add test_cli_prune_no_existing_worktrees (line 356)
- Add test_get_worktree_head_oserror (lines 305-306)
why: Submodules also have .git files with "gitdir:" but point to .git/modules/
what:
- Add check for "/worktrees/" in gitdir path to distinguish from submodules
- Worktrees point to .git/worktrees/, submodules point to .git/modules/
why: --dry-run flag was ignored for worktree operations
what:
- Pass dry_run parameter to sync_all_worktrees() instead of hardcoded False
why: Recursive and non-recursive discovery had inconsistent .git detection
what:
- Change (item / ".git").exists() to (item / ".git").is_dir()
- Both branches now consistently match only regular repos with .git directories
…onal doctests

why: CLAUDE.md requires doctests to actually execute and test behavior
what:
- Remove try/except pass workarounds from _create_worktree and _update_worktree
- Replace Examples sections with Notes sections referencing integration tests
why: NumPy docstring style requires all parameters to be documented
what:
- Add include_worktrees parameter to list_repos docstring
why: CLAUDE.md requires proper docstrings for all functions
what:
- Add Parameters sections to _add_common_args, _handle_list, _emit_worktree_entry,
  _handle_sync, _handle_prune
- Add Notes sections referencing integration tests
why: CLAUDE.md requires all functions to have working doctests
what:
- Add Examples section with valid config doctests
- Add error case doctests for invalid configurations
why: CLAUDE.md requires namespace imports for stdlib modules
what:
- Change from dataclasses import to import dataclasses
- Update @DataClass to @dataclasses.dataclass
- Update field() to dataclasses.field()
why: Git worktrees have .git as a file, not a directory
what:
- Add .is_file() check for non-recursive discovery
- Add .git file check for recursive discovery via os.walk
- Enables --include-worktrees to actually discover worktrees
…octests

why: CLAUDE.md requires all functions to have working doctests
what:
- Replace Notes section with Raises and Examples sections
- Add doctests showing FileNotFoundError for invalid paths
- Document subprocess.CalledProcessError and FileNotFoundError raises
tony added 3 commits February 1, 2026 06:56
why: Document bug where mappings inside YAML lists are incorrectly
flagged as duplicate top-level keys

what:
- Add test_duplicate_aware_reader_ignores_nested_list_mappings
- Mark with xfail until fix is applied
- Document root cause: PyYAML constructs list items after parent mappings
… in nested lists

why: PyYAML constructs sequence items after exiting parent mappings,
causing list item mappings to incorrectly appear as top-level keys

what:
- Replace _mapping_depth counter with _root_mapping_node tracking
- Only treat keys as top-level if their parent node IS the root
- Add docstring explaining PyYAML's construction order behavior
why: The nested list mapping bug is now fixed
what:
- Remove pytest.mark.xfail decorator
- Remove unused pytest import
tony added 3 commits February 1, 2026 07:26
…git command

why: git worktree add --lock does not support --reason option
what:
- Remove --reason from git worktree add command
- Call git worktree lock --reason separately after creation
- Add regression test for lock_reason functionality
why: branch parameter was unused, could pull wrong branch
what:
- Check current branch with git symbolic-ref
- Checkout expected branch if different
- Add regression test for branch verification
…tion

why: silent except clause made debugging difficult
what:
- Add log.debug explaining exception handling rationale
@tony
Copy link
Member Author

tony commented Feb 1, 2026

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

why: Documentation incorrectly stated lock_reason requires lock=True
what:
- Update docstring to reflect actual behavior: lock_reason implies lock=True
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.

git worktree for tags/refs

2 participants