Conversation
… compatibility (#38) Rebuilds GitSync on top of the GitHub REST API (Contents + Git Data) instead of shelling out to a local git binary. Same ability contracts, completely different implementation — works identically on self-hosted, WordPress.com Business, WP Engine, Pantheon, and local dev. ## Why Phase 1 + 2 shelled out to git via Workspace-style primitives. That locked GitSync out of every managed host (exec disabled, no git binary, no writable dirs outside wp-content). Since the actual consumer use cases — wiki content sync, agent definition sync — are file-level operations that map cleanly to 'PUT /repos/:slug/contents/:path', shell-git was the wrong tool for the job. DMC is already hybrid: - Workspace = shell git (for agent code-editing workflows) - GitHubAbilities = REST API (for issues, PRs, file CRUD) GitSync fits firmly in the second category — its needs were never the shell-git ones (no interactive rebase, no multi-file staging, no local branches). Rebuilding on GitHubAbilities' surface collapses ~2000 LOC of stash/branch/rebase orchestration to ~1100 LOC of straight HTTP calls, and works on every WordPress host. ## Changes New files: - inc/GitSync/GitSyncFetcher.php — pull implementation. Reads the recursive tree via GET git/trees/:branch, compares each blob's SHA to a local file's git-blob-sha (sha1('blob '+len+'\0'+content), the same formula GitHub uses), GETs mismatched blobs via the Contents API, writes to disk. Tracks pulled_paths so upstream deletions propagate locally while consumer-added files stay untouched. Handles the Contents API's 1MB truncation by falling back to GET /git/blobs/:sha. - inc/GitSync/GitSyncProposer.php — submit + push implementation. Submit: GET /git/ref/heads/:pinned for base SHA, ensure gitsync/<slug> exists at base SHA via POST or PATCH /git/refs, PUT /contents/:path for each changed file on the feature branch, open or PATCH the PR via /pulls. Push: same but targets pinned branch directly (gated by two-key auth: write_enabled AND safe_direct_push). Deleted files: - inc/GitSync/GitSyncSubmitter.php — the shell-git orchestrator with its stash/reset/checkout-B/pop/push dance. Replaced by GitSyncProposer which does the same job via five HTTP calls. - inc/GitSync/GitRepo.php — readHead/readBranch/countDirty shell helpers. No local git state to read anymore; upstream state comes from the API directly. Rewritten: - inc/GitSync/GitSync.php — facade slimmed to bind/unbind/pull/ submit/push/status/list/updatePolicy. Delegates pull to Fetcher, submit/push to Proposer. No internal git ops. - inc/GitSync/GitSyncBinding.php — policy shape slightly simplified: add pulled_paths (list of files this binding owns on disk, for delete detection); tighten remote_url validation to GitHub URLs only (file:// dropped — no local-remote test case anymore, smoke uses HTTP mocking instead). DEFAULT_POLICY retains write_enabled, safe_direct_push, allowed_paths, conflict; auto_pull/pull_interval stay as future-scheduler hints. - inc/Abilities/GitSyncAbilities.php — 8 abilities (was 10). Dropped gitsync-add and gitsync-commit since the API-first flow has no separate staging step — consumer writes files to disk, calls submit directly, Proposer diffs and uploads. Kept bind, unbind, list, status, pull, submit, push, policy-update. - inc/Cli/Commands/GitSyncCommand.php — corresponding CLI surface. - inc/Support/GitHubRemote.php — pushUrlWithPat() dropped (no URL push happens anymore). Kept isGitHubRemote, slug, apiUrl. - tests/smoke-gitsync.php — 45-assertion end-to-end smoke using wp_remote_request mocking. Covers: validation, bind, pull, idempotent re-pull, upstream-deletion propagation with untracked- file preservation, conflict policies (fail/upstream_wins), submit gate enforcement, submit creates PR, submit updates PR, nothing-to-submit, push two-key auth, status/list/unbind/purge, policy validation (unknown keys, orphan safe_direct_push, bad conflict strategy). Runs in ~100ms with zero network. Deleted: - tests/smoke-gitsync-write.php — merged into tests/smoke-gitsync.php since the API-first implementation doesn't have separate read/write test paths. ## Smokes tests/smoke-gitsync.php 45/45 passing tests/smoke-worktree-handles.php 32/32 passing (Workspace unchanged) ## Binding shape migration Phase 1+2 shipped briefly between #39 and this PR. Any binding saved by those versions rehydrates cleanly here via GitSyncBinding::fromArray (pulled_paths defaults to empty, file:// remotes get rejected on first re-save). No explicit migration — fresh installs are unaffected. ## Known limitations - GitHub-only. Non-GitHub remotes refused at bind time. - Per-file commits on submit (N files = N commits). PR reviewers see the aggregate diff; Git Data API optimization (single tree + commit + ref update) is a follow-up. - No deletion propagation on submit. Deleting a file upstream is a manual step, then pull. - Scheduled sync not implemented. auto_pull/pull_interval are stored metadata that a future task can consume. Refs: #38
3387665 to
f976071
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces the shell-git GitSync from #39 + #41 with an API-first implementation that works on every WordPress host — self-hosted, WordPress.com Business, WP Engine, Pantheon, Kinsta, local dev. Same ability contracts; completely different implementation.
Why
Phase 1 + 2 (shipped in #39 + #41) shelled out to the local `git` binary. That ruled out every managed host — `exec()` disabled, no `git` in PATH, no writable dirs outside `wp-content`. Not a viable long-term substrate for Intelligence's wiki sync or Matt's personal-agent scenarios.
DMC is already hybrid:
GitSync's actual use cases — wiki content, agent definitions — are file-level content sync that maps cleanly to `PUT /repos/:slug/contents/:path`. The shell-git inheritance from Workspace was the wrong primary layer. Rebuilding on GitHubAbilities' surface collapses ~2000 LOC of stash/branch/rebase orchestration to straight HTTP calls.
What changes
Gone
New
Rewritten
Smokes
Surface summary
Known limitations
Files
Next
With this landed, GitSync is ready to be consumed — but (per the separate concern Chris raised in the discussion thread) the DB ↔ disk bridge for each consumer CPT lives outside this PR. Intelligence#31 and Intelligence#125 each need their own bridge that turns DB records into disk files (for submit) and vice versa (after pull). That's a consumer concern; GitSync's contract is disk ↔ upstream only. Deliberate boundary.
Refs: #38