18.05.15

Git pre-push hook to check for bad log pattern

I've just written a pre-push hook for Git that will check for certain patterns in the log messages that would get pushed.

This is meant to prevent you from accidentally pushing anything that starts with "fixup!" or "stash!" to certain branches (master, etc). These log messages are meant to be used with the autostash feature, which would setup your file for `git rebase --interactive` accordingly.

The code can be found in my dotfiles: ~df/config/git/template/hooks/pre-push.

I am using this through my Git template directory, which gets used with `git init` (and `git init` in an existing repo will also install missing hooks).

Here's the current version:

Code:

#!/bin/sh
#
# Git pre-push hook to check for "fixup!" and "squash!" in commit messages,
# which are not meant to get pushed to public/non-PR branches.
#
# It will also prevent fast-forward pushes, because git-log fails for them.
#
# You can use `--no-verify` with git-push to skip this hook.
#
# Args:
# 1: name of the remote
# 2: location of the remote
# stdin: <local ref> SP <local sha1> SP <remote ref> SP <remote sha1> LF
 
remote=$1
 
# Which remote heads/branches to check?
# (a regular expression for "grep -E").
CHECK_REMOTE_HEADS='(master|develop|production|staging)'
 
# The log pattern to check.
# (a regular expression for "git grep")
BAD_LOG_PATTERN='^(fixup!|squash!)'
 
# Uncomment for debugging.
# (the ":" is there so the function can be "empty")
debug() {
  :
  # echo "debug: $@"
}
debug "$0: $1 $2 ($#)"
 
# Return status of the script.
ret=0
 
while read local_ref local_sha remote_ref remote_sha; do
  debug "Pushing: $local_ref ($local_sha) => $remote_ref ($remote_sha)"
 
  # Is this a new remote ref?
  if [ "$remote_sha" = "0000000000000000000000000000000000000000" ]; then
    log_arg="$local_sha"
  else
    log_arg="${remote_sha}..${local_sha}"
  fi
 
  # Skip certain branches, but no other refs (tags).
  remote_head=${remote_ref#refs/heads/}
  if [ "$remote_ref" != "$remote_head" ]; then
    # This is a head/branch (no tag).
 
    # Allow any non-protected branch.
    if ! echo "$remote_head" | grep -qE "$CHECK_REMOTE_HEADS"; then
      debug "Skipping remote head: $remote_ref ($remote_head)"
      continue
    fi
  fi
 
  # Check for the bad log pattern.
  log_cmd="git log --grep $BAD_LOG_PATTERN --color=always $log_arg"
  log="$($log_cmd)"
  log_ret=$?
  if [ "$log_ret" != 0 ]; then
    echo "ERROR: git-log failed (non-fast-forward / forced push?)"
    echo "  cmd: $log_cmd"
    ret=1
  fi
  if [ -n "$log" ]; then
    echo "ERROR (pre-push): there are commits with a bad pattern ($BAD_LOG_PATTERN)!"
    echo "       local_ref: $local_ref => remote_ref: $remote_ref"
    debug "git-log argument: $log_arg"
    echo "$log" | sed 's/^/  /'
    ret=1
  fi
done
 
debug "ret=$ret"
exit $ret
By Daniel in development, Open Source, Snippets05/18/15 English (US) Email
Tags: ,

15.05.15

14.05.15

13.05.15

12.05.15

11.05.15

10.05.15

Seitenleiste