Hoppa till innehåll

Hooks

Git-krokar är körbara skript i .git/hooks/ som körs vid specifika tidpunkter under git-åtgärder. Pitmaster identifierar och anropar krokar med hjälp av PHPs processkontroll (proc_open).

Krokar körs som standard

Repositoryåtgärder kör automatiskt de hooks som anges under Hooks Pitmaster körs. Om du vill inaktivera dem för ett repository-handtag skickar du med alternativ när du öppnar det:

PHP
use Pitmaster\Pitmaster;

// Skip .git/hooks scripts for this handle
$repo = Pitmaster::open('/path/to/project', ['hooks' => false]);

// Start no processes at all: hooks, the fsmonitor hook, clone/fetch/push, and SSH are disabled
$repo = Pitmaster::open('/path/to/project', Pitmaster::processFreeOptions());

$repo->hooksEnabled();      // false
$repo->processesEnabled();  // false for the second handle

Pitmaster::init() och Pitmaster::clone() accepterar samma alternativ. För att köra en krok krävs proc_open(); på värdar där det är inaktiverat öppnar du arkiv med ['hooks' => false]. CLI öppnar alltid arkivet med krokar aktiverade.

Pitmaster letar endast efter krokar i <gitDir>/hooks. Den ignorerar core.hooksPath, och i ett länkat arbetsträd letar den i .git/worktrees/<name>/hooks, så de delade skripten i .git/hooks körs inte där (#12).

HookRunner, som beskrivs nedan, ignorerar dessa alternativ: om den anropas direkt körs kroken alltid.

HookRunner

PHP
use Pitmaster\Hooks\HookRunner;

$hooks = new HookRunner($repo->gitDir());

Kontrollera om en krok finns

PHP
if ($hooks->exists('pre-commit')) {
    echo "pre-commit hook is installed\n";
}

En krok finns om filen finns på .git/hooks/<name> och är körbar.

Kör en krok

PHP
$result = $hooks->run('pre-commit');

echo $result['exitCode'];  // 0 = success
echo $result['stdout'];    // Hook's standard output
echo $result['stderr'];    // Hook's standard error

Med argument

PHP
$result = $hooks->run('commit-msg', ['/path/to/COMMIT_EDITMSG']);

Med stdin

PHP
$result = $hooks->run('pre-push', ['origin', 'https://github.com/user/repo.git'], $stdinData);

Kroken pre-push tar emot ref-information via stdin.

Kontrollera om körningen lyckades

PHP
if ($hooks->runAndCheck('pre-commit')) {
    // Hook passed (exit code 0), proceed with commit
} else {
    // Hook rejected the operation
}

runAndCheck() är en praktisk metod som kör kroken och returnerar true om avslutningskoden är 0. Om kroken inte finns returnerar den true (ingen krok innebär ingen invändning).

Lista installerade krokar

PHP
$installed = $hooks->listHooks();
// ['pre-commit', 'commit-msg', 'post-checkout']

Listar alla körbara filer i .git/hooks/ (exkluderar filer av typen .sample).

run() returnerar avslutningskod 0 med tom utdata om kroken saknas eller inte är körbar. Om processen inte kan startas returnerar den avslutningskod 1 och skriver Failed to start hook till stderr.

Installera en krok

PHP
$hooks->install('pre-commit', "#!/bin/bash\nphp vendor/bin/phpcs --standard=PSR12 .\n");

Skriver skriptinnehållet till .git/hooks/<name> och anger körbehörighet (chmod 0755).

PHP
// Install a PHP hook
$hooks->install('pre-commit', <<<'HOOK'
#!/usr/bin/env php
<?php
// Run static analysis before commit
$output = [];
$returnCode = 0;
exec('php vendor/bin/phpstan analyse --no-progress 2>&1', $output, $returnCode);

if ($returnCode !== 0) {
    echo "PHPStan found errors:\n";
    echo implode("\n", $output) . "\n";
    exit(1);
}
HOOK);

Krokar som Pitmaster kör

HookRunner kan köra valfri krok med namn. Repository kör automatiskt följande:

Krok Körs av Argument Kan avbryta?
pre-commit commit() inga Ja (avslutningskod som inte är noll)
prepare-commit-msg commit() meddelandefil, sedan message (eller merge när en sammanslagning slutförs) Ja
commit-msg commit() meddelandefil (.git/COMMIT_EDITMSG); ändringar i filen används Ja (avslutningskod som inte är noll)
post-commit commit() inga Nej (endast information)
pre-rebase rebase() uppströmsrevisionen Ja
post-checkout checkout() gammalt HEAD, nytt HEAD, 1 Nej (endast information)
post-merge merge(), mergeOctopus(), mergeContinue() 0 Nej (endast information)
pre-push push() och dess varianter fjärrnamn, URL; ref-rader via stdin Ja (avslutningskod som inte är noll)

Om en krok misslyckas kastar operationen RuntimeException('<name> hook failed'); krokens utdata inkluderas inte. Commit-krokar körs endast från commit(): merge-commits som skapas av merge() kör dem inte. post-checkout körs inte för addWorktree(), reset() eller restore().

Krokar på serversidan (pre-receive, update, post-receive, post-update), pre-auto-gc och post-rewrite körs aldrig automatiskt.

Krokens miljö

När Pitmaster kör en krok skickar den med följande miljö:

PHP
$env = [
    'GIT_DIR' => $this->gitDir,
    'GIT_WORK_TREE' => dirname($this->gitDir),
];

Detta är de enda variabler som kroken får: PATH, HOME och alla andra variabler i processen PHP skickas inte vidare (#13). Använd absoluta sökvägar i krokskript eller ange PATH i skriptet; en shebang med #!/usr/bin/env php hittar bara tolkar i systemets standardsökväg.

Kroken körs i dirname($gitDir), vilket är arbetskatalogen för en vanlig .git-katalog.

Format för krokskript

Krokar kan skrivas i valfritt språk. Den första raden måste vara en shebang:

Shell
#!/bin/bash
# Bash hook
PHP
#!/usr/bin/env php
<?php
// PHP hook
Python
#!/usr/bin/env python3
# Python hook

Exempel: pre-commit med Pitmaster

commit() kör redan pre-commit, prepare-commit-msg, commit-msg och post-commit, så programkoden behöver bara hantera felet:

PHP
try {
    $commitId = $repo->commit('Add feature');
} catch (\RuntimeException $e) {
    echo $e->getMessage(); // "pre-commit hook failed"
}

Anropa HookRunner själv endast med ett handtag som öppnats med ['hooks' => false] eller för krokar som Pitmaster inte kör.

Exempel på krokar

Git initierar arkiv med .sample-krokfiler; Pitmaster::init() skapar en tom hooks/-katalog. Pitmasters listHooks() utesluter .sample-filer:

Kod
.git/hooks/
  pre-commit.sample       (excluded from listHooks)
  commit-msg.sample       (excluded from listHooks)
  pre-commit              (included - installed by user)