Ugrás a tartalomhoz

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:

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

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

PHP
use Pitmaster\Hooks\HookRunner;

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

Hook meglétének ellenőrzése

PHP
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

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

Argumentumokkal

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

stdin bemenettel

PHP
$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

PHP
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

PHP
$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

PHP
$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).

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);

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:

PHP
$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:

Shell
#!/bin/bash
# Bash hook
PHP
#!/usr/bin/env php
<?php
// PHP hook
Python
#!/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:

PHP
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:

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