Hookok
A Git hookok a .git/hooks/ könyvtárban lévő futtatható parancsfájlok, amelyek a git-műveletek meghatározott pontjain futnak le. A Pitmaster felismeri és meghívja a hookokat a PHP folyamatvezérlésével (proc_open).
A hookok alapértelmezés szerint lefutnak
A repository-műveletek automatikusan futtatják a Hooks Pitmaster által] felsorolt hookokat. Egy repository-kezelőnél a kikapcsolásukhoz átadáskor adja meg az opciókat:
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
A Pitmaster::init() és a Pitmaster::clone() ugyanazokat az opciókat fogadja. Hook futtatásához proc_open() szükséges; az ezt letiltó gazdagépeken a repository-kat ['hooks' => false] beállítással nyissa meg. A CLI mindig engedélyezett hookokkal nyitja meg a repository-t.
A Pitmaster kizárólag a <gitDir>/hooks helyen keresi a hookokat. A core.hooksPath helyet figyelmen kívül hagyja, kapcsolt munkafában pedig a .git/worktrees/<name>/hooks helyen keres, ezért a megosztott .git/hooks parancsfájlok ott nem futnak le (#12).
Az alább ismertetett HookRunner figyelmen kívül hagyja ezeket az opciókat: közvetlen meghívásakor mindig lefuttatja a hookot.
HookRunner
use Pitmaster\Hooks\HookRunner;
$hooks = new HookRunner($repo->gitDir());
Hook meglétének ellenőrzése
if ($hooks->exists('pre-commit')) {
echo "pre-commit hook is installed\n";
}
Akkor létezik hook, ha a fájl megtalálható a .git/hooks/<name> helyen, és futtatható.
Hook futtatása
$result = $hooks->run('pre-commit');
echo $result['exitCode']; // 0 = success
echo $result['stdout']; // Hook's standard output
echo $result['stderr']; // Hook's standard error
Argumentumokkal
$result = $hooks->run('commit-msg', ['/path/to/COMMIT_EDITMSG']);
stdin bemenettel
$result = $hooks->run('pre-push', ['origin', 'https://github.com/user/repo.git'], $stdinData);
A pre-push hook stdin-en kapja meg a refadatokat.
Siker ellenőrzése
if ($hooks->runAndCheck('pre-commit')) {
// Hook passed (exit code 0), proceed with commit
} else {
// Hook rejected the operation
}
A runAndCheck() kényelmi függvény lefuttatja a hookot, és true értéket ad vissza, ha a kilépési kód 0. Ha a hook nem létezik, true értéket ad vissza (hook hiányában nincs kifogás).
Telepített hookok listázása
$installed = $hooks->listHooks();
// ['pre-commit', 'commit-msg', 'post-checkout']
Felsorolja a .git/hooks/ összes futtatható fájlját (a .sample fájlok kivételével).
Ha a run() hiányzó vagy nem futtatható hookot kap, 0 kilépési kóddal és üres kimenettel tér vissza. Ha a folyamat nem indítható el, 1-es kilépési kódot ad, a Failed to start hook pedig stderr-re kerül.
Hook telepítése
$hooks->install('pre-commit', "#!/bin/bash\nphp vendor/bin/phpcs --standard=PSR12 .\n");
A parancsfájl tartalmát a .git/hooks/<name> helyre írja, és futtatási jogosultságot állít be (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);
A Pitmaster által futtatott hookok
A HookRunner név alapján bármely hookot futtathat. A Repository automatikusan ezeket futtatja:
| Hook | Futtatja | Argumentumok | Megszakíthatja? |
|---|---|---|---|
pre-commit |
commit() |
nincs | Igen (nem nulla kilépés) |
prepare-commit-msg |
commit() |
üzenetfájl, majd message (vagy merge egy merge befejezésekor) |
Igen |
commit-msg |
commit() |
üzenetfájl (.git/COMMIT_EDITMSG); a fájl módosításai érvényesülnek |
Igen (nem nulla kilépés) |
post-commit |
commit() |
nincs | Nem (tájékoztató jellegű) |
pre-rebase |
rebase() |
upstream revízió | Igen |
post-checkout |
checkout() |
régi HEAD, új HEAD, 1 |
Nem (tájékoztató jellegű) |
post-merge |
merge(), mergeOctopus(), mergeContinue() |
0 |
Nem (tájékoztató jellegű) |
pre-push |
push() és változatai |
távoli név, URL; ref-sorok stdin-en | Igen (nem nulla kilépés) |
A sikertelen hook miatt a művelet RuntimeException('<name> hook failed') hibával megszakad; a hook kimenete nem szerepel benne. A commit-hookok csak a commit() műveletből futnak le: a merge() által létrehozott merge commitok nem futtatják őket. A post-checkout nem fut a addWorktree(), reset() vagy restore() esetén.
A szerveroldali hookok (pre-receive, update, post-receive, post-update), valamint a pre-auto-gc és a post-rewrite soha nem futnak le automatikusan.
Hook-környezet
Amikor a Pitmaster hookot futtat, ezt a környezetet adja át:
$env = [
'GIT_DIR' => $this->gitDir,
'GIT_WORK_TREE' => dirname($this->gitDir),
];
A hook csak ezeket a változókat kapja meg: a PATH, a HOME és a PHP folyamat összes többi változója kimarad (#13). A hook-parancsfájlokban használjon abszolút útvonalakat, vagy állítsa be a PATH értékét magában a parancsfájlban; a #!/usr/bin/env php shebang csak a rendszer alapértelmezett elérési útján találja meg az értelmezőket.
A hook a dirname($gitDir) könyvtárban fut, ami normál .git könyvtár esetén a munkakönyvtár.
Hook-parancsfájl formátuma
A hookok bármilyen nyelven megírhatók. Az első sornak shebanget kell tartalmaznia:
#!/bin/bash
# Bash hook
#!/usr/bin/env php
<?php
// PHP hook
#!/usr/bin/env python3
# Python hook
Példa: pre-commit Pitmaster-szel
A commit() már futtatja a pre-commit, prepare-commit-msg, commit-msg és post-commit elemeket, ezért az alkalmazáskódnak csak a hibát kell kezelnie:
try {
$commitId = $repo->commit('Add feature');
} catch (\RuntimeException $e) {
echo $e->getMessage(); // "pre-commit hook failed"
}
Csak ['hooks' => false] beállítással megnyitott kezelőnél hívja meg saját maga a HookRunner-t, vagy olyan hookoknál, amelyeket a Pitmaster nem futtat.
Hookminták
A Git repository-kat inicializál a .sample hookfájlokkal; a Pitmaster::init() üres hooks/ könyvtárat hoz létre. A Pitmaster listHooks() fájljai kizárják a .sample fájlokat:
.git/hooks/
pre-commit.sample (excluded from listHooks)
commit-msg.sample (excluded from listHooks)
pre-commit (included - installed by user)