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|| die "Not a git archive." 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 123( 124 N=10 125 126# if the patch records the base tree... 127sed-ne' 128 /^diff /q 129 /^applies-to: \([0-9a-f]*\)$/{ 130 s//\1/p 131 q 132 } 133 '"$PATCHFILE" 134 135# or hoping the patch is against our recent commits... 136 git-rev-list --max-count=$N HEAD 137 138# or hoping the patch is against known tags... 139 git-ls-remote --tags . 140) | 141whileread base junk 142do 143# Try it if we have it as a tree. 144 git-cat-file tree "$base">/dev/null 2>&1||continue 145 146rm-fr .patch-merge-tmp-* && 147mkdir .patch-merge-tmp-dir||break 148( 149cd .patch-merge-tmp-dir&& 150 GIT_INDEX_FILE=../.patch-merge-tmp-index&& 151 GIT_OBJECT_DIRECTORY="$O_OBJECT"&& 152export GIT_INDEX_FILE GIT_OBJECT_DIRECTORY && 153 git-read-tree"$base"&& 154 git-apply --index&& 155mv ../.patch-merge-tmp-index ../.patch-merge-index&& 156echo"$base">../.patch-merge-base 157) <"$PATCHFILE"2>/dev/null &&break 158done 159 160test -f .patch-merge-index&& 161 his_tree=$(GIT_INDEX_FILE=.patch-merge-index git-write-tree)&& 162 orig_tree=$(cat .patch-merge-base)&& 163rm-fr .patch-merge-* ||exit1 164 165echo Falling back to patching base and 3-way merge using $orig_tree... 166 167# This is not so wrong. Depending on which base we picked, 168# orig_tree may be wildly different from ours, but his_tree 169# has the same set of wildly different changes in parts the 170# patch did not touch, so resolve ends up cancelling them, 171# saying that we reverted all those changes. 172 173if git-merge-resolve$orig_tree-- HEAD $his_tree 174then 175echo Done. 176else 177echo Failed to merge in the changes. 178exit1 179fi 180} 181 182iftest -x"$GIT_DIR"/hooks/pre-applypatch 183then 184"$GIT_DIR"/hooks/pre-applypatch||exit 185fi 186 187tree=$(git-write-tree)||exit1 188echo Wrote tree $tree 189parent=$(git-rev-parse --verify HEAD)&& 190commit=$(git-commit-tree $tree -p $parent <"$final")||exit1 191echo Committed:$commit 192git-update-ref HEAD $commit $parent||exit 193 194iftest -x"$GIT_DIR"/hooks/post-applypatch 195then 196"$GIT_DIR"/hooks/post-applypatch 197fi