wp-php-toolkit / git
Git component for WordPress.
Package info
pkg:composer/wp-php-toolkit/git
Requires
- php: >=7.2
- wp-php-toolkit/bytestream: ^0.8
- wp-php-toolkit/filesystem: ^0.8
- wp-php-toolkit/http-client: ^0.8
Requires (Dev)
- phpunit/phpunit: ^9.5
- dev-trunk
- v0.8.0
- v0.7.9
- v0.7.8
- v0.7.7
- v0.7.6
- v0.7.5
- v0.7.4
- v0.7.3
- v0.7.2
- v0.7.1
- v0.7.0
- v0.6.2
- v0.6.1
- v0.6.0
- v0.5.1
- v0.5.0
- v0.4.1
- v0.4.0
- v0.3.1
- v0.3.0
- v0.2.0
- v0.1.5
- v0.1.4
- v0.1.3
- v0.1.2
- v0.1.1
- v0.1.0
- 0.0.19
- 0.0.18
- 0.0.17
- 0.0.16
- v0.0.15
- v0.0.15-alpha
- 0.0.14
- 0.0.13
- 0.0.12
- 0.0.11
- v0.0.8-alpha
- 0.0.7
- v0.0.7-alpha
- 0.0.6
- v0.0.6-alpha
- v0.0.5-alpha
- v0.0.4-alpha
- v0.0.3-alpha
- v0.0.2-alpha
- v0.0.1-alpha
This package is auto-updated.
Last update: 2026-05-19 20:25:29 UTC
README
| slug | git | |||
|---|---|---|---|---|
| title | Git | |||
| install | wp-php-toolkit/git | |||
| see_also |
|
A PHP implementation of core Git repository operations plus HTTP protocol helpers. Commits, branches, diffs, and selected push/pull workflows run without shelling out to git.
Why this exists
Git is a useful storage model even when a server cannot run the git binary: snapshots, branches, object-addressed files, diffs, merges, and sync over HTTP. That matters for WordPress tools that want revision history for generated files, content snapshots, site state, or collaborative edits in constrained runtimes.
The Git component implements the core repository operations in PHP and stores objects through the toolkit Filesystem interface. That means the same repository can live on disk, in memory, or in another backend, and higher-level code can commit files without knowing where objects are stored. It is a toolkit implementation for supported workflows, not a complete replacement for every git command and protocol edge case.
Git object storage and pack processing use zlib compression through the ByteStream compression filters.
The docs start with simple commits because that mental model scales: a repository is just objects plus refs. From there, branches, history walking, root commits, and merges become details you can reason about instead of magic shell behavior.
Choose it for tests, browser-like sandboxes, hosted WordPress environments, and applications that need Git behavior through PHP APIs instead of shell commands.
Commit files into an in-memory repo
The simplest possible repository: an InMemoryFilesystem as object storage and one commit() call. Reach for this in tests, in WP-CLI snapshots, or any place you want versioning without touching disk.
<?php require '/php-toolkit/vendor/autoload.php'; use WordPress\Filesystem\InMemoryFilesystem; use WordPress\Git\GitRepository; $repo = new GitRepository( InMemoryFilesystem::create() ); $oid = $repo->commit( array( 'updates' => array( 'README.md' => "# My Project\n", 'src/hello-world.php' => '<?php echo "Hello!";', ), ) ); echo "commit: {$oid}\n"; echo "HEAD: " . $repo->get_branch_tip( 'HEAD' ) . "\n"; echo "README: " . $repo->read_object_by_path( '/README.md' )->consume_all();
commit: <oid>
HEAD: <oid>
README: # My Project
Walk the commit history
Follow the parent chain from HEAD backwards. Building block for a WP-CLI "post revisions" log or a "what changed since release X" report.
<?php require '/php-toolkit/vendor/autoload.php'; use WordPress\Filesystem\InMemoryFilesystem; use WordPress\Git\GitRepository; use WordPress\Git\Model\Commit; $repo = new GitRepository( InMemoryFilesystem::create() ); foreach ( array( 'add intro', 'fix typo', 'expand examples' ) as $i => $msg ) { $repo->commit( array( 'updates' => array( 'post.md' => "# Draft {$i}" ), 'commit' => array( 'message' => $msg ), ) ); } $oid = $repo->get_branch_tip( 'HEAD' ); while ( ! Commit::is_null_hash( $oid ) ) { $c = $repo->read_object( $oid )->as_commit(); echo substr( $c->hash, 0, 7 ) . ' ' . trim( $c->message ) . "\n"; $oid = $c->get_first_parent_hash(); if ( ! $oid || ! $repo->has_object( $oid ) ) break; }
<hash> expand examples
<hash> fix typo
<hash> add intro
Treat a repository like a filesystem
GitFilesystem wraps a repository in this toolkit's Filesystem interface. With the default options, each put_contents() records a new commit.
<?php require '/php-toolkit/vendor/autoload.php'; use WordPress\Filesystem\InMemoryFilesystem; use WordPress\Git\GitFilesystem; use WordPress\Git\GitRepository; $repo = new GitRepository( InMemoryFilesystem::create() ); $fs = GitFilesystem::create( $repo ); $fs->put_contents( '/posts/hello.md', "# Hello\nFirst draft." ); $fs->put_contents( '/posts/about.md', "# About\nWho we are." ); $fs->put_contents( '/posts/hello.md', "# Hello\nSecond draft." ); echo "tree:\n"; foreach ( $fs->ls( '/posts' ) as $name ) { echo " /posts/{$name}\n"; } echo "\nhello.md now:\n" . $fs->get_contents( '/posts/hello.md' ) . "\n";
tree:
/posts/about.md
/posts/hello.md
hello.md now:
# Hello
Second draft.
Branch, edit, and switch back
Create a feature branch off the current commit, change files, flip HEAD back. Useful for experimental edits in collaborative tools.
<?php require '/php-toolkit/vendor/autoload.php'; use WordPress\Filesystem\InMemoryFilesystem; use WordPress\Git\GitRepository; $repo = new GitRepository( InMemoryFilesystem::create() ); $base = $repo->commit( array( 'updates' => array( 'config.json' => '{"flag":false}' ), 'commit' => array( 'message' => 'baseline' ), ) ); $repo->create_branch( 'refs/heads/experiment', $base ); $repo->checkout( 'refs/heads/experiment' ); $repo->commit( array( 'updates' => array( 'config.json' => '{"flag":true}' ), 'commit' => array( 'message' => 'flip the flag' ), ) ); echo "on experiment: " . $repo->read_object_by_path( '/config.json' )->consume_all() . "\n"; $repo->checkout( 'refs/heads/trunk' ); echo "on trunk: " . $repo->read_object_by_path( '/config.json' )->consume_all() . "\n";
on experiment: {"flag":true}
on trunk: {"flag":false}
Three-way merge two branches
The classic Git workflow: branch off, edit on each side, merge. $repo->merge() finds the common ancestor, three-way-merges every file, and creates a merge commit.
<?php require '/php-toolkit/vendor/autoload.php'; use WordPress\Filesystem\InMemoryFilesystem; use WordPress\Git\GitRepository; $repo = new GitRepository( InMemoryFilesystem::create() ); $base = $repo->commit( array( 'updates' => array( 'todo.txt' => "buy milk\nwalk dog\nread book\n", ) ) ); $repo->commit( array( 'updates' => array( 'todo.txt' => "buy oat milk\nwalk dog\nread book\n", ) ) ); $repo->create_branch( 'refs/heads/feature', $base ); $repo->checkout( 'refs/heads/feature' ); $repo->commit( array( 'updates' => array( 'todo.txt' => "buy milk\nwalk dog\nread book\nwrite blog post\n", ) ) ); $repo->checkout( 'refs/heads/trunk' ); $result = $repo->merge( 'refs/heads/feature' ); echo "merge head: {$result['new_head']}\n"; echo "conflicts: " . ( $result['conflicts'] ? implode( ',', $result['conflicts'] ) : 'none' ) . "\n"; echo "result:\n" . $repo->read_object_by_path( '/todo.txt' )->consume_all();
merge head: <oid>
conflicts: none
result:
buy oat milk
walk dog
read book
write blog post
Snapshot WordPress options into a repo
Serialize a chunk of WP state (options, post meta, a theme config) on every save and commit it. You get free history, diffs between snapshots, and a "rollback to last week" button.
<?php require '/php-toolkit/vendor/autoload.php'; use WordPress\Filesystem\InMemoryFilesystem; use WordPress\Git\GitRepository; $repo = new GitRepository( InMemoryFilesystem::create() ); $snapshots = array( array( 'blogname' => 'My Site', 'posts_per_page' => 10, 'timezone_string' => 'UTC' ), array( 'blogname' => 'My Site', 'posts_per_page' => 20, 'timezone_string' => 'UTC' ), array( 'blogname' => 'New Name', 'posts_per_page' => 20, 'timezone_string' => 'Europe/Warsaw' ), ); foreach ( $snapshots as $i => $options ) { $repo->commit( array( 'updates' => array( 'options.json' => json_encode( $options, JSON_PRETTY_PRINT ) ), 'commit' => array( 'message' => "snapshot #{$i}" ), ) ); } $head = $repo->get_branch_tip( 'HEAD' ); $parent = $repo->read_object( $head )->as_commit()->get_first_parent_hash(); $diff = $repo->diff_commits( $head, $parent ); echo "Files changed in last snapshot:\n"; foreach ( $diff as $name => $entry ) { echo " {$name}\n"; }
Files changed in last snapshot:
options.json