Įskiepiai
Git kabliai yra vykdomi scenarijai .git/hooks/ aplinkoje, paleidžiami tam tikrais git operacijų momentais. Pitmaster aptinka ir iškviečia kablius naudodama PHP procesų valdymą (proc_open).
Kabliai vykdomi pagal numatytuosius nustatymus
Saugyklos operacijos automatiškai vykdo Kabliai Pitmaster nurodytus kablius. Norėdami juos išjungti saugyklos deskriptoriui, perduokite parinktis jį atidarydami:
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() ir Pitmaster::clone() priima tas pačias parinktis. Kabliui vykdyti reikia proc_open(); aplinkose, kuriose jis išjungtas, atidarykite saugyklas su ['hooks' => false]. CLI visada atidaro saugyklą su įjungtais kabliais.
Pitmaster kablių ieško tik <gitDir>/hooks. Jis nepaiso core.hooksPath, o susietame darbiniame medyje ieško .git/worktrees/<name>/hooks, todėl bendrinami .git/hooks scenarijai ten nevykdomi (#12).
HookRunner, aprašytas toliau, šių parinkčių nepaiso: iškvietus jį tiesiogiai, kablys visada vykdomas.
HookRunner
use Pitmaster\Hooks\HookRunner;
$hooks = new HookRunner($repo->gitDir());
Tikrinimas, ar kablys yra
if ($hooks->exists('pre-commit')) {
echo "pre-commit hook is installed\n";
}
Kablys laikomas esančiu, jei failas yra .git/hooks/<name> ir yra vykdomas.
Kabliuko vykdymas
$result = $hooks->run('pre-commit');
echo $result['exitCode']; // 0 = success
echo $result['stdout']; // Hook's standard output
echo $result['stderr']; // Hook's standard error
Su argumentais
$result = $hooks->run('commit-msg', ['/path/to/COMMIT_EDITMSG']);
Su stdin
$result = $hooks->run('pre-push', ['origin', 'https://github.com/user/repo.git'], $stdinData);
pre-push kabliui informacija apie nuorodas perduodama per stdin.
Sėkmės tikrinimas
if ($hooks->runAndCheck('pre-commit')) {
// Hook passed (exit code 0), proceed with commit
} else {
// Hook rejected the operation
}
runAndCheck() yra patogumo funkcija: ji vykdo kablį ir grąžina true, jei išėjimo kodas yra 0. Jei kablio nėra, grąžinama true (kablio nebuvimas reiškia, kad nėra prieštaravimų).
Įdiegtų kablių sąrašas
$installed = $hooks->listHooks();
// ['pre-commit', 'commit-msg', 'post-checkout']
Išvardija visus vykdomus failus aplanke .git/hooks/ (neįtraukia .sample failų).
run(), jei kablio nėra arba jis nevykdomas, grąžina išėjimo kodą 0 ir tuščią išvestį. Jei proceso nepavyksta paleisti, grąžinamas išėjimo kodas 1, o Failed to start hook pateikiamas stderr.
Kabliuko diegimas
$hooks->install('pre-commit', "#!/bin/bash\nphp vendor/bin/phpcs --standard=PSR12 .\n");
Įrašo scenarijaus turinį į .git/hooks/<name> ir nustato vykdymo leidimą (chmod 0755).
// 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);
Kabliai, kuriuos vykdo Pitmaster
HookRunner gali vykdyti bet kurį kablį pagal pavadinimą. Repository automatiškai vykdo šiuos:
| Kablys | Vykdo | Argumentai | Gali nutraukti? |
|---|---|---|---|
pre-commit |
commit() |
nėra | Taip (ne nulinis išėjimo kodas) |
prepare-commit-msg |
commit() |
pranešimo failas, tada message (arba merge užbaigiant sujungimą) |
Taip |
commit-msg |
commit() |
pranešimo failas (.git/COMMIT_EDITMSG); failo pakeitimai naudojami |
Taip (ne nulinis išėjimo kodas) |
post-commit |
commit() |
nėra | Ne (informacinis) |
pre-rebase |
rebase() |
pirminės šakos revizija | Taip |
post-checkout |
checkout() |
senasis HEAD, naujasis HEAD, 1 |
Ne (informacinis) |
post-merge |
merge(), mergeOctopus(), mergeContinue() |
0 |
Ne (informacinis) |
pre-push |
push() ir jo variantai |
nuotolinės saugyklos pavadinimas, URL; nuorodų eilutės per stdin | Taip (ne nulinis išėjimo kodas) |
Neveikiančio kablio vykdymas priverčia operaciją išmesti RuntimeException('<name> hook failed'); kablio išvestis neįtraukiama. Commit kabliai vykdomi tik iš commit(): sujungimo commit, sukurtas naudojant merge(), jų nevykdo. post-checkout nevykdomas su addWorktree(), reset() ar restore().
Serverio pusės kabliai (pre-receive, update, post-receive, post-update), pre-auto-gc ir post-rewrite niekada nevykdomi automatiškai.
Kablių aplinka
Kai Pitmaster vykdo kablį, perduodama ši aplinka:
$env = [
'GIT_DIR' => $this->gitDir,
'GIT_WORK_TREE' => dirname($this->gitDir),
];
Tai vieninteliai kabliui perduodami kintamieji: PATH, HOME ir visi kiti PHP proceso kintamieji neperduodami (#13). Kablių scenarijuose naudokite absoliučiuosius kelius arba scenarijaus viduje nustatykite PATH; #!/usr/bin/env php shebang randa interpretatorius tik numatytajame sistemos kelyje.
Kablys vykdomas dirname($gitDir) kataloge, kuris įprastos .git saugyklos atveju yra darbinis medis.
Kablių scenarijų formatas
Kablius galima rašyti bet kuria kalba. Pirmoji eilutė turi būti shebang:
#!/bin/bash
# Bash hook
#!/usr/bin/env php
<?php
// PHP hook
#!/usr/bin/env python3
# Python hook
Pavyzdys: pre-commit su Pitmaster
commit() jau vykdo pre-commit, prepare-commit-msg, commit-msg ir post-commit, todėl programos kodui tereikia apdoroti nesėkmę:
try {
$commitId = $repo->commit('Add feature');
} catch (\RuntimeException $e) {
echo $e->getMessage(); // "pre-commit hook failed"
}
HookRunner kvieskite patys tik tada, kai deskriptorius atidarytas su ['hooks' => false], arba kai vykdomi kabliai, kurių Pitmaster nevykdo.
Kablių pavyzdžiai
Git inicijuoja saugyklas su .sample kablių failais; Pitmaster::init() sukuria tuščią hooks/ katalogą. Pitmaster listHooks() neįtraukia .sample failų:
.git/hooks/
pre-commit.sample (excluded from listHooks)
commit-msg.sample (excluded from listHooks)
pre-commit (included - installed by user)