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