#!/bin/sh # Run a command over a sequence of commits. # Example: # git test-sequence origin/master.. 'make clean && make test' . "$(git --exec-path)/git-sh-setup" require_work_tree t= force= run_once= ref_name=pass # The tree must be really really clean. if ! git update-index --ignore-submodules --refresh > /dev/null; then echo >&2 "cannot rebase: you have unstaged changes" git diff-files --name-status -r --ignore-submodules -- >&2 exit 1 fi diff=$(git diff-index --cached --name-status -r --ignore-submodules HEAD --) case "$diff" in ?*) echo >&2 "cannot rebase: your index contains uncommitted changes" echo >&2 "$diff" exit 1 ;; esac start_branch=`git rev-parse --symbolic-full-name HEAD | sed s,refs/heads/,,` git checkout `git rev-parse HEAD` > /dev/null 2>/dev/null cleanup() { git checkout $start_branch > /dev/null 2>/dev/null } already_passed() { obdata=${ref_name}-$t-$1 obhash=`echo $obdata | git hash-object --stdin` git cat-file blob $obhash > /dev/null 2>/dev/null \ && echo "Already ${ref_name} $1" } passed_on() { obdata=${ref_name}-$t-$1 echo $obdata | git hash-object -w --stdin > /dev/null echo "Passed: $1." } broke_on() { git log --pretty="format:Broke on %H (%s)%n" -n 1 $1 cleanup exit 1 } new_test() { echo "Testing $2" git reset --hard $v && eval "$2" && passed_on $1 || broke_on $v status=$? if test -n "$run_once"; then cleanup exit $status fi } while test $# != 0 do case "$1" in --force) force=yes ;; --once) run_once=yes ;; --ref-name) ref_name=$2 shift ;; *) break; ;; esac shift done t=`echo "$2" | git hash-object --stdin` for v in `git rev-list --reverse $1` do tree_ver=`git rev-parse "$v^{tree}"` test -z "$force" && already_passed $tree_ver || new_test $tree_ver "$2" done cleanup if test -n "$run_once"; then echo "All commits already passed for --once argument. Quiting." exit 127 fi echo "All's well."