jbtcd/git-bundle
jbtcd/git-bundle is a Git integration bundle for PHP and Symfony applications, providing services and commands to inspect repositories, run common Git operations, and bring version control data into your app. It helps automate repository workflows and simplify Git-related tasks.
jbtcd/git-bundle is a PHP package that shells out to git and exposes the current branch, commit hash, tag, and commit date to your application — most commonly for asset cache-busting query strings and a "version" stamp in the footer or /health endpoint.
Read the upgrade guide before installing. The only 2.0.0 artefact published is a compare link (1.3.0...2.0.0). A major bump on a 1.x line means the maintainers have declared breaking changes, but the notes do not enumerate them. Pull the tag locally and diff the public API yourself:
composer require --dry-run jbtcd/git-bundle:^2.0
git clone https://github.com/jbtcd/git-bundle && cd git-bundle
git diff 1.3.0..2.0.0 -- src/ README.md UPGRADE*.md CHANGELOG.md
Focus the diff on constructor signatures, the config key names, and any renamed Twig/Blade-facing helpers — those are the things that break silently in a template.
Confirm the package is a Symfony bundle. The -bundle suffix and the jbtcd namespace follow Symfony's DI conventions, so expect a DependencyInjection/ extension and a *Bundle class rather than a Laravel ServiceProvider. In a Laravel app you will normally consume the underlying service class or a small factory directly and skip bundle registration entirely.
Verify the runtime prerequisite. The package needs the git binary on PATH and a readable .git directory at the configured root. Check both before wiring anything up:
git --version
php -r 'var_dump(is_dir(base_path(".git")));'
First use case — asset versioning. Resolve the short hash once at deploy, write it into config, and append it to your compiled asset URLs. This is the lowest-risk integration and immediately tells you whether the package is reading the right repository.
Resolve at deploy, not per request. A git invocation is a process spawn plus a filesystem walk; doing it inside a service provider or middleware on every request is a measurable latency hit and a needless failure surface. Resolve once in your deploy script and hand the value to the app as an environment variable:
// config/app.php
'asset_version' => env('ASSET_VERSION', 'dev'),
Wrap the package in a single accessor. Give yourself one seam so a future breaking change is a one-file fix rather than a grep across templates:
final class BuildInfo
{
public static function version(): string
{
return cache()->rememberForever('build.version', function () {
try {
return app(GitInfo::class)->getShortCommitHash();
} catch (\Throwable $e) {
report($e);
return 'dev';
}
});
}
}
Expose it to Blade through a view composer rather than calling the service from templates, so the fallback logic above is always in play:
View::composer('layouts.app', fn ($view) => $view->with('version', BuildInfo::version()));
Point it at a non-default repository root for monorepos and subdirectory deploys. If your Laravel app lives in apps/web but the deploy artifact keeps .git at the workspace root, the default lookup will fail. Configure the path explicitly and give it the workspace root:
'path' => base_path('../'), // verify the actual option name against 2.0's source
Treat CI as a first-class consumer. In a container build, run the resolver before the .git directory is stripped and bake the result into the image as ASSET_VERSION. This gives you a stable version string in production without shipping repository internals into the runtime image.
Use it for more than versioning. A health or diagnostics endpoint that reports commit hash and commit date makes it trivial to confirm which build is actually serving traffic — worth the five lines even if you never touch asset URLs.
Pin ^1.3 until you have read the 2.0.0 diff. The release notes carry no migration content, so an unpinned composer update in CI is the fastest way to discover a breaking change in production. Bump deliberately, on a branch, with the diff open.
Do not assume composer require will wire it up in Laravel. If 2.0 dropped or changed the bundle/extension class, any manual instantiation you copied from a 1.x snippet will break. After upgrading, instantiate through the container once and assert the value is non-empty in a test — a null version string fails silently and just stops busting caches, which is far harder to notice than an exception.
Shallow clones and detached HEAD are the two classic failure modes. git clone --depth 1 has no reachable tags, so any tag-based method returns nothing; and CI checkouts are usually on a detached HEAD, so getBranchName() gives you HEAD or throws. Guard both: fall back to the commit hash, and never let branch name reach a user-facing template unguarded.
Missing .git is not an edge case — it is the normal production state. Docker build contexts typically exclude it and composer install --no-dev deploy pipelines often strip it. Every call site needs a try/catch with a sane fallback ('dev'), or you will ship a 500 to the health check that was supposed to prove the app is healthy.
Escape and validate the repository path. The package constructs shell commands; a path sourced from user input or an unvalidated env var is command-injection territory. Keep the path in config/ or .env, never in a request parameter, and confirm in the 2.0 source that the package escapes arguments — if it does not, that is reason enough to route it through your own wrapper.
Cache aggressively and bust on deploy. rememberForever plus a deploy step that clears the specific key is the right shape. Do not put a short TTL on it — you would be re-spawning git on a timer for a value that only changes when you ship code.
Check whether 2.0 renamed the published config tag or config keys. Symfony bundle config keys are frequently renamed in majors (e.g. repository_path → path). If you publish config in 1.x and upgrade without republishing, you get an unknown-option error at boot — loud enough to be fine, but confusing if you were not expecting it.
Verify PHP and git version requirements before upgrading. Majors in this space routinely bump the minimum PHP constraint or move to a newer Gitonomy/Symfony process major. Run composer why-not jbtcd/git-bundle 2.0.0 after the upgrade attempt to get a precise blocker instead of guessing from a resolution error.
How can I help you explore Laravel packages today?