Table of Contents

Git hooks for Windows

This article contains a few collected notes about working with git hooks in Windows environments.

Client-side git hooks are locally-installed scripts that run at certain points in your git workflow. For example:

Hook scripts are stored in the .git/hooks folder in the root of your repository – to use a hook script, you just need to make sure it's present in the folder in an appropriately named file name. If .git/hooks contains a file named pre-commit, git will automatically attempt to execute it as a script file when you run git commit.

A default repo installation includes sample git hook scripts, suffixed .sample – to use the sample pre-commit hook, you would just rename file pre-commit.sample to pre-commit (no extension).

Shebang

Hook scripts, like other *nix shell scripts start with a shebang. This initial line tells the system which script interpreter to use to execute the file. In a *nix system this might be e.g.:

but obviously /bin/sh and /bin/bash aren't valid Windows paths.

Instead,1) you need to include the path to the relevant script interpreter on your local Windows system, e.g.

#! C:/Program\ Files/Git/usr/bin/sh.exe

specifies the location of the sh interpreter bundled with my Git for Windows install. Notice the forward slash path separator and the backward slash escape character (used to prevent git from interpreting the path as stopping at C:/Program).

Version control

The contents of .git/hooks are excluded from version control and aren't cloned from a source repo. For this reason I prefer to:

The HookScripts folder is then version controlled like any other folder in the repo. To install a hook script in your local repo (e.g. pre-commit in the screenshot), copy it into (or soft link it in) your local .git/hooks folder. If you copy it, you'll need to modify the shebang for your local git install.

The “official” way to manage non-standard hook script location is to use the core.hooksPath git config option, but many users seem to report difficulties with this approach, particularly in Windows systems.

PowerShell

In a Windows system, writing hook scripts in PowerShell is convenient. In the screenshot above, the two .ps1 PowerShell scripts files provide actions available for use in a hook script – the pre-commit hook in the same folder then need only contain calls to the necessary scripts, e.g.:

powershell.exe -NoProfile -ExecutionPolicy Bypass -File ".\shared\HookScripts\Sort-SemanticModels.ps1"

The path to the script file is relative to the root of the repository2).

pre-commit changes

A common use case for pre-commit hooks is to make additional standard changes to files before committing them, e.g. applying format conventions, linting code etc.

Bear in mind that changes are made in a git repo by being first staged (git add), and then committed (git commit). A pre-commit hook runs on git commit, so any additional changes made to files by the hook script must also be staged if they are to be included in the commit.

In PowerShell, I:

Function Invoke-Utility {
    $exe, $argsForExe = $Args
    $ErrorActionPreference = 'Continue' # to prevent 2> redirections from triggering a terminating error.
    try { & $exe $argsForExe } catch { Throw } # catch triggered ONLY if $exe not found, not for errors reported by $exe itself
    if ($LASTEXITCODE) { Throw "$exe indicated failure (exit code $LASTEXITCODE; full command: $Args)." }
} 
 
# modify some file $filePath
# ...
 
# re-stage file after modifying
Invoke-Utility git add $filePath