Skip to content

Instantly share code, notes, and snippets.

@aadmathijssen
Last active July 8, 2021 19:15
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aadmathijssen/e539b808a5da9a7e8f74244610554111 to your computer and use it in GitHub Desktop.
Save aadmathijssen/e539b808a5da9a7e8f74244610554111 to your computer and use it in GitHub Desktop.
phpcs pre-commit hook using the gitstaged filter
#!/bin/bash
#stash all changes except for the staged ones
git stash push --keep-index --include-untracked -m "phpcs pre-commit stash"
#run phpcs on the staged files and store the exit code
vendor/bin/phpcs --filter=gitstaged
result=$?
#restore to the previous configuration
git reset --hard
git stash pop --index
#use the stored phpcs exit code as exit code.
exit ${result}
@aadmathijssen
Copy link
Author

aadmathijssen commented Jun 19, 2021

Possible solution to PHP_CodeSniffer issue 3379.

@morozov
Copy link

morozov commented Jul 8, 2021

Thanks for putting the script together, @aadmathijssen. I went ahead and implemented some improvements to make it more robust:

Here's my current version:
#!/usr/bin/env bash

# original idea: https://gist.github.com/aadmathijssen/e539b808a5da9a7e8f74244610554111
set -euo pipefail

# restore to the previous configuration
function cleanup {
    git reset --hard --quiet
    git stash pop --index --quiet
}

if [[ -f "$(git rev-parse --git-dir)/MERGE_HEAD" ]]; then
    exit
fi

PHPCS="$(git rev-parse --show-toplevel)/vendor/bin/phpcs"

# verify only PHP projects with PHP_CodeSniffer installed
if [[ ! -x "$PHPCS" ]]; then
    exit
fi

# early exit if there are no staged changes (e.g. during commit --amend)
if git diff --cached --exit-code > /dev/null ; then
    exit
fi

# stash all changes except for the staged ones
git stash push --keep-index --include-untracked -m "PHP_CodeSniffer pre-commit stash" --quiet

trap cleanup EXIT

# run PHP_CodeSniffer on the staged files
git diff --cached --name-only --diff-filter=AM | xargs "$PHPCS"

I changed the following:

  1. Added the usual set -euo pipefail for better error handling.
  2. Silenced Git operations with --quiet since they are implementation details.
  3. Moved cleanup to ensure all the temporary state is restored if something fails in between. This also allows not to store the exit code in a temporary variable.
  4. The GitStaged filter didn't work in all my environments, so I just replaced it with git --diff-filter=AM | xargs phpcs.
  5. Properly handle git commit --amend when there are no new changes.

The remaining problem is that the script messes up the workspace if it kicks in during a merge, so I had to disable it for the merge commits temporarily. Any idea how to fix that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment