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