1

I've been given a git pre-push hook to include in some checking inside a VS Code extension.

The request made to me was to run this hook against some code, but not actually push anything, just return the result.

The file I've been given has no file type from what I can tell, so my question is --- In theory couldn't I just copy this as a separate file and make it a .sh script, and then call it with whatever arguments it accepts (in this case two)?

trebleCode
  • 2,134
  • 19
  • 34
  • There's no need to copy it either: just run it. Note, however, that you may want to run it with the same environment that Git would, or perhaps with a deliberately-different environment that you can test in the hook. The Git hook environment is described (lightly) in the githooks docuementation: pay attention to the current working directory and to the $GIT_DIR environment variable setting in particular. – torek May 02 '19 at 19:29
  • @torek So in my case my extension is a mix of TypeScript and JavaScript. Could I just call it as-is with `execSync`? Ex. `execSync('path/to/pre-push argument1 argument2')`? – trebleCode May 02 '19 at 19:35
  • I have no idea what `execSync` is, but Git would run it by asking the OS to run it, so you can run your hook the same way: ask the OS to run it. If that's what `execSync` does, that's fine. – torek May 02 '19 at 20:01
  • Cheers @torek, much appreciated – trebleCode May 02 '19 at 20:12

1 Answers1

2

Call Githooks as standalone scripts

This will be officially supported with Git 2.36 (Q2 2022):

git hook run [--ignore-missing] <hook-name> [-- <hook-args>]

See commit 95ba86a, commit 306f445, commit dbb1c61, commit f443246, commit 0c8ac06, commit a755530, commit 1a3017d, commit 72ddf34, commit 67ad630, commit 432a50b, commit 25d4e02, commit 593ffdd, commit bad62a8, commit 96e7225 (22 Dec 2021) by Emily Shaffer (nasamuffin).
See commit 0d3979c, commit ab81cf2, commit 474c119 (22 Dec 2021) by Ævar Arnfjörð Bjarmason (avar).
(Merged by Junio C Hamano -- gitster -- in commit c70bc33, 09 Feb 2022)

hook: add 'run' subcommand

Signed-off-by: Emily Shaffer
Signed-off-by: Ævar Arnfjörð Bjarmason
Acked-by: Emily Shaffer

In order to enable hooks to be run as an external process, by a standalone Git command, or by tools which wrap Git, provide an external means to run all configured hook commands for a given hook event.

Most of our hooks require more complex functionality than this, but let's start with the bare minimum required to support our simplest hooks.

In terms of implementation the usage_with_options() and "goto usage" pattern here mirrors that of builtin/{commit-graph,multi-pack-index}.c.

Some of the implementation here, such as a function being named run_hooks_opt() when it's tasked with running one hook, to using the run_processes_parallel_tr2() API to run with jobs=1 is somewhere between a bit odd and and an overkill for the current features of this "hook run" command and the hook.[ch] API.

This code will eventually be able to run multiple hooks declared in config in parallel, by starting out with these names and APIs we reduce the later churn of renaming functions, switching from the run_command() to run_processes_parallel_tr2() API etc.

git hook now includes in its man page:

git-hook(1)

NAME

git-hook - Run git hooks

SYNOPSIS

[verse]

 'git hook' run <hook-name> [-- <hook-args>]

DESCRIPTION

A command interface to running git hooks (see linkgit:githooks[5]), for use by other scripted git commands.

SUBCOMMANDS

run

Run the <hook-name> hook.

Any positional arguments to the hook should be passed after a mandatory -- (or --end-of-options).

And:

git hook run: add an --ignore-missing flag

Signed-off-by: Ævar Arnfjörð Bjarmason
Reviewed-by: Emily Shaffer

For certain one-shot hooks we'd like to optimistically run them, and not complain if they don't exist.

This was already supported by the underlying hook.c library, but had not been exposed via "git hook"(man) run".
The command version of this will be used by send-email in a subsequent commit.

git hook now includes in its man page:

'git hook' run [--ignore-missing] <hook-name> [-- <hook-args>]

git hook now includes in its man page:

OPTIONS

--ignore-missing

Ignore any missing hook by quietly returning zero.

Used for tools that want to do a blind one-shot run of a hook that may or may not be present.


Warning: in Git 2.36 we revamped the way how hooks are invoked.
One change that is end-user visible is that the output of a hook is no longer directly connected to the standard output of "git" that spawns the hook, which was noticed post release.
This is getting corrected with Git 2.37 (Q3 2022).

See commit a082345, commit fd3aaf5 (07 Jun 2022) by Ævar Arnfjörð Bjarmason (avar).
(Merged by Junio C Hamano -- gitster -- in commit 1a7f6be, 13 Jun 2022)

hook API: fix v2.36.0 regression: hooks should be connected to a TTY

Reported-by: Anthony Sottile
Signed-off-by: Ævar Arnfjörð Bjarmason

Fix a regression reported against f443246 (commit: convert {pre-commit, 2021-12-22, Git v2.36.0-rc0 -- merge listed in batch #2) (commit: convert {pre-commit,prepare-commit-msg} hook to hook.h, 2021-12-22): Due to using the run_process_parallel() API in the earlier 96e7225 ("hook: add 'run' subcommand", 2021-12-22, Git v2.36.0-rc0 -- merge listed in batch #2) we'd capture the hook's stderr and stdout, and thus lose the connection to the TTY in the case of e.g. the "pre-commit" hook.

As a preceding commit notes GNU parallel's similar --ungroup option also has it emit output faster.
While we're unlikely to have hooks that emit truly massive amounts of output (or where the performance thereof matters) it's still informative to measure the overhead.
In a similar "seq" test we're now ~30% faster:

$ cat .git/hooks/seq-hook; git hyperfine -L rev origin/master,HEAD~0 -s 'make CFLAGS=-O3' './git hook run seq-hook'
#!/bin/sh

seq 100000000
Benchmark 1: ./git hook run seq-hook' in 'origin/master
  Time (mean ± σ):     787.1 ms ±  13.6 ms    [User: 701.6 ms, System: 534.4 ms]
  Range (min … max):   773.2 ms … 806.3 ms    10 runs

Benchmark 2: ./git hook run seq-hook' in 'HEAD~0
  Time (mean ± σ):     603.4 ms ±   1.6 ms    [User: 573.1 ms, System: 30.3 ms]
  Range (min … max):   601.0 ms … 606.2 ms    10 runs

Summary
  './git hook run seq-hook' in 'HEAD~0' ran
    1.30 ± 0.02 times faster than './git hook run seq-hook' in 'origin/master'

Git 2.37.3 (Q3 2022) adds a follow-up fix to a fix for a regression in 2.36.

See commit 99ddc24 (05 Aug 2022) by Ævar Arnfjörð Bjarmason (avar).
(Merged by Junio C Hamano -- gitster -- in commit d86ac14, 14 Aug 2022)

hook API: don't segfault on strbuf_addf() to NULL "out"

Reported-by: Ilya K
Signed-off-by: Ævar Arnfjörð Bjarmason
Reviewed-by: Emily Shaffer
Reviewed-by: Đoàn Trần Công Danh

Fix a logic error in a082345 ("hook API: fix v2.36.0 regression: hooks should be connected to a TTY", 2022-06-07, Git v2.37.0-rc0 -- merge).
When it started using the "ungroup" API added in fd3aaf5 (run-command: add an , 2022-06-07, Git v2.37.0-rc0 -- merge) (run-command: add an "ungroup" option to run_process_parallel(), 2022-06-07) it should have made the same sort of change that fd3aaf5 itself made in "t/helper/test-run-command.c".

The correct way to emit this "Couldn't start" output with "ungroup" would be:

fprintf(stderr, _("Couldn't start hook '%s'\n"), hook_path);

But we should instead remove the emitting of this output.

The "cannot run" output here is emitted by run-command.c's child_err_spew().

So the addition of the "Couldn't start hook" output here in 96e7225 ("hook: add 'run' subcommand", 2021-12-22, Git v2.36.0-rc0 -- merge listed in batch #2) was always redundant.

For the pre-commit hook we'll now emit exactly the same output as we did before f443246 (commit: convert {pre-commit, 2021-12-22, Git v2.36.0-rc0 -- merge listed in batch #2) (commit: convert {pre-commit,prepare-commit-msg} hook to hook.h, 2021-12-22) (and likewise for others).

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • See also "**[Read from STDIN on a Git pre-commit Hook](https://stackoverflow.com/a/75645261/6309)**", from Git 2.40 (Q1 2023). – VonC Mar 18 '23 at 17:50