graham-campbell/git-wrapper
A PHP wrapper around the Git command-line client that provides a clean, object-oriented API for running Git commands via Symfony Process. It simplifies repository operations like clone, checkout, commit, and log, with configurable binary paths and support for custom environments.
What the package is. A thin, object-oriented PHP wrapper around the git CLI. It shells out via symfony/process, returns structured output and exit codes, and throws GitException on failure. It adds no git capability of its own — every operation depends on the runtime binary and the filesystem state of a working copy. Treat it as a process-execution adapter, not a git implementation, and plan for the operational surface that implies.
Architecture fit. Appropriate only where "run git" is occasional and trusted-input: build/version stamping (git describe), changelog assembly from commit history, tag and branch inspection, repo metadata reads, and internal release/admin tooling. Poor fit for anything on the request path, anything multi-tenant, anything that lets external input reach refs/paths/remote URLs, and anything on ephemeral compute. The decision rule for planning: git work belongs in a queued job with a timeout, a capped output buffer, and a sandboxed working directory — never inline in a web request.
Integration feasibility. Mechanically trivial — composer require, instantiate, bind a configured singleton. Two questions must be resolved before design work is sequenced:
cpliakas/php-git. The answer determines whether integration is ~10–50 lines in AppServiceProvider or a version-constraint fight against illuminate/support. Confirm on the installed version.Technical risk.
GitCommand::__toString() — do not assume.CVE-2022-24765 (safe.directory), CVE-2022-39253, and CVE-2024-32002 (submodule RCE on clone) enter the threat model. Composer audit will not surface these.disable_functions, open_basedir, read-only filesystems; requires writable working copies and credentials on disk or in an agent.v1.1.2 specifically. Patch-level with no prose changelog, consistent with dependency-constraint housekeeping. Semver patch implies no API change and does not alter the adoption calculus; read the compare link for exact bumps before pinning.
Key questions for the TPM to close before committing:
Stack fit. PHP 8.x, modern Composer, pin ^1.1. Read it as framework-agnostic: require the package, then bind a configured singleton in AppServiceProvider with a fixed binary path, explicit timeout, and a logger. Do not publish or assume config that may not exist on this line. If the installed version is Laravel-glued to old constraints, take the fork-or-underlying-library path early rather than fighting the constraint.
Migration path, in preferred order.
RepositoryInspector, ReleaseTagger) so it stays an implementation detail and a swap remains cheap.Compatibility.
GIT_TERMINAL_PROMPT=0 and batch-mode SSH unconditionally so missing credentials fail fast instead of hanging a worker.new GitWrapper() at call sites.Sequencing.
Maintenance. Single-maintainer, low-touch upstream line; budget for owning the glue regardless of upstream activity. The recurring obligation is tracking git binary advisories, not Composer advisories — most teams do not have that in process today, so assign it explicitly with a named owner and a review cadence.
Support. No vendor. Escalation is reading the source, which is small. The difficult knowledge is not the package — it is git CLI semantics and working-copy state, which is precisely the knowledge that is not transferable from the library's documentation.
Scaling. Each operation is a fork/exec; throughput is bounded by process spawn cost and disk I/O. Concurrent operations against the same working copy contend on .git/index.lock — the dominant failure mode under load, and not solved by adding workers. Horizontal scaling fails outright if working copies live on ephemeral storage: you need a shared volume, job-per-repository affinity (a queue with a repository key), or a design with no persistent working copy at all.
Failure modes to instrument from day one.
index.lock contention; partial or corrupt clones on timeout or cancellation.safe.directory).log/diff filling memory — cap the output buffer.Ramp-up. A competent Laravel developer is productive in days; the API is small and the failure semantics are ordinary subprocess semantics. The real cost is the long tail of runtime-git failure modes that surface in production months later. Budget the on-call surface, not the integration effort, as the actual line item — and frame it that way to stakeholders when scoping the first feature.
How can I help you explore Laravel packages today?