Skip to content

Add GitService foundation + schema for git integration#8

Merged
JMRussas merged 6 commits intomainfrom
feature/git-integration
Mar 1, 2026
Merged

Add GitService foundation + schema for git integration#8
JMRussas merged 6 commits intomainfrom
feature/git-integration

Conversation

@JMRussas
Copy link
Owner

@JMRussas JMRussas commented Mar 1, 2026

Summary

  • Adds GitService — stateless git operations service wrapping subprocess calls via asyncio.to_thread() with configurable timeout
  • Adds schema migration (010) with git columns on projects (repo_path, git_base_branch, git_project_branch, git_worktree_path, git_state_json) and tasks (git_branch, git_commit_sha)
  • Wires git config constants, Pydantic schema fields, route updates for project create/update/read, and DI container registration

This is Phase 1 of 5 from the git integration plan. It adds the foundation (service + data model) without any execution wiring. Subsequent phases will integrate with the executor, add git tools for agents, API routes, and worktree isolation.

GitService capabilities

  • Repo validation, branch CRUD, checkout, merge (FF preferred, conflict detection)
  • Worktree create/remove
  • Stage + commit with configurable author
  • Diff (committed, staged, working), status, log
  • Dirty state detection with "is ours" heuristic (author match, .orchestration/ dir, branch prefix)
  • Backup dirty state to branch, discard changes, revert commits
  • Push branch, create PR via gh CLI (graceful fallback)

Config additions (config.example.json)

"git": {
  "enabled": true,
  "commit_author": "Orchestration Engine <orchestration@local>",
  "branch_prefix": "orch",
  "non_code_output_path": ".orchestration",
  "auto_pr": true,
  "pr_remote": "origin",
  "command_timeout": 30
}

Test plan

  • 33 new unit tests in tests/unit/test_git_service.py — all use real temp git repos, no mocking
  • Full test suite passes: 561 passed, 0 failed
  • Covers: repo validation, branch ops, commit ops, diff ops, status/log, dirty state detection, merge (FF/conflict/regular), worktree, backup/discard/revert, error handling

Generated by Claude Code · Claude Opus 4.6

@JMRussas
Copy link
Owner Author

JMRussas commented Mar 1, 2026

Self-Review Findings

Cross-branch contamination: CLEAN

Verified full git diff main...HEAD — no leaked changes from feature/mcp-external-executor (no claimed_by, claimed_at, api_keys, ExecutionMode, EXTERNAL_CLAIM_TIMEOUT_SECONDS).

Schema consistency: PASS

All 3 locations (connection.py inline, models_metadata.py SA, migration 010) define the same 7 columns with matching types and defaults.

Defects found and fixed (commit db8ee1f)

1. create_prTimeoutExpired not caught (git_service.py:455)
subprocess.TimeoutExpired inherits from SubprocessError, not OSError. If gh hangs past the timeout, the exception would propagate uncaught. Fixed by adding explicit except subprocess.TimeoutExpired clause.

2. get_log — pipe delimiter fragile (git_service.py:303)
Format %H|%an|%ae|%s|%aI uses | as delimiter, but commit subjects can contain |. Fixed by switching to ASCII unit separator (\x1f).

3. backup_dirty_state — docstring unclear (git_service.py:373)
Clarified that after backup, the original branch is left clean (all dirty changes committed to backup branch).

Known limitations (not bugs, intentional or deferred)

4. check_dirty file parsingline[3:] assumes standard --short format (2-char status + space). Renamed files (R old -> new) will parse oddly. Acceptable for Phase 1 — Phase 2 lifecycle hooks can use --porcelain for stricter parsing.

5. clone_project doesn't copy git columns — Cloned projects will have repo_path=NULL even if source had one. Intentional: clones start fresh; binding the same repo would cause conflicts.

JMRussas and others added 3 commits March 1, 2026 00:16
Core git operations service with subprocess-based git commands wrapped
in asyncio.to_thread(). Adds git columns to projects and tasks tables,
config constants, Pydantic schema fields, route updates, and DI wiring.

Phase 1 of 5 — no execution wiring yet, just the foundation.

- GitService: validate_repo, branch/checkout/merge/delete, worktree
  create/remove, stage_and_commit, diff/status/log, dirty state
  detection with "is ours" heuristic, backup/discard/revert, push, PR
- Migration 010: repo_path, git_base_branch, git_project_branch,
  git_worktree_path, git_state_json on projects; git_branch,
  git_commit_sha on tasks
- Config: git.enabled, commit_author, branch_prefix, auto_pr, etc.
- 33 unit tests using real temp repos (no git mocking)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tring

- create_pr: catch subprocess.TimeoutExpired separately (doesn't inherit
  from OSError, would propagate uncaught if gh hangs)
- get_log: use ASCII unit separator (\x1f) instead of pipe as delimiter
  to handle commit messages containing | characters
- backup_dirty_state: clarify docstring that original branch is left clean

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The analytics PR (merged to main) added migration 010_add_usage_task_index.
Our migration was also numbered 010 with an incorrect down_revision
("009_task_events_fk_and_indexes" instead of "009"). Renumber to 011
and chain from "010" to maintain a linear migration history.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@JMRussas JMRussas force-pushed the feature/git-integration branch from db8ee1f to fe22ba7 Compare March 1, 2026 05:22
merge_branch() only checked UU and AA conflict markers. Added DD,
AU, UA, DU, UD to cover all git unmerged states (both deleted,
add/modify, delete/modify conflicts).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@JMRussas
Copy link
Owner Author

JMRussas commented Mar 1, 2026

Post-Rebase Review

Reviewed the full diff (git diff origin/main...HEAD, 11 files, 971 insertions) after rebasing onto main (analytics PR merge).

Conflict resolution

  • models_metadata.py: Main already had our git columns (merged via analytics PR) plus claimed_by/claimed_at. Resolution: keep both. File has zero diff against main now.
  • Migration renumbered from 010 → 011, chaining from "010" (usage task index). The old down_revision was also wrong ("009_task_events_fk_and_indexes" vs actual revision ID "009").

Defect found and fixed (commit 182570c)

merge_branch() conflict file parsing was incomplete. Only matched UU and AA conflict markers, missing DD, AU, UA, DU, UD. The merge was correctly detected and aborted, but the conflict_files list would have been incomplete for non-standard conflicts. Fixed by checking against all 7 unmerged status codes.

Design limitation (not a bug, deferred)

ProjectUpdate can't set repo_path/git_base_branch back to NULL via PATCH. The if body.repo_path is not None pattern prevents clearing the field. Not an issue for Phase 1 (repo binding isn't wired to execution yet), but should be addressed in Phase 2.

Pre-existing issue on main (not this PR)

connection.py and models_metadata.py are out of sync: models_metadata.py has claimed_by, claimed_at, and api_keys table from the analytics PR, but connection.py (inline test schema) doesn't. This drift exists on main already.

Cross-contamination check: CLEAN

All 11 files are git-integration only. No analytics, external execution, API key, or other unrelated changes present.

JMRussas and others added 2 commits March 1, 2026 00:35
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- CLAUDE.md: add git_service.py, analytics.py to structure, add git
  convention, update test counts (578 backend, 137 frontend)
- architecture.md: update container tree (all 13 providers), expand
  schema to 10+ tables, add Git Integration section with phase status,
  add git-related gotchas, update dep map and test counts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@JMRussas JMRussas merged commit ffb441f into main Mar 1, 2026
3 checks passed
@JMRussas JMRussas deleted the feature/git-integration branch March 1, 2026 23:02
@JMRussas JMRussas mentioned this pull request Mar 3, 2026
3 tasks
JMRussas added a commit that referenced this pull request Mar 4, 2026
…nd more

- Extract shared JSON utilities to backend/utils/json_utils.py (#37)
- Fix quadratic token growth in Claude agent via message pruning (#8)
- Fix context forwarding race with per-dep transaction (#9)
- Fix budget leak on plan parse failure by recording spend before re-raise (#11)
- Fix verification feedback cap with proper sliding window (#17)
- Include RUNNING tasks in cancel_project (#18)
- Add retry limit check to review_task retry action (#19)
- Switch to paragraph-based requirement numbering (#21)
- Skip budget check for Ollama-only projects (#23)
- Make HTTP client timeout configurable (#35)
- Add timeout + budget skip to verifier and knowledge extractor (#36)
- Truncate long output before sending to verifier (#38)
- Add _reset_warned_models() with autouse fixture (#44)
- 22 new tests covering all findings

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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