Anand Sunderraman
Anand Sunderraman

Reputation: 8128

How can I get git push to ask for confirmation or run some checks?

I would like to customize my Git prompt in such a way that it reminds me or runs checks for me before I push something to a remote repo.

For instance, when I run

git push

Git should ask the user

Did you run unit tests locally?

or something to that effect, so that I don't accidentally push code that is not unit-tested.

Upvotes: 5

Views: 3262

Answers (2)

Charles Duffy
Charles Duffy

Reputation: 295316

First: This won't work (not in a technical sense, but in a human-habit sense). See Rob Mayoff's idea instead.

However, to demonstrate an implementation, you could put the following in your ~/.bashrc:

git() {
  if [[ $1 = push ]]; then
    printf %s "Did you run unit tests locally?"
    read response
    case $response in
      y|Y|yes|YES) command git "$@" ;;
      *)           echo "Aborting" ;;
    esac
  else
    command git "$@"
  fi
}

Better, to implement Rob's idea:

git() {
  local -a options=( )
  while (( $# )) && [[ $1 = -* ]]; do
    case $1 in
      -C|-c) options+=( "$1" "$2" ); shift; shift ;;
      *)     options+=( "$1" ); shift ;;
    esac
  done
  local base_dir=$(git rev-parse --show-toplevel)
  case $1 in
    commit|merge|rebase)
      touch "$base_dir/.untested"
      command git "${options[@]}" "$@"
      ;;
    push)
      if [[ -e "$base_dir/.untested" ]]; then
        echo "Untested commits exist; you must run tests"
      else
        command git "${options[@]}" "$@"
      fi
      ;;
    *) command git "${options[@]}" "$@" ;;
  esac
}

unittest() (
  cd "$(git rev-parse --show-toplevel)"
  make test && rm .untested
)

Upvotes: 0

rob mayoff
rob mayoff

Reputation: 385540

Set up your pre-push hook to prevent pushing unless the file .testspassed exists. Example:

cat > .git/hooks/pre-push <<EOF
#!/bin/sh -e

if ! [ -f .testspassed ]; then
    echo 1>&2 "push aborted because tests were not run or did not all pass"
    exit 1
fi

exit 0
EOF
chmod +x .git/hooks/pre-push

Set up your prepare-commit-msg hook to remove .testspassed if it exists:

cat > .git/hooks/prepare-commit-msg <<EOF
#!/bin/sh -e

rm -f .testspassed
exit 0
EOF

I'm using prepare-commit-msg instead of pre-commit because prepare-commit-msg runs on merges too. Any time you commit or merge, git will remove the .testspassed file, preventing you from pushing.

Tell git to ignore the .testspassed file so it doesn't end up in your repo:

echo .testspassed >> .gitignore
git commit -m 'add .testspassed to .gitignore' .gitignore

Finally, modify your test-run process to create (“touch”) .testspassed if all your tests pass. How you do this depends on how you run your tests.

Upvotes: 4

Related Questions