#!/usr/bin/env bash # Warn on a dirty work tree. git rev-parse --verify HEAD >/dev/null || exit 1 git update-index -q --ignore-submodules --refresh if ! git diff-files --quiet --ignore-submodules then echo "WARNING (dirty work tree): The patch will only be checked against actual commits." fi # Warn on a dirty index. if ! git diff-index --cached --quiet --ignore-submodules HEAD -- then echo "WARNING (dirty index): The patch will only be checked against actual commits." fi # Use a temporary index. index=$(git_extra_mktemp) cleanup() { rm "$index" exit 2 } trap cleanup INT # Go back in history while parent commits are available. echo "Trying to find a commit the patch applies to..." rev=$(git rev-parse HEAD) while [ $? = 0 ] do GIT_INDEX_FILE=$index git read-tree "$rev" # Try to apply the patch. GIT_INDEX_FILE=$index git apply --cached "$1" &>/dev/null patch_failed=$? # Do it again, but show the error, if the problem is the patch itself. if [ $patch_failed = 128 ] then GIT_INDEX_FILE=$index git apply --index --check "$1" exit $patch_failed fi # The patch applied. Commit and rebase. if [ $patch_failed = 0 ] then # Manufacture a commit. tree=$(GIT_INDEX_FILE=$index git write-tree) commit=$(git commit-tree "$tree" -p "$rev" -m "$1") rm "$index" echo "Patch applied to $(git rev-parse --short "$rev") as $(git rev-parse --short "$commit")" git cherry-pick "$commit" exit $? fi rev=$(git rev-parse --verify -q "$rev^") done # No compatible commit found. Restore. echo "Failed to find a commit the patch applies to." rm "$index" exit 1