pitmaster / pitmaster
Pure PHP Git implementation. Reads and writes Git repositories without shelling out to git.
Requires
- php: ^8.2
- ext-json: *
- ext-mbstring: *
- ext-zlib: *
Requires (Dev)
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0
- squizlabs/php_codesniffer: ^3.0
README
Pure PHP Git implementation
What is Pitmaster?
Pitmaster reads and writes Git repositories in pure PHP. Core repository operations do not shell out to the git binary or rely on FFI. Objects, refs, pack files, the index, and smart HTTP transport are handled natively in PHP.
The problem: PHP applications that need to interact with Git repositories either shell out to the git binary (requires exec(), hard to deploy, security surface) or use FFI/extension bindings (complex setup, version coupling). There's no way to read a pack file, create a commit, or diff two trees from pure PHP.
Pitmaster solves this by implementing the Git object model, binary formats, and protocols natively:
- Read and write loose objects (blob, tree, commit, tag)
- Read and write pack files with full delta chain resolution
- Read and write the index (staging area)
- Compute diffs (Myers O(ND) algorithm, byte-exact with
git diff) - Three-way merge with conflict markers
- Walk commit graphs, compute merge bases
- Speak the Git smart HTTP protocol (clone, fetch, push)
Quick Start
composer require pitmaster/pitmaster
use Pitmaster\Pitmaster; // Open an existing repository $repo = Pitmaster::open('/path/to/project'); // Read $head = $repo->head(); // Current HEAD commit $log = $repo->log(10); // Last 10 commits $refs = $repo->allRefs(); // All branches and tags $obj = $repo->readObject($hash); // Any object by hash // Write $repo->add('src/main.php'); // Stage a file $repo->commit("Fix the bug\n"); // Create a commit $repo->createBranch('feature'); // Create a branch $repo->merge('feature'); // Merge a branch // Diff $diffs = $repo->diff(); // Unstaged changes $diffs = $repo->diffStaged(); // Staged changes $diffs = $repo->diffTree($treeA, $treeB); // Tree-to-tree // Status $status = $repo->status(); // WorkingTreeStatus foreach ($status as $entry) { echo $entry->shortFormat() . "\n"; // "M src/main.php" } // Network $repo->fetch('origin'); // Fetch from remote $repo->push('origin', 'main'); // Push to remote // Init and clone $repo = Pitmaster::init('/path/to/new'); $repo = Pitmaster::clone('https://github.com/user/repo.git', '/path');
CLI
Pitmaster ships with a CLI that mirrors a subset of git commands:
./vendor/bin/pitmaster log ./vendor/bin/pitmaster status ./vendor/bin/pitmaster diff ./vendor/bin/pitmaster show HEAD ./vendor/bin/pitmaster add file.txt ./vendor/bin/pitmaster commit -m "message" ./vendor/bin/pitmaster branch feature ./vendor/bin/pitmaster checkout feature ./vendor/bin/pitmaster merge feature ./vendor/bin/pitmaster stash push ./vendor/bin/pitmaster blame file.txt ./vendor/bin/pitmaster grep "pattern" ./vendor/bin/pitmaster tag v1.0 -m "Release" ./vendor/bin/pitmaster reset --hard HEAD~1 ./vendor/bin/pitmaster refs ./vendor/bin/pitmaster init
Testing
Pitmaster is exercised with unit tests, integration tests against the canonical git binary, and imported oracle-style scenarios from upstream Git implementations.
# Unit tests (no git binary needed) composer test:unit # Integration tests (verified against git) composer test:integration # All tests composer test # Static analysis composer analyse # Coding standards composer cs
The current suite covers unit behavior, end-to-end repository operations, and round-trip comparisons against git. Run composer test for the current totals in this checkout.
Requirements
- PHP 8.2+
ext-zlib(built-in)ext-mbstring(built-in)ext-json(built-in)
Core repository operations do not require the git binary or FFI. Optional features have extra runtime expectations: hook execution uses proc_open(), and SSH transport requires ext-ssh2.
Features
See SUPPORT_MATRIX.md for the full feature list. Highlights:
| Category | Features |
|---|---|
| Objects | Blob, tree, commit, tag (SHA-1 + SHA-256) |
| Storage | Loose objects, pack files (v1/v2 index, OFS/REF delta), MIDX, commit-graph |
| Index | v2/v3/v4 with extensions (TREE, REUC, FSMN) |
| Refs | Loose, packed, symbolic, reftable, reflog |
| Diff | Myers O(ND), patience, histogram, word diff, rename detection |
| Merge | Three-way, recursive, ours, octopus, fast-forward, conflict markers |
| Network | Smart HTTP (v1/v2), SSH, git://, dumb HTTP, bundles |
| Operations | add, commit, status, diff, merge, checkout, reset, stash, cherry-pick, revert, rebase, blame, grep, bisect, notes |
| Advanced | Submodules, worktrees, sparse checkout, hooks, LFS, rerere, fsmonitor |
Architecture
src/
├── Pitmaster.php # Static facade (open, init, clone)
├── Repository.php # All operations
├── Object/ # Blob, Tree, Commit, Tag, ObjectId
├── Storage/ # LooseObjectStore, PackFileStore, ObjectDatabase
├── Pack/ # PackFile, PackIndex, DeltaApplier, PackWriter
├── Index/ # Index reader/writer
├── Ref/ # LooseRefStore, PackedRefStore, RefDatabase
├── Diff/ # MyersDiff (O(ND)), TreeDiff, DiffResult
├── Merge/ # ThreeWayMerge, MergeBase, ConflictMarker
├── Graph/ # CommitWalker, Blame, Grep, Bisect, Rebase
├── Status/ # WorkingTreeStatus, GitIgnore, Fsmonitor
├── Protocol/ # SmartHttpClient, PktLine, UploadPackClient
├── Stash/ # Stash (push/pop/apply/list/drop)
├── Config/ # GitConfig, GitAttributes
├── Encoding/ # BinaryReader, VarInt, Leb128
├── Hooks/ # HookRunner
├── Lfs/ # LfsClient, LfsPointer
├── Submodule/ # SubmoduleManager
├── Worktree/ # WorktreeManager
├── Checkout/ # SparseCheckout
└── Exceptions/ # Typed exceptions
License
MIT