1#!/bin/sh 2# 3# Copyright (c) 2005, 2006 Junio C Hamano 4 5SUBDIRECTORY_OK=Yes 6OPTIONS_KEEPDASHDASH= 7OPTIONS_SPEC="\ 8git-am [options] <mbox>|<Maildir>... 9git-am [options] --resolved 10git-am [options] --skip 11-- 12d,dotest= use <dir> and not .dotest 13i,interactive run interactively 14b,binary pass --allo-binary-replacement to git-apply 153,3way allow fall back on 3way merging if needed 16s,signoff add a Signed-off-by line to the commit message 17u,utf8 recode into utf8 (default) 18k,keep pass -k flag to git-mailinfo 19whitespace= pass it through git-apply 20C= pass it through git-apply 21p= pass it through git-apply 22resolvemsg= override error message when patch failure occurs 23r,resolved to be used after a patch failure 24skip skip the current patch" 25 26. git-sh-setup 27set_reflog_action am 28require_work_tree 29cd_to_toplevel 30 31git var GIT_COMMITTER_IDENT >/dev/null ||exit 32 33stop_here () { 34echo"$1">"$dotest/next" 35exit1 36} 37 38stop_here_user_resolve () { 39if[-n"$resolvemsg"];then 40printf'%s\n'"$resolvemsg" 41 stop_here $1 42fi 43 cmdline=$(basename $0) 44iftest''!="$interactive" 45then 46 cmdline="$cmdline-i" 47fi 48iftest''!="$threeway" 49then 50 cmdline="$cmdline-3" 51fi 52iftest'.dotest'!="$dotest" 53then 54 cmdline="$cmdline-d=$dotest" 55fi 56echo"When you have resolved this problem run\"$cmdline--resolved\"." 57echo"If you would prefer to skip this patch, instead run\"$cmdline--skip\"." 58 59 stop_here $1 60} 61 62go_next () { 63rm-f"$dotest/$msgnum""$dotest/msg""$dotest/msg-clean" \ 64"$dotest/patch""$dotest/info" 65echo"$next">"$dotest/next" 66 this=$next 67} 68 69cannot_fallback () { 70echo"$1" 71echo"Cannot fall back to three-way merge." 72exit1 73} 74 75fall_back_3way () { 76 O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd` 77 78rm-fr"$dotest"/patch-merge-* 79mkdir"$dotest/patch-merge-tmp-dir" 80 81# First see if the patch records the index info that we can use. 82 git apply --build-fake-ancestor"$dotest/patch-merge-tmp-index" \ 83"$dotest/patch"&& 84 GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \ 85 git write-tree>"$dotest/patch-merge-base+"|| 86 cannot_fallback "Repository lacks necessary blobs to fall back on 3-way merge." 87 88echo Using index info to reconstruct a base tree... 89if GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \ 90 git apply $binary--cached<"$dotest/patch" 91then 92mv"$dotest/patch-merge-base+""$dotest/patch-merge-base" 93mv"$dotest/patch-merge-tmp-index""$dotest/patch-merge-index" 94else 95 cannot_fallback "Did you hand edit your patch? 96It does not apply to blobs recorded in its index." 97fi 98 99test -f"$dotest/patch-merge-index"&& 100 his_tree=$(GIT_INDEX_FILE="$dotest/patch-merge-index" git write-tree)&& 101 orig_tree=$(cat "$dotest/patch-merge-base")&& 102rm-fr"$dotest"/patch-merge-* ||exit1 103 104echo Falling back to patching base and 3-way merge... 105 106# This is not so wrong. Depending on which base we picked, 107# orig_tree may be wildly different from ours, but his_tree 108# has the same set of wildly different changes in parts the 109# patch did not touch, so recursive ends up canceling them, 110# saying that we reverted all those changes. 111 112eval GITHEAD_$his_tree='"$SUBJECT"' 113export GITHEAD_$his_tree 114 git-merge-recursive$orig_tree-- HEAD $his_tree|| { 115 git rerere 116echo Failed to merge in the changes. 117exit1 118} 119unset GITHEAD_$his_tree 120} 121 122reread_subject () { 123 git stripspace <"$1"|sed-e1q 124} 125 126prec=4 127dotest=.dotest sign= utf8=t keep= skip= interactive= resolved= binary= 128resolvemsg= resume= 129git_apply_opt= 130 131whiletest$#!=0 132do 133case"$1"in 134-i|--interactive) 135 interactive=t ;; 136-b|--binary) 137 binary=t ;; 138-3|--3way) 139 threeway=t ;; 140-s|--signoff) 141 sign=t ;; 142-u|--utf8) 143 utf8=t ;;# this is now default 144--no-utf8) 145 utf8= ;; 146-k|--keep) 147 keep=t ;; 148-r|--resolved) 149 resolved=t ;; 150--skip) 151 skip=t ;; 152-d|--dotest) 153shift; dotest=$1;; 154--resolvemsg) 155shift; resolvemsg=$1;; 156--whitespace) 157 git_apply_opt="$git_apply_opt$1=$2";shift;; 158-C|-p) 159 git_apply_opt="$git_apply_opt$1$2";shift;; 160--) 161shift;break;; 162*) 163 usage ;; 164esac 165shift 166done 167 168# If the dotest directory exists, but we have finished applying all the 169# patches in them, clear it out. 170iftest -d"$dotest"&& 171 last=$(cat "$dotest/last")&& 172 next=$(cat "$dotest/next")&& 173test$#!=0&& 174test"$next"-gt"$last" 175then 176rm-fr"$dotest" 177fi 178 179iftest -d"$dotest" 180then 181case"$#,$skip$resolved"in 1820,*t*) 183# Explicit resume command and we do not have file, so 184# we are happy. 185: ;; 1860,) 187# No file input but without resume parameters; catch 188# user error to feed us a patch from standard input 189# when there is already .dotest. This is somewhat 190# unreliable -- stdin could be /dev/null for example 191# and the caller did not intend to feed us a patch but 192# wanted to continue unattended. 193 tty -s 194;; 195*) 196 false 197;; 198esac|| 199 die "previous dotest directory$doteststill exists but mbox given." 200 resume=yes 201else 202# Make sure we are not given --skip nor --resolved 203test",$skip,$resolved,"= ,,, || 204 die "Resolve operation not in progress, we are not resuming." 205 206# Start afresh. 207mkdir-p"$dotest"||exit 208 209 git mailsplit -d"$prec"-o"$dotest"-b --"$@">"$dotest/last"|| { 210rm-fr"$dotest" 211exit1 212} 213 214# -b, -s, -u, -k and --whitespace flags are kept for the 215# resuming session after a patch failure. 216# -3 and -i can and must be given when resuming. 217echo"$binary">"$dotest/binary" 218echo"$ws">"$dotest/whitespace" 219echo"$sign">"$dotest/sign" 220echo"$utf8">"$dotest/utf8" 221echo"$keep">"$dotest/keep" 222echo1>"$dotest/next" 223fi 224 225case"$resolved"in 226'') 227 files=$(git diff-index --cached --name-only HEAD --)||exit 228if["$files"];then 229echo"Dirty index: cannot apply patches (dirty:$files)">&2 230exit1 231fi 232esac 233 234iftest"$(cat "$dotest/binary")"= t 235then 236 binary=--allow-binary-replacement 237fi 238iftest"$(cat "$dotest/utf8")"= t 239then 240 utf8=-u 241else 242 utf8=-n 243fi 244iftest"$(cat "$dotest/keep")"= t 245then 246 keep=-k 247fi 248ws=`cat "$dotest/whitespace"` 249iftest"$(cat "$dotest/sign")"= t 250then 251 SIGNOFF=`git-var GIT_COMMITTER_IDENT | sed -e ' 252 s/>.*/>/ 253 s/^/Signed-off-by: /' 254 ` 255else 256 SIGNOFF= 257fi 258 259last=`cat "$dotest/last"` 260this=`cat "$dotest/next"` 261iftest"$skip"= t 262then 263 git rerere clear 264 this=`expr "$this" + 1` 265 resume= 266fi 267 268iftest"$this"-gt"$last" 269then 270echo Nothing to do. 271rm-fr"$dotest" 272exit 273fi 274 275whiletest"$this"-le"$last" 276do 277 msgnum=`printf "%0${prec}d"$this` 278 next=`expr "$this" + 1` 279test -f"$dotest/$msgnum"|| { 280 resume= 281 go_next 282continue 283} 284 285# If we are not resuming, parse and extract the patch information 286# into separate files: 287# - info records the authorship and title 288# - msg is the rest of commit log message 289# - patch is the patch body. 290# 291# When we are resuming, these files are either already prepared 292# by the user, or the user can tell us to do so by --resolved flag. 293case"$resume"in 294'') 295 git mailinfo $keep $utf8"$dotest/msg""$dotest/patch" \ 296<"$dotest/$msgnum">"$dotest/info"|| 297 stop_here $this 298 299# skip pine's internal folder data 300grep'^Author: Mail System Internal Data$' \ 301<"$dotest"/info >/dev/null && 302 go_next &&continue 303 304test -s$dotest/patch|| { 305echo"Patch is empty. Was it split wrong?" 306 stop_here $this 307} 308 git stripspace <"$dotest/msg">"$dotest/msg-clean" 309;; 310esac 311 312 GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$dotest/info")" 313 GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$dotest/info")" 314 GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$dotest/info")" 315 316iftest -z"$GIT_AUTHOR_EMAIL" 317then 318echo"Patch does not have a valid e-mail address." 319 stop_here $this 320fi 321 322export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE 323 324 SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")" 325case"$keep_subject"in-k) SUBJECT="[PATCH]$SUBJECT";;esac 326 327case"$resume"in 328'') 329iftest''!="$SIGNOFF" 330then 331 LAST_SIGNED_OFF_BY=` 332 sed -ne '/^Signed-off-by: /p' \ 333 "$dotest/msg-clean" | 334 tail -n 1 335 ` 336 ADD_SIGNOFF=` 337 test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || { 338 test '' = "$LAST_SIGNED_OFF_BY" && echo 339 echo "$SIGNOFF" 340 }` 341else 342 ADD_SIGNOFF= 343fi 344{ 345printf'%s\n'"$SUBJECT" 346iftest -s"$dotest/msg-clean" 347then 348echo 349cat"$dotest/msg-clean" 350fi 351iftest''!="$ADD_SIGNOFF" 352then 353echo"$ADD_SIGNOFF" 354fi 355} >"$dotest/final-commit" 356;; 357*) 358case"$resolved$interactive"in 359 tt) 360# This is used only for interactive view option. 361 git diff-index -p --cached HEAD -->"$dotest/patch" 362;; 363esac 364esac 365 366 resume= 367iftest"$interactive"= t 368then 369test -t0|| 370 die "cannot be interactive without stdin connected to a terminal." 371 action=again 372whiletest"$action"= again 373do 374echo"Commit Body is:" 375echo"--------------------------" 376cat"$dotest/final-commit" 377echo"--------------------------" 378printf"Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " 379read reply 380case"$reply"in 381[yY]*) action=yes;; 382[aA]*) action=yes interactive= ;; 383[nN]*) action=skip ;; 384[eE]*) git_editor "$dotest/final-commit" 385 SUBJECT=$(reread_subject "$dotest/final-commit") 386 action=again ;; 387[vV]*) action=again 388 LESS=-S${PAGER:-less}"$dotest/patch";; 389*) action=again ;; 390esac 391done 392else 393 action=yes 394fi 395 396iftest$action= skip 397then 398 go_next 399continue 400fi 401 402iftest -x"$GIT_DIR"/hooks/applypatch-msg 403then 404"$GIT_DIR"/hooks/applypatch-msg"$dotest/final-commit"|| 405 stop_here $this 406fi 407 408printf'Applying %s\n'"$SUBJECT" 409 410case"$resolved"in 411'') 412 git apply $git_apply_opt $binary--index"$dotest/patch" 413 apply_status=$? 414;; 415 t) 416# Resolved means the user did all the hard work, and 417# we do not have to do any patch application. Just 418# trust what the user has in the index file and the 419# working tree. 420 resolved= 421 git diff-index --quiet --cached HEAD --&& { 422echo"No changes - did you forget to use 'git add'?" 423 stop_here_user_resolve $this 424} 425 unmerged=$(git ls-files -u) 426iftest -n"$unmerged" 427then 428echo"You still have unmerged paths in your index" 429echo"did you forget to use 'git add'?" 430 stop_here_user_resolve $this 431fi 432 apply_status=0 433 git rerere 434;; 435esac 436 437iftest$apply_status=1&&test"$threeway"= t 438then 439if(fall_back_3way) 440then 441# Applying the patch to an earlier tree and merging the 442# result may have produced the same tree as ours. 443 git diff-index --quiet --cached HEAD --&& { 444echo No changes -- Patch already applied. 445 go_next 446continue 447} 448# clear apply_status -- we have successfully merged. 449 apply_status=0 450fi 451fi 452iftest$apply_status!=0 453then 454echo Patch failed at$msgnum. 455 stop_here_user_resolve $this 456fi 457 458iftest -x"$GIT_DIR"/hooks/pre-applypatch 459then 460"$GIT_DIR"/hooks/pre-applypatch|| stop_here $this 461fi 462 463 tree=$(git write-tree)&& 464 parent=$(git rev-parse --verify HEAD)&& 465 commit=$(git commit-tree $tree -p $parent <"$dotest/final-commit")&& 466 git update-ref -m"$GIT_REFLOG_ACTION:$SUBJECT" HEAD $commit $parent|| 467 stop_here $this 468 469iftest -x"$GIT_DIR"/hooks/post-applypatch 470then 471"$GIT_DIR"/hooks/post-applypatch 472fi 473 474 go_next 475done 476 477git gc --auto 478 479rm-fr"$dotest"