Hooky
Obslužné skripty Git sú spustiteľné skripty v .git/hooks/, ktoré sa spúšťajú v konkrétnych fázach operácií git. Pitmaster ich zisťuje a spúšťa pomocou riadenia procesov v PHP (proc_open).
Obslužné skripty sa spúšťajú predvolene
Operácie s repozitárom automaticky spúšťajú hooky uvedené v časti Háčiky Pitmaster sa spúšťajú. Ak ich chcete pre konkrétny handle repozitára vypnúť, pri jeho otvorení odovzdajte možnosti:
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
Pre Pitmaster::init() aj Pitmaster::clone() platia rovnaké možnosti. Spúšťanie obslužného skriptu vyžaduje proc_open(); na hostiteľských systémoch, ktoré ho zakazujú, otvárajte repozitáre pomocou ['hooks' => false]. Trieda CLI vždy otvára repozitár so zapnutými obslužnými skriptmi.
Pitmaster hľadá obslužné skripty iba v <gitDir>/hooks. core.hooksPath ignoruje a v prepojenom pracovnom strome ich hľadá v .git/worktrees/<name>/hooks, preto sa tam zdieľané skripty .git/hooks nespustia (#12).
Funkcia HookRunner, opísaná nižšie, tieto možnosti ignoruje: pri priamom zavolaní vždy spustí obslužný skript.
HookRunner
use Pitmaster\Hooks\HookRunner;
$hooks = new HookRunner($repo->gitDir());
Kontrola existencie obslužného skriptu
if ($hooks->exists('pre-commit')) {
echo "pre-commit hook is installed\n";
}
Obslužný skript existuje, ak sa súbor nachádza v .git/hooks/<name> a má nastavené právo na spustenie.
Spustenie obslužného skriptu
$result = $hooks->run('pre-commit');
echo $result['exitCode']; // 0 = success
echo $result['stdout']; // Hook's standard output
echo $result['stderr']; // Hook's standard error
S argumentmi
$result = $hooks->run('commit-msg', ['/path/to/COMMIT_EDITMSG']);
So štandardným vstupom
$result = $hooks->run('pre-push', ['origin', 'https://github.com/user/repo.git'], $stdinData);
Obslužný skript pre-push prijíma informácie o referencii zo štandardného vstupu.
Kontrola úspešného vykonania
if ($hooks->runAndCheck('pre-commit')) {
// Hook passed (exit code 0), proceed with commit
} else {
// Hook rejected the operation
}
runAndCheck() je pomocná funkcia, ktorá spustí obslužný skript a vráti true, ak je návratový kód 0. Ak obslužný skript neexistuje, vráti true (ak skript chýba, ničomu nebráni).
Zoznam nainštalovaných obslužných skriptov
$installed = $hooks->listHooks();
// ['pre-commit', 'commit-msg', 'post-checkout']
Vypíše všetky spustiteľné súbory v .git/hooks/ (súbory .sample vynechá).
Ak obslužný skript run() chýba alebo nie je spustiteľný, vráti návratový kód 0 a prázdny výstup. Ak proces nemožno spustiť, vráti návratový kód 1 a na štandardný chybový výstup vypíše Failed to start hook.
Inštalácia obslužného skriptu
$hooks->install('pre-commit', "#!/bin/bash\nphp vendor/bin/phpcs --standard=PSR12 .\n");
Zapíše obsah skriptu do .git/hooks/<name> a nastaví mu právo na spustenie (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);
Obslužné skripty spúšťané Pitmaster
HookRunner dokáže spustiť ľubovoľný obslužný skript podľa názvu. Repository ich spúšťa automaticky:
| Obslužný skript | Spúšťa ho | Argumenty | Môže prerušiť operáciu? |
|---|---|---|---|
pre-commit |
commit() |
žiadne | Áno (nenulový návratový kód) |
prepare-commit-msg |
commit() |
súbor správy, potom message (alebo merge pri dokončovaní zlúčenia) |
Áno |
commit-msg |
commit() |
súbor správy (.git/COMMIT_EDITMSG); zmeny v súbore sa použijú |
Áno (nenulový návratový kód) |
post-commit |
commit() |
žiadne | Nie (iba informatívny) |
pre-rebase |
rebase() |
revízia vzdialeného repozitára, z ktorého sa sťahujú zmeny | Áno |
post-checkout |
checkout() |
starý HEAD, nový HEAD, 1 |
Nie (iba informatívny) |
post-merge |
merge(), mergeOctopus(), mergeContinue() |
0 |
Nie (iba informatívny) |
pre-push |
push() a jeho varianty |
názov vzdialeného repozitára, URL; riadky s referenciami zo štandardného vstupu | Áno (nenulový návratový kód) |
Ak obslužný skript zlyhá, operácia vyvolá RuntimeException('<name> hook failed'); výstup skriptu sa nezahrnie. Obslužné skripty pre odovzdanie zmien sa spúšťajú iba pri operácii commit(): odovzdania zlúčenia vytvorené pomocou merge() ich nespúšťajú. post-checkout sa nespúšťa pri operáciách addWorktree(), reset() ani restore().
Serverové obslužné skripty (pre-receive, update, post-receive, post-update), pre-auto-gc a post-rewrite sa nikdy nespúšťajú automaticky.
Prostredie obslužných skriptov
Pri spúšťaní obslužného skriptu Pitmaster mu odovzdá tieto premenné prostredia:
$env = [
'GIT_DIR' => $this->gitDir,
'GIT_WORK_TREE' => dirname($this->gitDir),
];
Obslužný skript dostane iba tieto premenné: PATH, HOME a žiadne ďalšie premenné procesu PHP sa neodovzdávajú (#13). V skriptoch používajte absolútne cesty alebo v nich nastavte PATH; shebang #!/usr/bin/env php nájde interprety iba v predvolenej systémovej ceste.
Obslužný skript sa spúšťa v dirname($gitDir), čo je pri bežnom adresári .git pracovný strom.
Formát skriptu obslužného skriptu
Obslužné skripty možno napísať v ľubovoľnom jazyku. Prvý riadok musí obsahovať shebang:
#!/bin/bash
# Bash hook
#!/usr/bin/env php
<?php
// PHP hook
#!/usr/bin/env python3
# Python hook
Príklad: pre-commit pomocou Pitmaster
commit() už spúšťa pre-commit, prepare-commit-msg, commit-msg a post-commit, takže v kóde aplikácie stačí ošetriť zlyhanie:
try {
$commitId = $repo->commit('Add feature');
} catch (\RuntimeException $e) {
echo $e->getMessage(); // "pre-commit hook failed"
}
HookRunner volajte samostatne iba pri objekte repozitára otvorenom pomocou ['hooks' => false] alebo pri obslužných skriptoch, ktoré Pitmaster nespúšťa.
Ukážkové obslužné skripty
Git inicializuje repozitáre so súbormi obslužných skriptov .sample; Pitmaster::init() vytvorí prázdny adresár hooks/. Konfigurácia Pitmaster listHooks() vynecháva súbory .sample:
.git/hooks/
pre-commit.sample (excluded from listHooks)
commit-msg.sample (excluded from listHooks)
pre-commit (included - installed by user)