From 343fdfcb92a9dbb701fc4fd368419f31d5e8fd1b Mon Sep 17 00:00:00 2001 From: Tai Groot Date: Mon, 23 Feb 2026 10:31:12 +0000 Subject: [PATCH] docs: rewrite README, fix pre-commit shellcheck issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Complete README rewrite with proper installation instructions - Added quick install section, configuration section, prerequisites - Fixed typos (occasionaly, Compatability, alondside) - pre-commit: use stat instead of parsing ls output (SC2012) - pre-commit: fix popd called with arguments (SC2164) - pre-commit: proper IFS newline assignment - pre-commit: skip non-existent files cleanly - Fixed repo description typo (usefull → useful) --- README.md | 87 ++++++++++++++++++++++++++++++++++++++++-------------- pre-commit | 30 +++++++++++-------- 2 files changed, 82 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 64305ac..f9622fa 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # hooks -This is a collection of simple git hooks I use on my own system. +A collection of simple, fast git hooks for everyday use. + Many people don't like git hooks these days, usually because they're slow. If your git hooks are slow, your commits slow down and start to cause development friction, which is to be avoided. @@ -10,46 +11,88 @@ For example, using git-lfs hooks can cause some slowdowns on repos which aren't lfs-enabled, but adding lfs support to repos which already have hooks installed is an annoying extra step, so `git lfs track` is used to short-circuit this logic. -These hooks presume a couple of pre-installed binaries: +## Prerequisites -- git (duh) -- git-lfs +- [git](https://git-scm.com/) +- [git-lfs](https://git-lfs.github.com/) - [gitleaks](https://github.com/gitleaks/gitleaks) -- [mg](https://github.com/taigrr/mg) +- [mg](https://github.com/taigrr/mg) (optional, for repo registration on push) ## What these hooks do Rather than try to lint code from a git hook, or run tests, etc., these hooks assume you're already a good developer. You know how to follow style guides, -you're ok with an occasionaly failing CI job. That's what CI is for, after all. +you're ok with an occasionally failing CI job. That's what CI is for, after all. These hooks don't try to hold your hand, they just prevent accidentally making a couple of annoying blunders: -1. Automatically configure LFS hooks for new repos -1. Warn the user when a file over a certain filesize limit is added to the repo -1. Scan the staged files for added secrets (using the fantastic gitleaks tool) -1. On a push, register the repo with Magnesium, (mg) my git repos management cli. +| Hook | What it does | +|------|-------------| +| `pre-commit` | Blocks commits containing files over 5 MB (unless tracked by LFS) | +| `pre-commit` | Scans staged files for leaked secrets via gitleaks | +| `post-checkout` | Runs `git lfs post-checkout` | +| `post-commit` | Runs `git lfs post-commit` | +| `post-merge` | Runs `git lfs post-merge` | +| `pre-push` | Registers the repo with mg, then runs `git lfs pre-push` if LFS is active | ## Installation + +### Quick Install + +```bash +git clone https://github.com/taigrr/hooks.git ~/.git-hooks +git config --global core.hooksPath ~/.git-hooks +``` + ### Template Installation -1. Clone this repo somewhere on your system. -1. Configure git to use these hooks as your template hook directory by adding this line to your global git config: `git config --global init.templatedir` -### Central Management Installation -Alternatively, you can use the hook directory as-is, instead of copying the hooks into every repo. -Run this command: -1. `git config --global core.hooksPath /path/to/my/centralized/hooks` +Use this if you want new repos to get a *copy* of the hooks at clone/init time: -This has the benefit of updating the hooks for all repos when you make a change, instead of only new repos going forward, but will require you to specify manual overrides for individual repos with customized hooks. +```bash +git clone https://github.com/taigrr/hooks.git ~/.git-hooks +git config --global init.templatedir ~/.git-hooks +``` -## Compatability Notice -These hooks are not tested alondside any other hooks, or 'hook managers' such as pre-commit or Husky. +> **Note:** Existing repos won't be affected — only newly cloned or initialized repos +> will receive the hooks. -They will almost certainly cause issues if used alongside git-annex. -You have been warned. +### Central Management Installation + +Use this if you want *all* repos (existing and new) to use the same hooks directory: + +```bash +git clone https://github.com/taigrr/hooks.git ~/.git-hooks +git config --global core.hooksPath ~/.git-hooks +``` + +This has the benefit of updating the hooks for all repos when you make a change, +instead of only new repos going forward, but will require you to specify manual +overrides for individual repos with customized hooks: + +```bash +# Override for a specific repo +cd /path/to/repo +git config core.hooksPath /path/to/other/hooks +``` + +## Configuration + +The file size limit in `pre-commit` defaults to **5 MB**. To change it, edit the +`size_limit` variable at the top of the `pre-commit` file: + +```bash +size_limit=$((10 * 2**20)) # 10 MB +``` + +## Compatibility Notice + +These hooks are not tested alongside any other hooks, or "hook managers" such as +pre-commit or Husky. They will almost certainly cause issues if used alongside +git-annex. You have been warned. ## Contributing + Keeping in mind that the hooks are supposed to be extremely generic and fast, I -don't know what else there might be to add, but if there's something you think +don't know what else there might be to add, but if there's something you think I'm missing feel free to open a PR and I'll consider it. diff --git a/pre-commit b/pre-commit index d63cd0a..d19a326 100755 --- a/pre-commit +++ b/pre-commit @@ -3,36 +3,40 @@ set +eou pipefail size_limit=$((5 * 2**20)) repo_root=$(git rev-parse --show-toplevel) -pushd "$repo_root" 2>/dev/null > /dev/null || true +pushd "$repo_root" > /dev/null 2>&1 || true + empty=$(git hash-object -t tree /dev/null) -if git rev-parse --verify HEAD > /dev/null 2>&1 -then +if git rev-parse --verify HEAD > /dev/null 2>&1; then against=HEAD else against="$empty" fi -IFS=' -' -tracked=$(git lfs ls-files --name-only) + +IFS=$'\n' +tracked=$(git lfs ls-files --name-only 2>/dev/null) hasLargeFile=false + for file in $(git diff-index --cached --name-only "$against"); do for tracked_file in $tracked; do if [ "$file" == "$tracked_file" ]; then continue 2 fi done - # shellcheck disable=SC2012 - file_size=$( ([ ! -f "$file" ] && echo 0) || ls -la "$file" | awk '{ print $5 }' ) - if [ "$file_size" -gt "$size_limit" ]; then - echo File "$file" is "$(( file_size / 10**6 ))"MB, which is larger than our configured limit of "$(( size_limit / 10**6 ))"MB + if [ ! -f "$file" ]; then + continue + fi + file_size=$(stat --format='%s' "$file" 2>/dev/null || stat -f '%z' "$file" 2>/dev/null || echo 0) + if [ "$file_size" -gt "$size_limit" ]; then + echo "File $file is $((file_size / 10**6))MB, which is larger than our configured limit of $((size_limit / 10**6))MB" hasLargeFile=true fi done if $hasLargeFile; then - echo Commit too large, did you add a binary file? For image assets, consider git-lfs. - popd "$repo_root" 2>/dev/null > /dev/null || true + echo "Commit too large, did you add a binary file? For image assets, consider git-lfs." + popd > /dev/null 2>&1 || true exit 1 fi -popd "$repo_root" 2>/dev/null > /dev/null || true + +popd > /dev/null 2>&1 || true gitleaks protect --staged --verbose --no-banner --no-color 2>/dev/null