├── .gitignore ├── bash-icon.png ├── git-logo.png ├── perl-icon.png ├── python-icon.png ├── create-new-file.gif ├── .travis.yml ├── prettier.config.js ├── pre-commit-hooks ├── dotenvx.hook ├── format-code.hook ├── verify-name-and-email.hook ├── search-term.hook └── spell-check-md-files.hook ├── post-update-hooks └── update-server-info.hook ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ ├── bug_report.md │ └── new-git-hook-script-request.md ├── post-checkout-hooks ├── delete-pyc-files.hook └── new-branch-alert.hook ├── package.json ├── prepare-commit-msg-hooks ├── include-git-diff-name-status.hook └── insert-issue-number.hook ├── commit-msg-hooks └── enforce-insert-issue-number.hook ├── pre-push-hooks └── prevent-bad-push.hook ├── tests ├── verify-name-and-email-test.bats └── spell-check-md-files-test.bats ├── CONTRIBUTING.md ├── CODE-OF-CONDUCT.md ├── query-watchman-hooks └── fsmonitor-watchman.hook ├── update-hooks └── prevent-unannotated-tags.hook ├── pre-rebase-hooks └── prevent-rebase.hook ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | tests.log -------------------------------------------------------------------------------- /bash-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CompSciLauren/awesome-git-hooks/HEAD/bash-icon.png -------------------------------------------------------------------------------- /git-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CompSciLauren/awesome-git-hooks/HEAD/git-logo.png -------------------------------------------------------------------------------- /perl-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CompSciLauren/awesome-git-hooks/HEAD/perl-icon.png -------------------------------------------------------------------------------- /python-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CompSciLauren/awesome-git-hooks/HEAD/python-icon.png -------------------------------------------------------------------------------- /create-new-file.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CompSciLauren/awesome-git-hooks/HEAD/create-new-file.gif -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 'node' 4 | git: 5 | depth: false 6 | addons: 7 | apt: 8 | packages: 9 | - aspell 10 | - aspell-en -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 120, 3 | tabWidth: 2, 4 | useTabs: false, 5 | semi: true, 6 | singleQuote: true, 7 | trailingComma: 'all', 8 | bracketSpacing: true, 9 | jsxBracketSameLine: false, 10 | arrowParens: 'always', 11 | }; -------------------------------------------------------------------------------- /pre-commit-hooks/dotenvx.hook: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Prevents you from accidentally committing your `.env` file(s) to code 4 | # 5 | # Requirements: 6 | # * Bash 7 | # * dotenvx 8 | # 9 | # To enable this hook, install dotnevx [https://dotenvx.com/docs/install] and rename this file to "pre-commit". 10 | 11 | dotenvx precommit 12 | -------------------------------------------------------------------------------- /pre-commit-hooks/format-code.hook: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Formats code using mvn fmt:format command. 4 | # Any staged files that are modified by this command will be re-added to the commit. 5 | # 6 | # Requirements: 7 | # * Bash 8 | # 9 | # To enable this hook, rename this file to "pre-commit". 10 | 11 | mvn fmt:format 12 | git diff --name-only --cached --diff-filter=d | xargs -l git add 13 | -------------------------------------------------------------------------------- /post-update-hooks/update-server-info.hook: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Based on the post-update sample generated by default in .git/hooks 3 | # Source: https://www.git-scm.com/docs/githooks/1.7.1 4 | # 5 | # Prepares a packed repository for use over dumb transports (e.g. http). 6 | # 7 | # Requirements: 8 | # * Bash 9 | # 10 | # To enable this hook, rename this file to "post-update". 11 | 12 | exec git update-server-info 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Description of Bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Steps to Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | -------------------------------------------------------------------------------- /post-checkout-hooks/delete-pyc-files.hook: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Based on a hook from dzone.com 3 | # Source: https://dzone.com/articles/an-in-depth-look-at-git-hooks 4 | # 5 | # Deletes all .pyc files every time a new branch is checked out. 6 | # 7 | # Requirements: 8 | # * Python 2/3 9 | # 10 | # To enable this hook, rename this file to "post-checkout". 11 | 12 | import sys, os, re 13 | from subprocess import check_output 14 | 15 | # Collect the parameters 16 | previous_head = sys.argv[1] 17 | new_head = sys.argv[2] 18 | is_branch_checkout = sys.argv[3] 19 | if is_branch_checkout == "0": 20 | print "post-checkout: This is a file checkout. Nothing to do." 21 | sys.exit(0) 22 | print "post-checkout: Deleting all '.pyc' files in working directory" 23 | for root, dirs, files in os.walk('.'): 24 | for filename in files: 25 | ext = os.path.splitext(filename)[1] 26 | if ext == '.pyc': 27 | os.unlink(os.path.join(root, filename)) -------------------------------------------------------------------------------- /pre-commit-hooks/verify-name-and-email.hook: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Based on a hook from tygertec.com 3 | # Source: https://www.tygertec.com/git-hooks-practical-uses-windows/ 4 | # 5 | # Verifies user.name and user.email are set to correct name and email address. 6 | # 7 | # The hook should exit with non-zero status after issuing an appropriate 8 | # message if it stops the commit. 9 | # 10 | # Requirements: 11 | # * Bash 12 | # 13 | # To enable this hook, rename this file to "pre-commit". 14 | 15 | # Make sure user.name is set properly 16 | username=$(git config user.name) 17 | if [ "$username" != "Lauren Stephenson" ] 18 | then 19 | cat <<\EOF 20 | Error: user.name not set to "Lauren Stephenson" 21 | EOF 22 | exit 1 23 | fi 24 | 25 | # Make sure user.email is set properly 26 | email=$(git config user.email) 27 | if [ "$email" != "compscilauren@gmail.com" ] 28 | then 29 | cat <<\EOF 30 | Error: user.email not set to "compscilauren@gmail.com" 31 | EOF 32 | exit 1 33 | fi 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "awesome-git-hooks", 3 | "version": "1.0.0", 4 | "description": "

\r \r \"Awesome
Awesome Git Hooks\r

", 5 | "main": "index.js", 6 | "dependencies": { 7 | "awesome-lint": "^0.11.0" 8 | }, 9 | "devDependencies": { 10 | "bats": "^1.1.0", 11 | "bats-mock": "^1.0.1" 12 | }, 13 | "scripts": { 14 | "lint": "awesome-lint https://github.com/CompSciLauren/awesome-git-hooks", 15 | "test": "npm run lint && bats tests/" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/CompSciLauren/awesome-git-hooks.git" 20 | }, 21 | "author": "", 22 | "license": "ISC", 23 | "bugs": { 24 | "url": "https://github.com/CompSciLauren/awesome-git-hooks/issues" 25 | }, 26 | "homepage": "https://github.com/CompSciLauren/awesome-git-hooks#readme" 27 | } 28 | -------------------------------------------------------------------------------- /pre-commit-hooks/search-term.hook: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Based on a hook from hackernoon.com 3 | # Source: https://hackernoon.com/automate-your-workflow-with-git-hooks-fef5d9b2a58c 4 | # 5 | # Verifies changes to be committed do not contain 6 | # any 'FIXME:' comments. 7 | # 8 | # The hook should exit with non-zero status after issuing an appropriate 9 | # message if it stops the commit. 10 | # 11 | # Requirements: 12 | # * Bash 13 | # 14 | # To enable this hook, rename this file to "pre-commit". 15 | 16 | # Redirect output to stderr 17 | exec 1>&2 18 | 19 | # Define colors 20 | RED='\033[0;31m' 21 | NC='\033[0m' 22 | 23 | # Define term to search for 24 | SEARCH_TERM="FIXME:" 25 | 26 | # Check for the presence of the SEARCH_TERM in updated files 27 | if [[ $(git diff --cached | grep -E "^\+" | grep -v '+++ b/' | cut -c 2-) == *$SEARCH_TERM* ]] 28 | then 29 | printf "${RED}Error:${NC} Found ${SEARCH_TERM} in attempted commit.\n" 30 | printf "Please remove all occurances of ${SEARCH_TERM} before committing.\n" 31 | exit 1 32 | fi 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/new-git-hook-script-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: New Git hook script request 3 | about: Ask for a new Git hook script to be created 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your script request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe what you want the script to do.** 14 | A clear description of what you want the script to do. Feel free to include pseudocode, a diagram, etc. 15 | 16 | **Is there a specific language you would prefer the script to be written in?** 17 | If no preference, please say so. Otherwise, list your preferred language and explain why you need it to be in that language. 18 | 19 | **Do you have a project that would potentially use this script?** 20 | Link to example project that might use this script. This could provide more insight for whoever writes the script. 21 | 22 | **Anything else that would be helpful to know?** 23 | If you want to add any additional details, please include them here. 24 | -------------------------------------------------------------------------------- /prepare-commit-msg-hooks/include-git-diff-name-status.hook: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Based on the pre-push sample generated by default in .git/hooks 3 | # Source: https://www.git-scm.com/docs/githooks/1.7.1 4 | # 5 | # Prepares the commit log message. 6 | # Called by "git commit" with the name of the file that has the 7 | # commit message, followed by the description of the commit 8 | # message's source. The hook's purpose is to edit the commit 9 | # message file. 10 | # 11 | # Includes the output of "git diff --name-status -r" 12 | # into the message, just before the "git status" output. It is 13 | # commented because it doesn't cope with --amend or with squashed 14 | # commits. 15 | # 16 | # Requirements: 17 | # * Bash 18 | # 19 | # To enable this hook, rename this file to "prepare-commit-msg". 20 | 21 | COMMIT_MSG_FILE=$1 22 | COMMIT_SOURCE=$2 23 | SHA1=$3 24 | 25 | # case "$COMMIT_SOURCE,$SHA1" in 26 | # ,|template,) 27 | # /usr/bin/perl -i.bak -pe ' 28 | # print "\n" . `git diff --cached --name-status -r` 29 | # if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; 30 | # *) ;; 31 | # esac -------------------------------------------------------------------------------- /prepare-commit-msg-hooks/insert-issue-number.hook: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Based on a hook from dzone.com 3 | # Source: https://dzone.com/articles/an-in-depth-look-at-git-hooks 4 | # 5 | # Inserts issue number to beginning of the commit message. 6 | # 7 | # Requirements: 8 | # * Python 9 | # 10 | # To enable this hook, rename this file to "prepare-commit-msg". 11 | 12 | import sys, os, re 13 | from subprocess import check_output 14 | # Collect the parameters 15 | commit_msg_filepath = sys.argv[1] 16 | if len(sys.argv) > 2: 17 | commit_type = sys.argv[2] 18 | else: 19 | commit_type = '' 20 | if len(sys.argv) > 3: 21 | commit_hash = sys.argv[3] 22 | else: 23 | commit_hash = '' 24 | print "prepare-commit-msg: File: %s\nType: %s\nHash: %s" % (commit_msg_filepath, commit_type, commit_hash) 25 | # Figure out which branch we're on 26 | branch = check_output(['git', 'symbolic-ref', '--short', 'HEAD']).strip() 27 | print "prepare-commit-msg: On branch '%s'" % branch 28 | # Populate the commit message with the issue #, if there is one 29 | if branch.startswith('issue-'): 30 | print "prepare-commit-msg: Oh hey, it's an issue branch." 31 | result = re.match('issue-(.*)', branch) 32 | issue_number = result.group(1) 33 | with open(commit_msg_filepath, 'r+') as f: 34 | content = f.read() 35 | f.seek(0, 0) 36 | f.write("ISSUE-%s %s" % (issue_number, content)) -------------------------------------------------------------------------------- /commit-msg-hooks/enforce-insert-issue-number.hook: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Based on a hook from dzone.com 3 | # Source: https://dzone.com/articles/an-in-depth-look-at-git-hooks 4 | # 5 | # Makes sure user did not delete the ISSUE-[#] string that was generated by prepare-commit-msg/insert-issue-number.sample 6 | # 7 | # The hook should exit with non-zero status after issuing an appropriate 8 | # message if it stops the commit. 9 | # 10 | # Requirements: 11 | # * Python 2/3 12 | # 13 | # To enable this hook, rename this file to "commit-msg". 14 | 15 | import sys, os, re 16 | from subprocess import check_output 17 | 18 | # Collect the parameters 19 | commit_msg_filepath = sys.argv[1] 20 | 21 | # Figure out which branch we're on 22 | branch = check_output(['git', 'symbolic-ref', '--short', 'HEAD']).strip() 23 | print "commit-msg: On branch '%s'" % branch 24 | 25 | # Check the commit message if we're on an issue branch 26 | if branch.startswith('issue-'): 27 | print "commit-msg: Oh hey, it's an issue branch." 28 | result = re.match('issue-(.*)', branch) 29 | issue_number = result.group(1) 30 | required_message = "ISSUE-%s" % issue_number 31 | with open(commit_msg_filepath, 'r') as f: 32 | content = f.read() 33 | if not content.startswith(required_message): 34 | print "commit-msg: ERROR! The commit message must start with '%s'" % required_message 35 | sys.exit(1) 36 | -------------------------------------------------------------------------------- /post-checkout-hooks/new-branch-alert.hook: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Based on a hook from gist.github.com 3 | # Source: https://gist.github.com/zgohr/4557894 4 | # 5 | # Creates a commit and displays a custom message when a new branch is checked out for the first time. 6 | # A commit is made in order to help determine if a new branch has been created. 7 | # 8 | # Requirements: 9 | # * Bash 10 | # 11 | # To enable this hook, rename this file to "post-checkout". 12 | 13 | from_hash=$1 14 | to_hash=$2 15 | checkout_type=$3 16 | branch_name=$(git rev-parse --abbrev-ref HEAD) 17 | from_branch_name=$(git name-rev --name-only $from_hash) 18 | 19 | light_red='\033[1;31m' 20 | no_color='\033[0m' 21 | 22 | containsElement () { 23 | local e 24 | for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done 25 | return 1 26 | } 27 | 28 | if [ $checkout_type -ne 1 ] 29 | then 30 | exit 0 ; # Not a branch checkout 31 | fi 32 | 33 | if [ $from_hash != $to_hash ] 34 | then 35 | exit 0 ; # Not checking out a new branch 36 | fi 37 | 38 | if [ $branch_name == $from_branch_name ] 39 | then 40 | exit 0 ; # Not checking out a new branch 41 | fi 42 | 43 | # Create a commit and display a message 44 | git commit --allow-empty -m "Created branch $branch_name" --no-verify 45 | echo -e "\n${light_red}Remember to change parent pom version to match branch name in every module!${no_color}\n" 46 | -------------------------------------------------------------------------------- /pre-commit-hooks/spell-check-md-files.hook: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Based on a hook from tygertec.com 3 | # Source: https://cloudrkt.com/spellcheck-hook.html 4 | # 5 | # Used to check files with the .md extension (markdown) for spelling errors. 6 | # It will run each .md file through aspell and returns an exit code other than 0 when it matches. 7 | # 8 | # Requirements: 9 | # * Bash 10 | # 11 | # To enable this hook, rename this file to "pre-commit". 12 | 13 | # Where are the markdown files located? 14 | SEARCH_DIR="content" 15 | 16 | # Set some fancy colors to indicate errors and wrongly spelled words. 17 | RED='\033[0;31m' 18 | YELLOW='\033[0;33m' 19 | NC='\033[0m' # No Color 20 | 21 | # Start checking the current directory for md files 22 | for file in $(find $SEARCH_DIR -type f -name "*.md"); 23 | # Pass each .md file through aspell. 24 | do output=$(cat $file | aspell --lang=en list); 25 | if [[ $? != 0 ]]; then 26 | echo -e "${RED}Error found in output${NC}, cannot continue." 27 | echo -e "Please check manually for aspell -c $file?" 28 | exit 1 29 | elif [[ $output ]]; then 30 | echo -e "-> ${RED}Spelling errors found${NC} <-" 31 | echo -e "${YELLOW}$output${NC}" |sort -u 32 | echo "Please check with: aspell -c $file" 33 | bad="yes" 34 | good="yes" 35 | fi 36 | done 37 | 38 | # Matched in aspell 39 | if [[ "$bad" == "yes" ]]; then 40 | exit 1 41 | fi 42 | 43 | # No match in aspell 44 | if [[ "$good" == "yes" ]]; then 45 | echo -e "Spelling check is ${RED}OK${NC}, good to go." 46 | exit 0 47 | fi -------------------------------------------------------------------------------- /pre-push-hooks/prevent-bad-push.hook: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Based on the pre-push sample generated by default in .git/hooks 3 | # Source: https://www.git-scm.com/docs/githooks/1.7.1 4 | # 5 | # Prevents push of commits where the log message starts 6 | # with "WIP" (work in progress). Called by "git push" after 7 | # it has checked the remote status, but before anything has been pushed. 8 | # 9 | # The hook should exit with non-zero status after issuing an appropriate 10 | # message if it stops the push. 11 | # 12 | # Requirements: 13 | # * Bash 14 | # 15 | # To enable this hook, rename this file to "pre-push". 16 | 17 | # This hook is called with the following parameters: 18 | # 19 | # $1 -- Name of the remote to which the push is being done 20 | # $2 -- URL to which the push is being done 21 | # 22 | # If pushing without using a named remote those arguments will be equal. 23 | # 24 | # Information about the commits which are being pushed is supplied as lines to 25 | # the standard input in the form: 26 | # 27 | # 28 | 29 | remote="$1" 30 | url="$2" 31 | 32 | z40=0000000000000000000000000000000000000000 33 | 34 | while read local_ref local_sha remote_ref remote_sha 35 | do 36 | if [ "$local_sha" = $z40 ] 37 | then 38 | # Handle delete 39 | : 40 | else 41 | if [ "$remote_sha" = $z40 ] 42 | then 43 | # New branch, examine all commits 44 | range="$local_sha" 45 | else 46 | # Update to existing branch, examine new commits 47 | range="$remote_sha..$local_sha" 48 | fi 49 | 50 | # Check for WIP commit 51 | commit=`git rev-list -n 1 --grep '^WIP' "$range"` 52 | if [ -n "$commit" ] 53 | then 54 | echo >&2 "Found WIP commit in $local_ref, not pushing" 55 | exit 1 56 | fi 57 | fi 58 | done 59 | 60 | exit 0 61 | -------------------------------------------------------------------------------- /tests/verify-name-and-email-test.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | LOG="./tests/tests.log" 4 | 5 | setup() { 6 | # Preserve original user name/email 7 | ORIG_GIT_USER="$(git config --get --local user.name || true)" 8 | ORIG_GIT_EMAIL="$(git config --get --local user.email || true)" 9 | } 10 | 11 | teardown() { 12 | # Restore original user name/email 13 | git config --unset-all user.name 14 | git config --unset-all user.email 15 | 16 | if [ -n "$ORIG_GIT_USER" ]; then 17 | git config --local user.name "$ORIG_GIT_USER" 18 | fi 19 | if [ -n "$ORIG_GIT_EMAIL" ]; then 20 | git config --local user.email "$ORIG_GIT_EMAIL" 21 | fi 22 | 23 | # Don't leave behind an empty [user] section 24 | if [ -z "$(git config --local -l | grep ^user)" ]; then 25 | git config --local --remove-section user 2>/dev/null || true 26 | fi 27 | } 28 | 29 | # Verifies that an error is thrown when a commit is attempted and the user.name is incorrect in the git config. 30 | @test "incorrect name throws error" { 31 | testName="First Last" 32 | $(git config user.name $testName) 33 | 34 | { # try 35 | runGitCommit="$(git commit -m 'Failed commit')" 36 | } || { # catch 37 | date >> "$LOG" 38 | echo "incorrect name throws error test: PASS" >> "$LOG" 39 | echo "" >> "$LOG" 40 | echo "--------------------------------------------" >> "$LOG" 41 | echo "" >> "$LOG" 42 | } 43 | } 44 | 45 | # Verifies that an error is thrown when a commit is attempted and the user.email is incorrect in the git config. 46 | @test "incorrect email throws error" { 47 | testEmail="first.last@gmail.com" 48 | $(git config user.email $testEmail) 49 | 50 | { # try 51 | runGitCommit="$(git commit -m 'Failed commit')" 52 | } || { # catch 53 | date >> "$LOG" 54 | echo "incorrect email throws error test: PASS" >> "$LOG" 55 | echo "" >> "$LOG" 56 | echo "--------------------------------------------" >> "$LOG" 57 | echo "" >> "$LOG" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tests/spell-check-md-files-test.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | LOG="./tests/tests.log" 4 | 5 | logTest() { 6 | # $1 indicates the test status [PASS, FAIL] 7 | date >> "$LOG" 8 | echo "missing aspell error test: $1" >> "$LOG" 9 | echo "" >> "$LOG" 10 | echo "--------------------------------------------" >> "$LOG" 11 | echo "" >> "$LOG" 12 | } 13 | 14 | setup() { 15 | # Create demo .md files to test against 16 | correctSentence="This sentence is correct and working" 17 | misspelledSentence="Tihs nto as muhc and migth have probelms" 18 | otherLangSentence="人間にとっての小さな一歩、人類にとっての大きな飛躍" 19 | echo $correctSentence > proper.md 20 | echo $misspelledSentence > faulty.md 21 | echo $otherLangSentence > other_lang.md 22 | } 23 | 24 | teardown() { 25 | # Remove demo .md files 26 | rm proper.md faulty.md other_lang.md 27 | } 28 | 29 | # Verifies that aspell is installed on the hosts system. 30 | @test "aspell not found error" { 31 | run aspell -v 32 | if [ "$status" -eq 0 ]; then 33 | logTest "PASS" 34 | else 35 | logTest "FAIL" 36 | [ "$output" = "aspell is not installed" ] 37 | fi 38 | } 39 | 40 | # Verifies that aspell works against proper spelling 41 | @test "spellcheck proper md" { 42 | runAspell=$(cat proper.md | aspell --lang=en list) 43 | if [ -z "$runAspell" ]; then 44 | logTest "PASS" 45 | else 46 | logTest "FAIL" 47 | [ "$output" = "aspell found spelling mistakes" ] 48 | fi 49 | } 50 | 51 | # Verifies that aspell works against miss-spelling 52 | @test "spellcheck faulty md" { 53 | runAspell=$(cat faulty.md | aspell --lang=en list) 54 | if [ -n "$runAspell" ]; then 55 | logTest "PASS" 56 | else 57 | logTest "FAIL" 58 | [ "$output" = "aspell didn't find spelling mistakes" ] 59 | fi 60 | } 61 | 62 | # Verifies that aspell checks only english 63 | @test "unsupported language error" { 64 | runAspell=$(cat other_lang.md | aspell --lang=en list) 65 | if [ -z "$runAspell" ]; then 66 | logTest "PASS" 67 | else 68 | logTest "FAIL" 69 | [ "$output" = "aspell found spelling mistakes in unsupported lang" ] 70 | fi 71 | } 72 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | Please note that this project is released with a [Contributor Code of Conduct](CODE-OF-CONDUCT.md). By participating in this project you agree to abide by its terms. 4 | 5 | Contributions are _always_ welcome! Please ensure you follow the guidelines explained below. Thank you! 6 | 7 | ## Pull Requests 8 | 9 | - Search previous pull requests before making a new one, as yours may be a duplicate. 10 | - Keep pull request title short and simple, but descriptive. 11 | - Keep descriptions short and simple, but descriptive. 12 | - Check your spelling and grammar. 13 | 14 | ## Adding a New Git Hook 15 | 16 | Hooray! We like these a lot. These are the requirements for adding a new Git hook. 17 | 18 | - Format the beginning of the hook file like this: 19 | 20 | ``` 21 | #[!/bin/bash or other shebang] 22 | # Based on a hook from [title of source] 23 | # Source: [https://www.website.com/] 24 | # 25 | # This sentence describes in simple terms what the git hook is actually doing. 26 | # 27 | # The hook should exit with non-zero status after issuing an appropriate 28 | # message if it stops the [git command]. (If your script doesn't do this then you can remove this section) 29 | # 30 | # Requirements: 31 | # * Python 2/3 (whatever language the script is written in) 32 | # 33 | # To enable this hook, rename this file to "[type of git hook]". 34 | 35 | // code for actual hook goes here 36 | ``` 37 | 38 | - Add a comment above each body/section of code to explain what it's doing. 39 | - Add additional comments as needed. 40 | - Add it to the list of Git Hook Scripts on the readme, following the existing formatting. 41 | 42 | ## Adding Anything Else 43 | 44 | Have something to contribute that isn't a Git hook? We love all forms of friendly contributions! Feel free to make a change to the readme or other files and create a pull request, or you can [create a new issue](https://github.com/CompSciLauren/awesome-git-hooks/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=) to discuss any proposals/feedback/thoughts/etc. 45 | 46 | ## How to Contribute 47 | 48 | To fix a bug or add an enhancement, follow these steps: 49 | 50 | - Fork the repo 51 | - Create a new branch (`git checkout -b improve-feature`) 52 | - Make the appropriate changes in the files 53 | - Commit your changes (`git commit -am 'Improve feature'`) 54 | - Push to the branch (`git push origin improve-feature`) 55 | - Create a Pull Request 56 | -------------------------------------------------------------------------------- /CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project owner at compscilauren@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project owner is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /query-watchman-hooks/fsmonitor-watchman.hook: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Based on the query-watchman sample generated by default in .git/hooks 3 | # Source: https://www.git-scm.com/docs/githooks/1.7.1 4 | # 5 | # An example hook script to integrate Watchman 6 | # (https://facebook.github.io/watchman/) with git to speed up detecting 7 | # new and modified files. 8 | # 9 | # The hook is passed a version (currently 1) and a time in nanoseconds 10 | # formatted as a string and outputs to stdout all files that have been 11 | # modified since the given time. Paths must be relative to the root of 12 | # the working tree and separated by a single NUL. 13 | # 14 | # Requirements: 15 | # * Perl 16 | # 17 | # To enable this hook, rename this file to "query-watchman" and set 18 | # 'git config core.fsmonitor .git/hooks/query-watchman' 19 | 20 | use strict; 21 | use warnings; 22 | use IPC::Open2; 23 | 24 | my ($version, $time) = @ARGV; 25 | 26 | # Check the hook interface version 27 | 28 | if ($version == 1) { 29 | # convert nanoseconds to seconds 30 | $time = int $time / 1000000000; 31 | } else { 32 | die "Unsupported query-fsmonitor hook version '$version'.\n" . 33 | "Falling back to scanning...\n"; 34 | } 35 | 36 | my $git_work_tree; 37 | if ($^O =~ 'msys' || $^O =~ 'cygwin') { 38 | $git_work_tree = Win32::GetCwd(); 39 | $git_work_tree =~ tr/\\/\//; 40 | } else { 41 | require Cwd; 42 | $git_work_tree = Cwd::cwd(); 43 | } 44 | 45 | my $retry = 1; 46 | 47 | launch_watchman(); 48 | 49 | sub launch_watchman { 50 | 51 | my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty') 52 | or die "open2() failed: $!\n" . 53 | "Falling back to scanning...\n"; 54 | 55 | # In the query expression below we're asking for names of files that 56 | # changed since $time but were not transient (ie created after 57 | # $time but no longer exist). 58 | # 59 | # To accomplish this, we're using the "since" generator to use the 60 | # recency index to select candidate nodes and "fields" to limit the 61 | # output to file names only. Then we're using the "expression" term to 62 | # further constrain the results. 63 | # 64 | # The category of transient files that we want to ignore will have a 65 | # creation clock (cclock) newer than $time_t value and will also not 66 | # currently exist. 67 | 68 | my $query = <<" END"; 69 | ["query", "$git_work_tree", { 70 | "since": $time, 71 | "fields": ["name"], 72 | "expression": ["not", ["allof", ["since", $time, "cclock"], ["not", "exists"]]] 73 | }] 74 | END 75 | 76 | print CHLD_IN $query; 77 | close CHLD_IN; 78 | my $response = do {local $/; }; 79 | 80 | die "Watchman: command returned no output.\n" . 81 | "Falling back to scanning...\n" if $response eq ""; 82 | die "Watchman: command returned invalid output: $response\n" . 83 | "Falling back to scanning...\n" unless $response =~ /^\{/; 84 | 85 | my $json_pkg; 86 | eval { 87 | require JSON::XS; 88 | $json_pkg = "JSON::XS"; 89 | 1; 90 | } or do { 91 | require JSON::PP; 92 | $json_pkg = "JSON::PP"; 93 | }; 94 | 95 | my $o = $json_pkg->new->utf8->decode($response); 96 | 97 | if ($retry > 0 and $o->{error} and $o->{error} =~ m/unable to resolve root .* directory (.*) is not watched/) { 98 | print STDERR "Adding '$git_work_tree' to watchman's watch list.\n"; 99 | $retry--; 100 | qx/watchman watch "$git_work_tree"/; 101 | die "Failed to make watchman watch '$git_work_tree'.\n" . 102 | "Falling back to scanning...\n" if $? != 0; 103 | 104 | # Watchman will always return all files on the first query so 105 | # return the fast "everything is dirty" flag to git and do the 106 | # Watchman query just to get it over with now so we won't pay 107 | # the cost in git to look up each individual file. 108 | print "/\0"; 109 | eval { launch_watchman() }; 110 | exit 0; 111 | } 112 | 113 | die "Watchman: $o->{error}.\n" . 114 | "Falling back to scanning...\n" if $o->{error}; 115 | 116 | binmode STDOUT, ":utf8"; 117 | local $, = "\0"; 118 | print @{$o->{files}}; 119 | } 120 | -------------------------------------------------------------------------------- /update-hooks/prevent-unannotated-tags.hook: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Based on the update sample generated by default in .git/hooks 3 | # Source: https://www.git-scm.com/docs/githooks/1.7.1 4 | # 5 | # Blocks unannotated tags from entering. 6 | # Called by "git receive-pack" with arguments: refname sha1-old sha1-new 7 | # 8 | # The hook should exit with non-zero status after issuing an appropriate 9 | # message if it stops the push. 10 | # 11 | # Requirements: 12 | # * Bash 13 | # 14 | # To enable this hook, rename this file to "update". 15 | 16 | # Config 17 | # ------ 18 | # hooks.allowunannotated 19 | # This boolean sets whether unannotated tags will be allowed into the 20 | # repository. By default they won't be. 21 | # hooks.allowdeletetag 22 | # This boolean sets whether deleting tags will be allowed in the 23 | # repository. By default they won't be. 24 | # hooks.allowmodifytag 25 | # This boolean sets whether a tag may be modified after creation. By default 26 | # it won't be. 27 | # hooks.allowdeletebranch 28 | # This boolean sets whether deleting branches will be allowed in the 29 | # repository. By default they won't be. 30 | # hooks.denycreatebranch 31 | # This boolean sets whether remotely creating branches will be denied 32 | # in the repository. By default this is allowed. 33 | 34 | # command line 35 | refname="$1" 36 | oldrev="$2" 37 | newrev="$3" 38 | 39 | # safety check 40 | if [ -z "$GIT_DIR" ]; then 41 | echo "Don't run this script from the command line." >&2 42 | echo " (if you want, you could supply GIT_DIR then run" >&2 43 | echo " $0 )" >&2 44 | exit 1 45 | fi 46 | 47 | if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then 48 | echo "usage: $0 " >&2 49 | exit 1 50 | fi 51 | 52 | # config 53 | allowunannotated=$(git config --bool hooks.allowunannotated) 54 | allowdeletebranch=$(git config --bool hooks.allowdeletebranch) 55 | denycreatebranch=$(git config --bool hooks.denycreatebranch) 56 | allowdeletetag=$(git config --bool hooks.allowdeletetag) 57 | allowmodifytag=$(git config --bool hooks.allowmodifytag) 58 | 59 | # check for no description 60 | projectdesc=$(sed -e '1q' "$GIT_DIR/description") 61 | case "$projectdesc" in 62 | "Unnamed repository"* | "") 63 | echo "*** Project description file hasn't been set" >&2 64 | exit 1 65 | ;; 66 | esac 67 | 68 | # check types 69 | # if $newrev is 0000...0000, it's a commit to delete a ref. 70 | zero="0000000000000000000000000000000000000000" 71 | if [ "$newrev" = "$zero" ]; then 72 | newrev_type=delete 73 | else 74 | newrev_type=$(git cat-file -t $newrev) 75 | fi 76 | 77 | case "$refname","$newrev_type" in 78 | refs/tags/*,commit) 79 | # unannotated tag 80 | short_refname=${refname##refs/tags/} 81 | if [ "$allowunannotated" != "true" ]; then 82 | echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 83 | echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 84 | exit 1 85 | fi 86 | ;; 87 | refs/tags/*,delete) 88 | # delete tag 89 | if [ "$allowdeletetag" != "true" ]; then 90 | echo "*** Deleting a tag is not allowed in this repository" >&2 91 | exit 1 92 | fi 93 | ;; 94 | refs/tags/*,tag) 95 | # annotated tag 96 | if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 97 | then 98 | echo "*** Tag '$refname' already exists." >&2 99 | echo "*** Modifying a tag is not allowed in this repository." >&2 100 | exit 1 101 | fi 102 | ;; 103 | refs/heads/*,commit) 104 | # branch 105 | if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then 106 | echo "*** Creating a branch is not allowed in this repository" >&2 107 | exit 1 108 | fi 109 | ;; 110 | refs/heads/*,delete) 111 | # delete branch 112 | if [ "$allowdeletebranch" != "true" ]; then 113 | echo "*** Deleting a branch is not allowed in this repository" >&2 114 | exit 1 115 | fi 116 | ;; 117 | refs/remotes/*,commit) 118 | # tracking branch 119 | ;; 120 | refs/remotes/*,delete) 121 | # delete tracking branch 122 | if [ "$allowdeletebranch" != "true" ]; then 123 | echo "*** Deleting a tracking branch is not allowed in this repository" >&2 124 | exit 1 125 | fi 126 | ;; 127 | *) 128 | # anything else (is there anything else?) 129 | echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 130 | exit 1 131 | ;; 132 | esac 133 | 134 | exit 0 135 | -------------------------------------------------------------------------------- /pre-rebase-hooks/prevent-rebase.hook: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Based on the pre-rebase sample generated by default in .git/hooks 3 | # Source: https://www.git-scm.com/docs/githooks/1.7.1 4 | # Copyright (c) 2006, 2008 Junio C Hamano 5 | # 6 | # The "pre-rebase" hook is run just before "git rebase" starts doing 7 | # its job, and can prevent the command from running by exiting with 8 | # non-zero status. 9 | # 10 | # The hook is called with the following parameters: 11 | # 12 | # $1 -- the upstream the series was forked from. 13 | # $2 -- the branch being rebased (or empty when rebasing the current branch). 14 | # 15 | # Prevents topic branches that are already 16 | # merged to 'next' branch from getting rebased, because allowing it 17 | # would result in rebasing already published history. 18 | # 19 | # The hook should exit with non-zero status after issuing an appropriate 20 | # message if it stops the rebase. 21 | # 22 | # Requirements: 23 | # * Bash 24 | # 25 | # To enable this hook, rename this file to "pre-rebase". 26 | 27 | publish=next 28 | basebranch="$1" 29 | if test "$#" = 2 30 | then 31 | topic="refs/heads/$2" 32 | else 33 | topic=`git symbolic-ref HEAD` || 34 | exit 0 ; # we do not interrupt rebasing detached HEAD 35 | fi 36 | 37 | case "$topic" in 38 | refs/heads/??/*) 39 | ;; 40 | *) 41 | exit 0 ; # we do not interrupt others. 42 | ;; 43 | esac 44 | 45 | # Now we are dealing with a topic branch being rebased 46 | # on top of master. Is it OK to rebase it? 47 | 48 | # Does the topic really exist? 49 | git show-ref -q "$topic" || { 50 | echo >&2 "No such branch $topic" 51 | exit 1 52 | } 53 | 54 | # Is topic fully merged to master? 55 | not_in_master=`git rev-list --pretty=oneline ^master "$topic"` 56 | if test -z "$not_in_master" 57 | then 58 | echo >&2 "$topic is fully merged to master; better remove it." 59 | exit 1 ;# we could allow it, but there is no point. 60 | fi 61 | 62 | # Is topic ever merged to next? If so you should not be rebasing it. 63 | only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` 64 | only_next_2=`git rev-list ^master ${publish} | sort` 65 | if test "$only_next_1" = "$only_next_2" 66 | then 67 | not_in_topic=`git rev-list "^$topic" master` 68 | if test -z "$not_in_topic" 69 | then 70 | echo >&2 "$topic is already up to date with master" 71 | exit 1 ; # we could allow it, but there is no point. 72 | else 73 | exit 0 74 | fi 75 | else 76 | not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` 77 | /usr/bin/perl -e ' 78 | my $topic = $ARGV[0]; 79 | my $msg = "* $topic has commits already merged to public branch:\n"; 80 | my (%not_in_next) = map { 81 | /^([0-9a-f]+) /; 82 | ($1 => 1); 83 | } split(/\n/, $ARGV[1]); 84 | for my $elem (map { 85 | /^([0-9a-f]+) (.*)$/; 86 | [$1 => $2]; 87 | } split(/\n/, $ARGV[2])) { 88 | if (!exists $not_in_next{$elem->[0]}) { 89 | if ($msg) { 90 | print STDERR $msg; 91 | undef $msg; 92 | } 93 | print STDERR " $elem->[1]\n"; 94 | } 95 | } 96 | ' "$topic" "$not_in_next" "$not_in_master" 97 | exit 1 98 | fi 99 | 100 | <<\DOC_END 101 | 102 | This sample hook safeguards topic branches that have been 103 | published from being rewound. 104 | 105 | The workflow assumed here is: 106 | 107 | * Once a topic branch forks from "master", "master" is never 108 | merged into it again (either directly or indirectly). 109 | 110 | * Once a topic branch is fully cooked and merged into "master", 111 | it is deleted. If you need to build on top of it to correct 112 | earlier mistakes, a new topic branch is created by forking at 113 | the tip of the "master". This is not strictly necessary, but 114 | it makes it easier to keep your history simple. 115 | 116 | * Whenever you need to test or publish your changes to topic 117 | branches, merge them into "next" branch. 118 | 119 | The script, being an example, hardcodes the publish branch name 120 | to be "next", but it is trivial to make it configurable via 121 | $GIT_DIR/config mechanism. 122 | 123 | With this workflow, you would want to know: 124 | 125 | (1) ... if a topic branch has ever been merged to "next". Young 126 | topic branches can have stupid mistakes you would rather 127 | clean up before publishing, and things that have not been 128 | merged into other branches can be easily rebased without 129 | affecting other people. But once it is published, you would 130 | not want to rewind it. 131 | 132 | (2) ... if a topic branch has been fully merged to "master". 133 | Then you can delete it. More importantly, you should not 134 | build on top of it -- other people may already want to 135 | change things related to the topic as patches against your 136 | "master", so if you need further changes, it is better to 137 | fork the topic (perhaps with the same name) afresh from the 138 | tip of "master". 139 | 140 | Let's look at this example: 141 | 142 | o---o---o---o---o---o---o---o---o---o "next" 143 | / / / / 144 | / a---a---b A / / 145 | / / / / 146 | / / c---c---c---c B / 147 | / / / \ / 148 | / / / b---b C \ / 149 | / / / / \ / 150 | ---o---o---o---o---o---o---o---o---o---o---o "master" 151 | 152 | 153 | A, B and C are topic branches. 154 | 155 | * A has one fix since it was merged up to "next". 156 | 157 | * B has finished. It has been fully merged up to "master" and "next", 158 | and is ready to be deleted. 159 | 160 | * C has not merged to "next" at all. 161 | 162 | We would want to allow C to be rebased, refuse A, and encourage 163 | B to be deleted. 164 | 165 | To compute (1): 166 | 167 | git rev-list ^master ^topic next 168 | git rev-list ^master next 169 | 170 | if these match, topic has not merged in next at all. 171 | 172 | To compute (2): 173 | 174 | git rev-list master..topic 175 | 176 | if this is empty, it is fully merged to "master". 177 | 178 | DOC_END 179 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | Awesome Git Hooks
Awesome Git Hooks 4 |

5 | 6 |

7 | Awesome Lists 8 | PRs welcome 9 |

10 | 11 | # Awesome Git Hooks 12 | 13 | > :anchor: Easy-to-use git hooks for automating tasks during git workflows. 14 | 15 | Git hooks are custom scripts you can use to automate tasks which are triggered before or after a git command is executed. There are two groups of these hooks: client-side and server-side. Client-side hooks are triggered by operations such as committing and merging, while server-side hooks run on network operations such as receiving pushed commits. This repo contains helpful resources as well as a variety of git hook scripts that can be easily customized to serve different purposes. 16 | 17 | :heavy_check_mark: Nothing to install/download 18 | 19 | :heavy_check_mark: Code is well-documented 20 | 21 | :heavy_check_mark: Grab & go! Copy the code you want to use and paste into your .git/hooks folder 22 | 23 | Contributions are _always_ welcome! Please see our [Contribution Guidelines](CONTRIBUTING.md). Also, if you don't find the script you want below, you can [create a new issue](https://github.com/CompSciLauren/awesome-git-hooks/issues/new?assignees=&labels=enhancement&template=new-git-hook-script-request.md&title=) to request it. 24 | 25 | ## Contents 26 | 27 | - [Git Hook Scripts](#git-hook-scripts) 28 | - [commit-msg](#commit-msg) 29 | - [post-checkout](#post-checkout) 30 | - [post-update](#post-update) 31 | - [pre-commit](#pre-commit) 32 | - [prepare-commit-msg](#prepare-commit-msg) 33 | - [pre-push](#pre-push) 34 | - [pre-rebase](#pre-rebase) 35 | - [query-watchman](#query-watchman) 36 | - [update](#update) 37 | - [Quick Start](#quick-start) 38 | - [Tools](#tools) 39 | - [Written Guides](#written-guides) 40 | - [Video Guides](#video-guides) 41 | 42 | ## Git Hook Scripts 43 | 44 | Note: The icon next to each script signifies what language it is written in. 45 | 46 | | icon | language | 47 | | -------------------------------------------------------- | -------- | 48 | | Bash Icon | `bash` | 49 | | Python Icon | `python` | 50 | | Perl Icon | `perl` | 51 | 52 | ### commit-msg 53 | 54 | - [enforce-insert-issue-number](https://github.com/CompSciLauren/awesome-git-hooks/blob/master/commit-msg-hooks/enforce-insert-issue-number.hook) - Make sure user did not delete the ISSUE-\[#] string that was generated by prepare-commit-msg/insert-issue-number.hook. Python Icon 55 | 56 | ### post-checkout 57 | 58 | - [delete-pyc-files](https://github.com/CompSciLauren/awesome-git-hooks/blob/master/post-checkout-hooks/delete-pyc-files.hook) - Delete all .pyc files every time a new branch is checked out. Python Icon 59 | - [new-branch-alert](https://github.com/CompSciLauren/awesome-git-hooks/blob/master/post-checkout-hooks/new-branch-alert.hook) - Display a message when a new branch is checked out for the first time. Bash Icon 60 | 61 | ### post-update 62 | 63 | - [update-server-info](https://github.com/CompSciLauren/awesome-git-hooks/blob/master/post-update-hooks/update-server-info.hook) - Prepare a packed repository for use over dumb transports (e.g. http). Bash Icon 64 | 65 | ### pre-commit 66 | 67 | - [dotenvx](https://github.com/CompSciLauren/awesome-git-hooks/blob/master/pre-commit-hooks/dotenvx.hook) - Prevent committing your `.env` file(s) to code. Bash Icon 68 | - [format-code](https://github.com/CompSciLauren/awesome-git-hooks/blob/master/pre-commit-hooks/format-code.hook) - Run command to format code and re-add any files modified after formatting. Bash Icon 69 | - [search-term](https://github.com/CompSciLauren/awesome-git-hooks/blob/master/pre-commit-hooks/search-term.hook) - Fail commit if a specific term is found in the code. Bash Icon 70 | - [spell-check-md-files](https://github.com/CompSciLauren/awesome-git-hooks/blob/master/pre-commit-hooks/spell-check-md-files.hook) - Check files with .md extension for spelling errors. Bash Icon 71 | - [verify-name-and-email](https://github.com/CompSciLauren/awesome-git-hooks/blob/master/pre-commit-hooks/verify-name-and-email.hook) - Fail commit if user.name or user.email is incorrect. Bash Icon 72 | 73 | ### prepare-commit-msg 74 | 75 | - [include-git-diff-name-status](https://github.com/CompSciLauren/awesome-git-hooks/blob/master/prepare-commit-msg-hooks/include-git-diff-name-status.hook) - Include the output of "git diff --name-status -r" into the message, just before the "git status" output. Bash Icon 76 | - [insert-issue-number](https://github.com/CompSciLauren/awesome-git-hooks/blob/master/prepare-commit-msg-hooks/insert-issue-number.hook) - Insert issue number to beginning of the commit message. Python Icon 77 | 78 | ### pre-push 79 | 80 | - [prevent-bad-push](https://github.com/CompSciLauren/awesome-git-hooks/blob/master/pre-push-hooks/prevent-bad-push.hook) - Prevent push of commits where the log message starts with "WIP" (work in progress). Bash Icon 81 | 82 | ### pre-rebase 83 | 84 | - [prevent-rebase](https://github.com/CompSciLauren/awesome-git-hooks/blob/master/pre-rebase-hooks/prevent-rebase.hook) - Prevent topic branches that are already merged to 'next' branch from getting rebased, because allowing it would result in rebasing already published history. Bash Icon 85 | 86 | ### query-watchman 87 | 88 | - [fsmonitor-watchman](https://github.com/CompSciLauren/awesome-git-hooks/blob/master/query-watchman-hooks/fsmonitor-watchman.hook) - Output to stdout all files that have been modified since a given time. Perl Icon 89 | 90 | ### update 91 | 92 | - [update](https://github.com/CompSciLauren/awesome-git-hooks/blob/master/update-hooks/prevent-unannotated-tags.hook) - Block unannotated tags from entering. Bash Icon 93 | 94 | ## Quick Start 95 | 96 | 1. Pick a hook, any hook! Try the "verify-name-and-email" one if you're not sure where to start. 97 | 2. Navigate to your project's hooks folder (.git/hooks). 98 | 3. You should see a list of files already in there. Create a new file called the exact commit type that you want to use (eg: "commit-msg", "pre-rebase", "pre-commit", etc). Do not give it an extension. 99 | 100 | ![create new file](create-new-file.gif) 101 | 102 | 4. Open your new file and paste the code from the hook you chose out of this repo (eg: [verify-name-and-email.hook](https://github.com/CompSciLauren/git-hooks/blob/master/pre-commit-hooks/verify-name-and-email.hook)). 103 | 5. Save file. Done! Now the git hook will be triggered automatically. 104 | 105 | ## Tools 106 | 107 | - [Husky](https://github.com/typicode/husky) - Manage git hooks with a nice user interface. 108 | 109 | - [Overcommit](https://github.com/sds/overcommit) - A fully configurable and extendable git hook manager. 110 | 111 | - [Git Build Hook Maven Plugin](https://github.com/rudikershaw/git-build-hook) - Install Git hooks and config during a Maven build. 112 | 113 | - [CaptainHook](https://github.com/CaptainHookPhp/captainhook) - Git hooks manager for PHP developers. 114 | 115 | - [pre-commit](https://github.com/pre-commit/pre-commit) - A framework for managing and maintaining multi-language pre-commit hooks. 116 | 117 | ## Written Guides 118 | 119 | - [Git hooks documentation at git-scm.com](https://git-scm.com/docs/githooks) 120 | 121 | - [Git Pro book by Scott Chacon and Ben Straub](https://git-scm.com/book/en/v2) 122 | 123 | - [An Introduction to Git Hooks](https://www.sitepoint.com/introduction-git-hooks/) 124 | 125 | - [Atlassian Tutorial on Git Hooks](https://www.atlassian.com/ru/git/tutorials/git-hooks) 126 | 127 | - [Easy git hooks with husky](https://www.vojtechruzicka.com/githooks-husky/) 128 | 129 | - [Git Hooked](https://www.javascriptjanuary.com/blog/git-hooked 'Git Hooked') 130 | 131 | - [How To Use Git Hooks To Automate Development and Deployment Tasks](https://www.digitalocean.com/community/tutorials/how-to-use-git-hooks-to-automate-development-and-deployment-tasks) 132 | 133 | - [Automate Your Workflow with Git Hooks](https://hackernoon.com/automate-your-workflow-with-git-hooks-fef5d9b2a58c) 134 | 135 | - [Using JavaScript in Your Git Hooks](https://medium.com/@Sergeon/using-javascript-in-your-git-hooks-f0ce09477334 'Using JavaScript in Your Git Hooks') 136 | 137 | - [An In-Depth Look at Git Hooks](https://dzone.com/articles/an-in-depth-look-at-git-hooks) 138 | 139 | - [Git hooks and practical uses. Yes, even on Windows.](https://www.tygertec.com/git-hooks-practical-uses-windows/) 140 | 141 | - [Automatically Manage Git Hooks with Direnv](https://knpw.rs/blog/direnv-git-hooks) 142 | 143 | ## Video Guides 144 | 145 | - [Git Hooks Part 1 - Getting Started](https://www.youtube.com/watch?v=aB3eq52sZSU) 146 | 147 | - [Git hooks and practical uses. Yes, even on Windows.](http://www.youtube.com/watch?feature=player_embedded&v=fMYv6-SZsSo&t=140s) 148 | 149 | ## License 150 | 151 | [![CC0](http://mirrors.creativecommons.org/presskit/buttons/88x31/svg/cc-zero.svg)](https://creativecommons.org/publicdomain/zero/1.0/)
This work is licensed under a Creative Commons Attribution 1.0 International License. 152 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | 3 | Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | 3. Public License Fallback. Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | 4. Limitations and Disclaimers. 94 | 95 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 96 | surrendered, licensed or otherwise affected by this document. 97 | 98 | b. Affirmer offers the Work as-is and makes no representations or warranties 99 | of any kind concerning the Work, express, implied, statutory or otherwise, 100 | including without limitation warranties of title, merchantability, fitness 101 | for a particular purpose, non infringement, or the absence of latent or 102 | other defects, accuracy, or the present or absence of errors, whether or not 103 | discoverable, all to the greatest extent permissible under applicable law. 104 | 105 | c. Affirmer disclaims responsibility for clearing rights of other persons 106 | that may apply to the Work or any use thereof, including without limitation 107 | any person's Copyright and Related Rights in the Work. Further, Affirmer 108 | disclaims responsibility for obtaining any necessary consents, permissions 109 | or other rights required for any use of the Work. 110 | 111 | d. Affirmer understands and acknowledges that Creative Commons is not a 112 | party to this document and has no duty or obligation with respect to this 113 | CC0 or use of the Work. 114 | 115 | For more information, please see 116 | 117 | CC0 1.0 Universal 118 | 119 | Statement of Purpose 120 | 121 | The laws of most jurisdictions throughout the world automatically confer 122 | exclusive Copyright and Related Rights (defined below) upon the creator and 123 | subsequent owner(s) (each and all, an "owner") of an original work of 124 | authorship and/or a database (each, a "Work"). 125 | 126 | Certain owners wish to permanently relinquish those rights to a Work for the 127 | purpose of contributing to a commons of creative, cultural and scientific 128 | works ("Commons") that the public can reliably and without fear of later 129 | claims of infringement build upon, modify, incorporate in other works, reuse 130 | and redistribute as freely as possible in any form whatsoever and for any 131 | purposes, including without limitation commercial purposes. These owners may 132 | contribute to the Commons to promote the ideal of a free culture and the 133 | further production of creative, cultural and scientific works, or to gain 134 | reputation or greater distribution for their Work in part through the use and 135 | efforts of others. 136 | 137 | For these and/or other purposes and motivations, and without any expectation 138 | of additional consideration or compensation, the person associating CC0 with a 139 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 140 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 141 | and publicly distribute the Work under its terms, with knowledge of his or her 142 | Copyright and Related Rights in the Work and the meaning and intended legal 143 | effect of CC0 on those rights. 144 | 145 | 1. Copyright and Related Rights. A Work made available under CC0 may be 146 | protected by copyright and related or neighboring rights ("Copyright and 147 | Related Rights"). Copyright and Related Rights include, but are not limited 148 | to, the following: 149 | 150 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 151 | and translate a Work; 152 | 153 | ii. moral rights retained by the original author(s) and/or performer(s); 154 | 155 | iii. publicity and privacy rights pertaining to a person's image or likeness 156 | depicted in a Work; 157 | 158 | iv. rights protecting against unfair competition in regards to a Work, 159 | subject to the limitations in paragraph 4(a), below; 160 | 161 | v. rights protecting the extraction, dissemination, use and reuse of data in 162 | a Work; 163 | 164 | vi. database rights (such as those arising under Directive 96/9/EC of the 165 | European Parliament and of the Council of 11 March 1996 on the legal 166 | protection of databases, and under any national implementation thereof, 167 | including any amended or successor version of such directive); and 168 | 169 | vii. other similar, equivalent or corresponding rights throughout the world 170 | based on applicable law or treaty, and any national implementations thereof. 171 | 172 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 173 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 174 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 175 | and Related Rights and associated claims and causes of action, whether now 176 | known or unknown (including existing as well as future claims and causes of 177 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 178 | duration provided by applicable law or treaty (including future time 179 | extensions), (iii) in any current or future medium and for any number of 180 | copies, and (iv) for any purpose whatsoever, including without limitation 181 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 182 | the Waiver for the benefit of each member of the public at large and to the 183 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 184 | shall not be subject to revocation, rescission, cancellation, termination, or 185 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 186 | by the public as contemplated by Affirmer's express Statement of Purpose. 187 | 188 | 3. Public License Fallback. Should any part of the Waiver for any reason be 189 | judged legally invalid or ineffective under applicable law, then the Waiver 190 | shall be preserved to the maximum extent permitted taking into account 191 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 192 | is so judged Affirmer hereby grants to each affected person a royalty-free, 193 | non transferable, non sublicensable, non exclusive, irrevocable and 194 | unconditional license to exercise Affirmer's Copyright and Related Rights in 195 | the Work (i) in all territories worldwide, (ii) for the maximum duration 196 | provided by applicable law or treaty (including future time extensions), (iii) 197 | in any current or future medium and for any number of copies, and (iv) for any 198 | purpose whatsoever, including without limitation commercial, advertising or 199 | promotional purposes (the "License"). The License shall be deemed effective as 200 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 201 | License for any reason be judged legally invalid or ineffective under 202 | applicable law, such partial invalidity or ineffectiveness shall not 203 | invalidate the remainder of the License, and in such case Affirmer hereby 204 | affirms that he or she will not (i) exercise any of his or her remaining 205 | Copyright and Related Rights in the Work or (ii) assert any associated claims 206 | and causes of action with respect to the Work, in either case contrary to 207 | Affirmer's express Statement of Purpose. 208 | 209 | 4. Limitations and Disclaimers. 210 | 211 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 212 | surrendered, licensed or otherwise affected by this document. 213 | 214 | b. Affirmer offers the Work as-is and makes no representations or warranties 215 | of any kind concerning the Work, express, implied, statutory or otherwise, 216 | including without limitation warranties of title, merchantability, fitness 217 | for a particular purpose, non infringement, or the absence of latent or 218 | other defects, accuracy, or the present or absence of errors, whether or not 219 | discoverable, all to the greatest extent permissible under applicable law. 220 | 221 | c. Affirmer disclaims responsibility for clearing rights of other persons 222 | that may apply to the Work or any use thereof, including without limitation 223 | any person's Copyright and Related Rights in the Work. Further, Affirmer 224 | disclaims responsibility for obtaining any necessary consents, permissions 225 | or other rights required for any use of the Work. 226 | 227 | d. Affirmer understands and acknowledges that Creative Commons is not a 228 | party to this document and has no duty or obligation with respect to this 229 | CC0 or use of the Work. 230 | 231 | For more information, please see 232 | 233 | --------------------------------------------------------------------------------