1#!/bin/sh 2## 3## applypatch takes four file arguments, and uses those to 4## apply the unpacked patch (surprise surprise) that they 5## represent to the current tree. 6## 7## The arguments are: 8## $1 - file with commit message 9## $2 - file with the actual patch 10## $3 - "info" file with Author, email and subject 11## $4 - optional file containing signoff to add 12## 13 14USAGE='<msg> <patch> <info> [<signoff>]' 15. git-sh-setup 16 17case"$#"in3|4) ;; *) usage ;;esac 18 19final=.dotest/final-commit 20## 21## If this file exists, we ask before applying 22## 23query_apply=.dotest/.query_apply 24 25## We do not munge the first line of the commit message too much 26## if this file exists. 27keep_subject=.dotest/.keep_subject 28 29## We do not attempt the 3-way merge fallback unless this file exists. 30fall_back_3way=.dotest/.3way 31 32MSGFILE=$1 33PATCHFILE=$2 34INFO=$3 35SIGNOFF=$4 36EDIT=${VISUAL:-${EDITOR:-vi}} 37 38export GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$INFO")" 39export GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$INFO")" 40export GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$INFO")" 41export SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$INFO")" 42 43iftest''!="$SIGNOFF" 44then 45iftest -f"$SIGNOFF" 46then 47 SIGNOFF=`cat "$SIGNOFF"`||exit 48elif case"$SIGNOFF"inyes| true | me | please) : ;; *) false ;;esac 49then 50 SIGNOFF=`git-var GIT_COMMITTER_IDENT | sed -e ' 51 s/>.*/>/ 52 s/^/Signed-off-by: /' 53 ` 54else 55 SIGNOFF= 56fi 57iftest''!="$SIGNOFF" 58then 59 LAST_SIGNED_OFF_BY=` 60 sed -ne '/^Signed-off-by: /p' "$MSGFILE" | 61 tail -n 1 62 ` 63test"$LAST_SIGNED_OFF_BY"="$SIGNOFF"|| { 64test''="$LAST_SIGNED_OFF_BY"&&echo 65echo"$SIGNOFF" 66} >>"$MSGFILE" 67fi 68fi 69 70patch_header= 71test -f"$keep_subject"|| patch_header='[PATCH] ' 72 73{ 74echo"$patch_header$SUBJECT" 75iftest -s"$MSGFILE" 76then 77echo 78cat"$MSGFILE" 79fi 80} >"$final" 81 82interactive=yes 83test -f"$query_apply"|| interactive=no 84 85while["$interactive"=yes];do 86echo"Commit Body is:" 87echo"--------------------------" 88cat"$final" 89echo"--------------------------" 90printf"Apply? [y]es/[n]o/[e]dit/[a]ccept all " 91read reply 92case"$reply"in 93 y|Y) interactive=no;; 94 n|N)exit2;;# special value to tell dotest to keep going 95 e|E)"$EDIT""$final";; 96 a|A)rm-f"$query_apply" 97 interactive=no ;; 98esac 99done 100 101iftest -x"$GIT_DIR"/hooks/applypatch-msg 102then 103"$GIT_DIR"/hooks/applypatch-msg"$final"||exit 104fi 105 106echo 107echo Applying "'$SUBJECT'" 108echo 109 110git-apply --index"$PATCHFILE"|| { 111 112# git-apply exits with status 1 when the patch does not apply, 113# but it die()s with other failures, most notably upon corrupt 114# patch. In the latter case, there is no point to try applying 115# it to another tree and do 3-way merge. 116test $? =1||exit1 117 118test -f"$fall_back_3way"||exit1 119 120# Here if we know which revision the patch applies to, 121# we create a temporary working tree and index, apply the 122# patch, and attempt 3-way merge with the resulting tree. 123 124 O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd` 125rm-fr .patch-merge-* 126 127if git-apply -z --index-info"$PATCHFILE" \ 128>.patch-merge-index-info2>/dev/null && 129 GIT_INDEX_FILE=.patch-merge-tmp-index \ 130 git-update-index -z --index-info<.patch-merge-index-info&& 131 GIT_INDEX_FILE=.patch-merge-tmp-index \ 132 git-write-tree>.patch-merge-tmp-base&& 133( 134mkdir .patch-merge-tmp-dir&& 135cd .patch-merge-tmp-dir&& 136 GIT_INDEX_FILE="../.patch-merge-tmp-index" \ 137 GIT_OBJECT_DIRECTORY="$O_OBJECT" \ 138 git-apply$binary--index 139) <"$PATCHFILE" 140then 141echo Using index info to reconstruct a base tree... 142mv .patch-merge-tmp-base .patch-merge-base 143mv .patch-merge-tmp-index .patch-merge-index 144else 145( 146 N=10 147 148# Otherwise, try nearby trees that can be used to apply the 149# patch. 150 git-rev-list --max-count=$N HEAD 151 152# or hoping the patch is against known tags... 153 git-ls-remote --tags . 154) | 155whileread base junk 156do 157# Try it if we have it as a tree. 158 git-cat-file tree "$base">/dev/null 2>&1||continue 159 160rm-fr .patch-merge-tmp-* && 161mkdir .patch-merge-tmp-dir||break 162( 163cd .patch-merge-tmp-dir&& 164 GIT_INDEX_FILE=../.patch-merge-tmp-index&& 165 GIT_OBJECT_DIRECTORY="$O_OBJECT"&& 166export GIT_INDEX_FILE GIT_OBJECT_DIRECTORY && 167 git-read-tree"$base"&& 168 git-apply --index&& 169mv ../.patch-merge-tmp-index ../.patch-merge-index&& 170echo"$base">../.patch-merge-base 171) <"$PATCHFILE"2>/dev/null &&break 172done 173fi 174 175test -f .patch-merge-index&& 176 his_tree=$(GIT_INDEX_FILE=.patch-merge-index git-write-tree)&& 177 orig_tree=$(cat .patch-merge-base)&& 178rm-fr .patch-merge-* ||exit1 179 180echo Falling back to patching base and 3-way merge using $orig_tree... 181 182# This is not so wrong. Depending on which base we picked, 183# orig_tree may be wildly different from ours, but his_tree 184# has the same set of wildly different changes in parts the 185# patch did not touch, so resolve ends up cancelling them, 186# saying that we reverted all those changes. 187 188if git-merge-resolve$orig_tree-- HEAD $his_tree 189then 190echo Done. 191else 192echo Failed to merge in the changes. 193exit1 194fi 195} 196 197iftest -x"$GIT_DIR"/hooks/pre-applypatch 198then 199"$GIT_DIR"/hooks/pre-applypatch||exit 200fi 201 202tree=$(git-write-tree)||exit1 203echo Wrote tree $tree 204parent=$(git-rev-parse --verify HEAD)&& 205commit=$(git-commit-tree $tree -p $parent <"$final")||exit1 206echo Committed:$commit 207git-update-ref -m"applypatch:$SUBJECT" HEAD $commit $parent||exit 208 209iftest -x"$GIT_DIR"/hooks/post-applypatch 210then 211"$GIT_DIR"/hooks/post-applypatch 212fi