| #!/bin/sh | 
 | # | 
 | # Copyright (c) 2005, 2006 Junio C Hamano | 
 |  | 
 | USAGE='[--signoff] [--dotest=<dir>] [--utf8 | --no-utf8] [--binary] [--3way] | 
 |   [--interactive] [--whitespace=<option>] [-C<n>] [-p<n>] <mbox>... | 
 |   or, when resuming [--skip | --resolved]' | 
 | . git-sh-setup | 
 | set_reflog_action am | 
 | require_work_tree | 
 |  | 
 | git var GIT_COMMITTER_IDENT >/dev/null || exit | 
 |  | 
 | stop_here () { | 
 |     echo "$1" >"$dotest/next" | 
 |     exit 1 | 
 | } | 
 |  | 
 | stop_here_user_resolve () { | 
 |     if [ -n "$resolvemsg" ]; then | 
 | 	    echo "$resolvemsg" | 
 | 	    stop_here $1 | 
 |     fi | 
 |     cmdline=$(basename $0) | 
 |     if test '' != "$interactive" | 
 |     then | 
 |         cmdline="$cmdline -i" | 
 |     fi | 
 |     if test '' != "$threeway" | 
 |     then | 
 |         cmdline="$cmdline -3" | 
 |     fi | 
 |     if test '.dotest' != "$dotest" | 
 |     then | 
 |         cmdline="$cmdline -d=$dotest" | 
 |     fi | 
 |     echo "When you have resolved this problem run \"$cmdline --resolved\"." | 
 |     echo "If you would prefer to skip this patch, instead run \"$cmdline --skip\"." | 
 |  | 
 |     stop_here $1 | 
 | } | 
 |  | 
 | go_next () { | 
 | 	rm -f "$dotest/$msgnum" "$dotest/msg" "$dotest/msg-clean" \ | 
 | 		"$dotest/patch" "$dotest/info" | 
 | 	echo "$next" >"$dotest/next" | 
 | 	this=$next | 
 | } | 
 |  | 
 | cannot_fallback () { | 
 | 	echo "$1" | 
 | 	echo "Cannot fall back to three-way merge." | 
 | 	exit 1 | 
 | } | 
 |  | 
 | fall_back_3way () { | 
 |     O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd` | 
 |  | 
 |     rm -fr "$dotest"/patch-merge-* | 
 |     mkdir "$dotest/patch-merge-tmp-dir" | 
 |  | 
 |     # First see if the patch records the index info that we can use. | 
 |     git-apply -z --index-info "$dotest/patch" \ | 
 | 	>"$dotest/patch-merge-index-info" && | 
 |     GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \ | 
 |     git-update-index -z --index-info <"$dotest/patch-merge-index-info" && | 
 |     GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \ | 
 |     git-write-tree >"$dotest/patch-merge-base+" || | 
 |     cannot_fallback "Repository lacks necessary blobs to fall back on 3-way merge." | 
 |  | 
 |     echo Using index info to reconstruct a base tree... | 
 |     if GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \ | 
 | 	git-apply $binary --cached <"$dotest/patch" | 
 |     then | 
 | 	mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base" | 
 | 	mv "$dotest/patch-merge-tmp-index" "$dotest/patch-merge-index" | 
 |     else | 
 |         cannot_fallback "Did you hand edit your patch? | 
 | It does not apply to blobs recorded in its index." | 
 |     fi | 
 |  | 
 |     test -f "$dotest/patch-merge-index" && | 
 |     his_tree=$(GIT_INDEX_FILE="$dotest/patch-merge-index" git-write-tree) && | 
 |     orig_tree=$(cat "$dotest/patch-merge-base") && | 
 |     rm -fr "$dotest"/patch-merge-* || exit 1 | 
 |  | 
 |     echo Falling back to patching base and 3-way merge... | 
 |  | 
 |     # This is not so wrong.  Depending on which base we picked, | 
 |     # orig_tree may be wildly different from ours, but his_tree | 
 |     # has the same set of wildly different changes in parts the | 
 |     # patch did not touch, so recursive ends up canceling them, | 
 |     # saying that we reverted all those changes. | 
 |  | 
 |     eval GITHEAD_$his_tree='"$SUBJECT"' | 
 |     export GITHEAD_$his_tree | 
 |     git-merge-recursive $orig_tree -- HEAD $his_tree || { | 
 | 	    if test -d "$GIT_DIR/rr-cache" | 
 | 	    then | 
 | 		git-rerere | 
 | 	    fi | 
 | 	    echo Failed to merge in the changes. | 
 | 	    exit 1 | 
 |     } | 
 |     unset GITHEAD_$his_tree | 
 | } | 
 |  | 
 | prec=4 | 
 | dotest=.dotest sign= utf8=t keep= skip= interactive= resolved= binary= resolvemsg= | 
 | git_apply_opt= | 
 |  | 
 | while case "$#" in 0) break;; esac | 
 | do | 
 | 	case "$1" in | 
 | 	-d=*|--d=*|--do=*|--dot=*|--dote=*|--dotes=*|--dotest=*) | 
 | 	dotest=`expr "z$1" : 'z-[^=]*=\(.*\)'`; shift ;; | 
 | 	-d|--d|--do|--dot|--dote|--dotes|--dotest) | 
 | 	case "$#" in 1) usage ;; esac; shift | 
 | 	dotest="$1"; shift;; | 
 |  | 
 | 	-i|--i|--in|--int|--inte|--inter|--intera|--interac|--interact|\ | 
 | 	--interacti|--interactiv|--interactive) | 
 | 	interactive=t; shift ;; | 
 |  | 
 | 	-b|--b|--bi|--bin|--bina|--binar|--binary) | 
 | 	binary=t; shift ;; | 
 |  | 
 | 	-3|--3|--3w|--3wa|--3way) | 
 | 	threeway=t; shift ;; | 
 | 	-s|--s|--si|--sig|--sign|--signo|--signof|--signoff) | 
 | 	sign=t; shift ;; | 
 | 	-u|--u|--ut|--utf|--utf8) | 
 | 	utf8=t; shift ;; # this is now default | 
 | 	--no-u|--no-ut|--no-utf|--no-utf8) | 
 | 	utf8=; shift ;; | 
 | 	-k|--k|--ke|--kee|--keep) | 
 | 	keep=t; shift ;; | 
 |  | 
 | 	-r|--r|--re|--res|--reso|--resol|--resolv|--resolve|--resolved) | 
 | 	resolved=t; shift ;; | 
 |  | 
 | 	--sk|--ski|--skip) | 
 | 	skip=t; shift ;; | 
 |  | 
 | 	--whitespace=*|-C*|-p*) | 
 | 	git_apply_opt="$git_apply_opt $1"; shift ;; | 
 |  | 
 | 	--resolvemsg=*) | 
 | 	resolvemsg=$(echo "$1" | sed -e "s/^--resolvemsg=//"); shift ;; | 
 |  | 
 | 	--) | 
 | 	shift; break ;; | 
 | 	-*) | 
 | 	usage ;; | 
 | 	*) | 
 | 	break ;; | 
 | 	esac | 
 | done | 
 |  | 
 | # If the dotest directory exists, but we have finished applying all the | 
 | # patches in them, clear it out. | 
 | if test -d "$dotest" && | 
 |    last=$(cat "$dotest/last") && | 
 |    next=$(cat "$dotest/next") && | 
 |    test $# != 0 && | 
 |    test "$next" -gt "$last" | 
 | then | 
 |    rm -fr "$dotest" | 
 | fi | 
 |  | 
 | if test -d "$dotest" | 
 | then | 
 | 	case "$#,$skip$resolved" in | 
 | 	0,*t*) | 
 | 		# Explicit resume command and we do not have file, so | 
 | 		# we are happy. | 
 | 		: ;; | 
 | 	0,) | 
 | 		# No file input but without resume parameters; catch | 
 | 		# user error to feed us a patch from standard input | 
 | 		# when there is already .dotest.  This is somewhat | 
 | 		# unreliable -- stdin could be /dev/null for example | 
 | 		# and the caller did not intend to feed us a patch but | 
 | 		# wanted to continue unattended. | 
 | 		tty -s | 
 | 		;; | 
 | 	*) | 
 | 		false | 
 | 		;; | 
 | 	esac || | 
 | 	die "previous dotest directory $dotest still exists but mbox given." | 
 | 	resume=yes | 
 | else | 
 | 	# Make sure we are not given --skip nor --resolved | 
 | 	test ",$skip,$resolved," = ,,, || | 
 | 		die "Resolve operation not in progress, we are not resuming." | 
 |  | 
 | 	# Start afresh. | 
 | 	mkdir -p "$dotest" || exit | 
 |  | 
 | 	git-mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" ||  { | 
 | 		rm -fr "$dotest" | 
 | 		exit 1 | 
 | 	} | 
 |  | 
 | 	# -b, -s, -u, -k and --whitespace flags are kept for the | 
 | 	# resuming session after a patch failure. | 
 | 	# -3 and -i can and must be given when resuming. | 
 | 	echo "$binary" >"$dotest/binary" | 
 | 	echo " $ws" >"$dotest/whitespace" | 
 | 	echo "$sign" >"$dotest/sign" | 
 | 	echo "$utf8" >"$dotest/utf8" | 
 | 	echo "$keep" >"$dotest/keep" | 
 | 	echo 1 >"$dotest/next" | 
 | fi | 
 |  | 
 | case "$resolved" in | 
 | '') | 
 | 	files=$(git-diff-index --cached --name-only HEAD) || exit | 
 | 	if [ "$files" ]; then | 
 | 	   echo "Dirty index: cannot apply patches (dirty: $files)" >&2 | 
 | 	   exit 1 | 
 | 	fi | 
 | esac | 
 |  | 
 | if test "$(cat "$dotest/binary")" = t | 
 | then | 
 | 	binary=--allow-binary-replacement | 
 | fi | 
 | if test "$(cat "$dotest/utf8")" = t | 
 | then | 
 | 	utf8=-u | 
 | else | 
 | 	utf8=-n | 
 | fi | 
 | if test "$(cat "$dotest/keep")" = t | 
 | then | 
 | 	keep=-k | 
 | fi | 
 | ws=`cat "$dotest/whitespace"` | 
 | if test "$(cat "$dotest/sign")" = t | 
 | then | 
 | 	SIGNOFF=`git-var GIT_COMMITTER_IDENT | sed -e ' | 
 | 			s/>.*/>/ | 
 | 			s/^/Signed-off-by: /' | 
 | 		` | 
 | else | 
 | 	SIGNOFF= | 
 | fi | 
 |  | 
 | last=`cat "$dotest/last"` | 
 | this=`cat "$dotest/next"` | 
 | if test "$skip" = t | 
 | then | 
 | 	if test -d "$GIT_DIR/rr-cache" | 
 | 	then | 
 | 		git-rerere clear | 
 | 	fi | 
 | 	this=`expr "$this" + 1` | 
 | 	resume= | 
 | fi | 
 |  | 
 | if test "$this" -gt "$last" | 
 | then | 
 | 	echo Nothing to do. | 
 | 	rm -fr "$dotest" | 
 | 	exit | 
 | fi | 
 |  | 
 | while test "$this" -le "$last" | 
 | do | 
 | 	msgnum=`printf "%0${prec}d" $this` | 
 | 	next=`expr "$this" + 1` | 
 | 	test -f "$dotest/$msgnum" || { | 
 | 		resume= | 
 | 		go_next | 
 | 		continue | 
 | 	} | 
 |  | 
 | 	# If we are not resuming, parse and extract the patch information | 
 | 	# into separate files: | 
 | 	#  - info records the authorship and title | 
 | 	#  - msg is the rest of commit log message | 
 | 	#  - patch is the patch body. | 
 | 	# | 
 | 	# When we are resuming, these files are either already prepared | 
 | 	# by the user, or the user can tell us to do so by --resolved flag. | 
 | 	case "$resume" in | 
 | 	'') | 
 | 		git-mailinfo $keep $utf8 "$dotest/msg" "$dotest/patch" \ | 
 | 			<"$dotest/$msgnum" >"$dotest/info" || | 
 | 			stop_here $this | 
 | 		test -s $dotest/patch || { | 
 | 			echo "Patch is empty.  Was it split wrong?" | 
 | 			stop_here $this | 
 | 		} | 
 | 		git-stripspace < "$dotest/msg" > "$dotest/msg-clean" | 
 | 		;; | 
 | 	esac | 
 |  | 
 | 	GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$dotest/info")" | 
 | 	GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$dotest/info")" | 
 | 	GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$dotest/info")" | 
 |  | 
 | 	if test -z "$GIT_AUTHOR_EMAIL" | 
 | 	then | 
 | 		echo "Patch does not have a valid e-mail address." | 
 | 		stop_here $this | 
 | 	fi | 
 |  | 
 | 	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE | 
 |  | 
 | 	SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")" | 
 | 	case "$keep_subject" in -k)  SUBJECT="[PATCH] $SUBJECT" ;; esac | 
 |  | 
 | 	case "$resume" in | 
 | 	'') | 
 | 	    if test '' != "$SIGNOFF" | 
 | 	    then | 
 | 		LAST_SIGNED_OFF_BY=` | 
 | 		    sed -ne '/^Signed-off-by: /p' \ | 
 | 		    "$dotest/msg-clean" | | 
 | 		    tail -n 1 | 
 | 		` | 
 | 		ADD_SIGNOFF=` | 
 | 		    test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || { | 
 | 		    test '' = "$LAST_SIGNED_OFF_BY" && echo | 
 | 		    echo "$SIGNOFF" | 
 | 		}` | 
 | 	    else | 
 | 		ADD_SIGNOFF= | 
 | 	    fi | 
 | 	    { | 
 | 		echo "$SUBJECT" | 
 | 		if test -s "$dotest/msg-clean" | 
 | 		then | 
 | 			echo | 
 | 			cat "$dotest/msg-clean" | 
 | 		fi | 
 | 		if test '' != "$ADD_SIGNOFF" | 
 | 		then | 
 | 			echo "$ADD_SIGNOFF" | 
 | 		fi | 
 | 	    } >"$dotest/final-commit" | 
 | 	    ;; | 
 | 	*) | 
 | 		case "$resolved$interactive" in | 
 | 		tt) | 
 | 			# This is used only for interactive view option. | 
 | 			git-diff-index -p --cached HEAD >"$dotest/patch" | 
 | 			;; | 
 | 		esac | 
 | 	esac | 
 |  | 
 | 	resume= | 
 | 	if test "$interactive" = t | 
 | 	then | 
 | 	    test -t 0 || | 
 | 	    die "cannot be interactive without stdin connected to a terminal." | 
 | 	    action=again | 
 | 	    while test "$action" = again | 
 | 	    do | 
 | 		echo "Commit Body is:" | 
 | 		echo "--------------------------" | 
 | 		cat "$dotest/final-commit" | 
 | 		echo "--------------------------" | 
 | 		printf "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " | 
 | 		read reply | 
 | 		case "$reply" in | 
 | 		[yY]*) action=yes ;; | 
 | 		[aA]*) action=yes interactive= ;; | 
 | 		[nN]*) action=skip ;; | 
 | 		[eE]*) "${VISUAL:-${EDITOR:-vi}}" "$dotest/final-commit" | 
 | 		       action=again ;; | 
 | 		[vV]*) action=again | 
 | 		       LESS=-S ${PAGER:-less} "$dotest/patch" ;; | 
 | 		*)     action=again ;; | 
 | 		esac | 
 | 	    done | 
 | 	else | 
 | 	    action=yes | 
 | 	fi | 
 |  | 
 | 	if test $action = skip | 
 | 	then | 
 | 		go_next | 
 | 		continue | 
 | 	fi | 
 |  | 
 | 	if test -x "$GIT_DIR"/hooks/applypatch-msg | 
 | 	then | 
 | 		"$GIT_DIR"/hooks/applypatch-msg "$dotest/final-commit" || | 
 | 		stop_here $this | 
 | 	fi | 
 |  | 
 | 	echo | 
 | 	echo "Applying '$SUBJECT'" | 
 | 	echo | 
 |  | 
 | 	case "$resolved" in | 
 | 	'') | 
 | 		git-apply $git_apply_opt $binary --index "$dotest/patch" | 
 | 		apply_status=$? | 
 | 		;; | 
 | 	t) | 
 | 		# Resolved means the user did all the hard work, and | 
 | 		# we do not have to do any patch application.  Just | 
 | 		# trust what the user has in the index file and the | 
 | 		# working tree. | 
 | 		resolved= | 
 | 		git-diff-index --quiet --cached HEAD && { | 
 | 			echo "No changes - did you forget to use 'git add'?" | 
 | 			stop_here_user_resolve $this | 
 | 		} | 
 | 		unmerged=$(git-ls-files -u) | 
 | 		if test -n "$unmerged" | 
 | 		then | 
 | 			echo "You still have unmerged paths in your index" | 
 | 			echo "did you forget to use 'git add'?" | 
 | 			stop_here_user_resolve $this | 
 | 		fi | 
 | 		apply_status=0 | 
 | 		if test -d "$GIT_DIR/rr-cache" | 
 | 		then | 
 | 			git rerere | 
 | 		fi | 
 | 		;; | 
 | 	esac | 
 |  | 
 | 	if test $apply_status = 1 && test "$threeway" = t | 
 | 	then | 
 | 		if (fall_back_3way) | 
 | 		then | 
 | 		    # Applying the patch to an earlier tree and merging the | 
 | 		    # result may have produced the same tree as ours. | 
 | 		    git-diff-index --quiet --cached HEAD && { | 
 | 			echo No changes -- Patch already applied. | 
 | 			go_next | 
 | 			continue | 
 | 		    } | 
 | 		    # clear apply_status -- we have successfully merged. | 
 | 		    apply_status=0 | 
 | 		fi | 
 | 	fi | 
 | 	if test $apply_status != 0 | 
 | 	then | 
 | 		echo Patch failed at $msgnum. | 
 | 		stop_here_user_resolve $this | 
 | 	fi | 
 |  | 
 | 	if test -x "$GIT_DIR"/hooks/pre-applypatch | 
 | 	then | 
 | 		"$GIT_DIR"/hooks/pre-applypatch || stop_here $this | 
 | 	fi | 
 |  | 
 | 	tree=$(git-write-tree) && | 
 | 	echo Wrote tree $tree && | 
 | 	parent=$(git-rev-parse --verify HEAD) && | 
 | 	commit=$(git-commit-tree $tree -p $parent <"$dotest/final-commit") && | 
 | 	echo Committed: $commit && | 
 | 	git-update-ref -m "$GIT_REFLOG_ACTION: $SUBJECT" HEAD $commit $parent || | 
 | 	stop_here $this | 
 |  | 
 | 	if test -x "$GIT_DIR"/hooks/post-applypatch | 
 | 	then | 
 | 		"$GIT_DIR"/hooks/post-applypatch | 
 | 	fi | 
 |  | 
 | 	go_next | 
 | done | 
 |  | 
 | rm -fr "$dotest" |