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