sebastian/git-state
PHP library to describe the state of a Git checkout. Retrieve origin URL, current branch and commit hash, and determine whether the working directory is clean or get a git-style status output. Useful for build/test tooling and CI metadata.
Installation Add the package via Composer:
composer require sebastian/git-state
For development-only usage (e.g., testing):
composer require --dev sebastian/git-state
First Use Case: Check Git State in a Laravel Artisan Command Create a new Artisan command to inspect Git state:
php artisan make:command GitStatus
Edit the generated file (app/Console/Commands/GitStatus.php):
use SebastianBergmann\GitState\Builder;
use Illuminate\Console\Command;
class GitStatus extends Command
{
protected $signature = 'git:status';
protected $description = 'Display the current Git repository state';
public function handle()
{
$builder = new Builder();
$state = $builder->build();
if ($state === false) {
$this->error('Not a Git repository or missing origin.');
return 1;
}
$this->info("Branch: {$state->branch()}");
$this->info("Commit: {$state->commit()}");
$this->info("Origin: {$state->originUrl()}");
$this->info($state->isClean() ? 'Working directory is clean' : 'Working directory has changes');
if (!$state->isClean()) {
$this->line('Status:');
$this->line($state->status());
}
}
}
Run the command:
php artisan git:status
Where to Look First
GitState object.
$builder = new Builder();
$state = $builder->build();
$state->branch(): Current branch name.$state->commit(): Current commit hash.$state->originUrl(): Remote origin URL.$state->isClean(): Boolean indicating if the working directory is clean.$state->status(): String with Git status output.build() method returns false if not in a Git repo or missing an origin.Service Layer Integration Encapsulate Git state logic in a service class for reusability:
namespace App\Services;
use SebastianBergmann\GitState\Builder;
class GitStateService
{
public function getState()
{
$builder = new Builder();
$state = $builder->build();
if ($state === false) {
return null;
}
return [
'branch' => $state->branch(),
'commit' => $state->commit(),
'origin' => $state->originUrl(),
'is_clean' => $state->isClean(),
'status' => $state->status(),
];
}
}
Use the service in controllers or other services:
use App\Services\GitStateService;
class DeploymentController extends Controller
{
public function check(GitStateService $gitState)
{
$state = $gitState->getState();
if (!$state || !$state['is_clean']) {
abort(500, 'Git repository is not in a valid state for deployment.');
}
// Proceed with deployment
}
}
Middleware for Git State Validation Validate Git state before critical operations (e.g., deployments):
namespace App\Http\Middleware;
use Closure;
use App\Services\GitStateService;
class ValidateGitState
{
public function __construct(protected GitStateService $gitState)
{
}
public function handle($request, Closure $next)
{
$state = $this->gitState->getState();
if (!$state || !$state['is_clean']) {
abort(403, 'Git repository must be clean for this operation.');
}
return $next($request);
}
}
Register the middleware in app/Http/Kernel.php:
protected $routeMiddleware = [
// ...
'validate.git' => \App\Http\Middleware\ValidateGitState::class,
];
Use in routes:
Route::middleware(['validate.git'])->group(function () {
Route::post('/deploy', [DeploymentController::class, 'deploy']);
});
Artisan Commands for Git Operations Create custom commands for Git-related tasks:
php artisan make:command GitInfo
Example command to log Git state:
use SebastianBergmann\GitState\Builder;
use Illuminate\Console\Command;
class GitInfo extends Command
{
protected $signature = 'git:info';
protected $description = 'Log Git repository information';
public function handle()
{
$builder = new Builder();
$state = $builder->build();
if ($state === false) {
$this->error('Not a Git repository or missing origin.');
return 1;
}
\Log::info('Git State', [
'branch' => $state->branch(),
'commit' => $state->commit(),
'origin' => $state->originUrl(),
'is_clean' => $state->isClean(),
]);
$this->info('Git information logged successfully.');
}
}
Event Listeners for Git State Changes Trigger actions based on Git state (e.g., notify team if working directory is dirty):
namespace App\Listeners;
use App\Services\GitStateService;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class GitStateListener
{
public function __construct(protected GitStateService $gitState)
{
}
public function handle()
{
$state = $this->gitState->getState();
if ($state && !$state['is_clean']) {
// Notify team or log warning
\Log::warning('Dirty working directory detected', [
'status' => $state['status'],
]);
}
}
}
Register the listener in EventServiceProvider:
protected $listen = [
'app.started' => [
GitStateListener::class,
],
];
Caching Git State for Performance Cache Git state to avoid repeated Git command executions:
namespace App\Services;
use SebastianBergmann\GitState\Builder;
use Illuminate\Support\Facades\Cache;
class GitStateService
{
public function getState()
{
return Cache::remember('git.state', now()->addMinutes(5), function () {
$builder = new Builder();
$state = $builder->build();
return $state ? [
'branch' => $state->branch(),
'commit' => $state->commit(),
'origin' => $state->originUrl(),
'is_clean' => $state->isClean(),
'status' => $state->status(),
] : null;
});
}
}
Non-Git Repository Handling
build() method returns false if not in a Git repository or if the origin is missing.false and handle gracefully:
$state = $builder->build();
if ($state === false) {
throw new \RuntimeException('Not a Git repository or missing origin.');
}
git --version
git rev-parse --is-inside-work-tree
Git Command Failures
try {
$state = $builder->build();
} catch (\Exception $e) {
\Log::error('Git state error: ' . $e->getMessage());
return null;
}
Working Directory Changes
isClean() method checks for uncommitted changes. False positives can occur if Git ignores files or if the working directory is not as expected.status() to inspect changes:
if (!$state->isClean()) {
$this->line('Uncommitted changes:');
$this->line($state->status());
}
Remote URL Issues
originUrl() method may return unexpected values if the remote is misconfigured or named differently (e.g., upstream instead of origin).$originUrl = $state->originUrl();
if (empty($originUrl)) {
// Try fetching from other remotes or handle as
How can I help you explore Laravel packages today?