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-- 11i,interactive run interactively 12b,binary* (historical option -- no-op) 133,3way allow fall back on 3way merging if needed 14q,quiet be quiet 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 18c,scissors strip everything before a scissors line 19whitespace= pass it through git-apply 20ignore-space-change pass it through git-apply 21ignore-whitespace pass it through git-apply 22directory= pass it through git-apply 23C= pass it through git-apply 24p= pass it through git-apply 25patch-format= format the patch(es) are in 26reject pass it through git-apply 27resolvemsg= override error message when patch failure occurs 28r,resolved to be used after a patch failure 29skip skip the current patch 30abort restore the original branch and abort the patching operation. 31committer-date-is-author-date lie about committer date 32ignore-date use current timestamp for author date 33rerere-autoupdate update the index with reused conflict resolution if possible 34rebasing* (internal use for git-rebase)" 35 36. git-sh-setup 37prefix=$(git rev-parse --show-prefix) 38set_reflog_action am 39require_work_tree 40cd_to_toplevel 41 42git var GIT_COMMITTER_IDENT >/dev/null || 43 die "You need to set your committer info first" 44 45if git rev-parse --verify -q HEAD >/dev/null 46then 47 HAS_HEAD=yes 48else 49 HAS_HEAD= 50fi 51 52sq() { 53 git rev-parse --sq-quote"$@" 54} 55 56stop_here () { 57echo"$1">"$dotest/next" 58exit1 59} 60 61stop_here_user_resolve () { 62if[-n"$resolvemsg"];then 63printf'%s\n'"$resolvemsg" 64 stop_here $1 65fi 66 cmdline="git am" 67iftest''!="$interactive" 68then 69 cmdline="$cmdline-i" 70fi 71iftest''!="$threeway" 72then 73 cmdline="$cmdline-3" 74fi 75echo"When you have resolved this problem run\"$cmdline--resolved\"." 76echo"If you would prefer to skip this patch, instead run\"$cmdline--skip\"." 77echo"To restore the original branch and stop patching run\"$cmdline--abort\"." 78 79 stop_here $1 80} 81 82go_next () { 83rm-f"$dotest/$msgnum""$dotest/msg""$dotest/msg-clean" \ 84"$dotest/patch""$dotest/info" 85echo"$next">"$dotest/next" 86 this=$next 87} 88 89cannot_fallback () { 90echo"$1" 91echo"Cannot fall back to three-way merge." 92exit1 93} 94 95fall_back_3way () { 96 O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd` 97 98rm-fr"$dotest"/patch-merge-* 99mkdir"$dotest/patch-merge-tmp-dir" 100 101# First see if the patch records the index info that we can use. 102 git apply --build-fake-ancestor"$dotest/patch-merge-tmp-index" \ 103"$dotest/patch"&& 104 GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \ 105 git write-tree>"$dotest/patch-merge-base+"|| 106 cannot_fallback "Repository lacks necessary blobs to fall back on 3-way merge." 107 108 say Using index info to reconstruct a base tree... 109if GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \ 110 git apply --cached<"$dotest/patch" 111then 112mv"$dotest/patch-merge-base+""$dotest/patch-merge-base" 113mv"$dotest/patch-merge-tmp-index""$dotest/patch-merge-index" 114else 115 cannot_fallback "Did you hand edit your patch? 116It does not apply to blobs recorded in its index." 117fi 118 119test -f"$dotest/patch-merge-index"&& 120 his_tree=$(GIT_INDEX_FILE="$dotest/patch-merge-index" git write-tree)&& 121 orig_tree=$(cat "$dotest/patch-merge-base")&& 122rm-fr"$dotest"/patch-merge-* ||exit1 123 124 say Falling back to patching base and 3-way merge... 125 126# This is not so wrong. Depending on which base we picked, 127# orig_tree may be wildly different from ours, but his_tree 128# has the same set of wildly different changes in parts the 129# patch did not touch, so recursive ends up canceling them, 130# saying that we reverted all those changes. 131 132eval GITHEAD_$his_tree='"$FIRSTLINE"' 133export GITHEAD_$his_tree 134iftest -n"$GIT_QUIET" 135then 136export GIT_MERGE_VERBOSITY=0 137fi 138 git-merge-recursive$orig_tree-- HEAD $his_tree|| { 139 git rerere $allow_rerere_autoupdate 140echo Failed to merge in the changes. 141exit1 142} 143unset GITHEAD_$his_tree 144} 145 146clean_abort () { 147test$#=0||echo>&2"$@" 148rm-fr"$dotest" 149exit1 150} 151 152patch_format= 153 154check_patch_format () { 155# early return if patch_format was set from the command line 156iftest -n"$patch_format" 157then 158return0 159fi 160 161# we default to mbox format if input is from stdin and for 162# directories 163iftest$#=0||test"x$1"="x-"||test -d"$1" 164then 165 patch_format=mbox 166return0 167fi 168 169# otherwise, check the first few lines of the first patch to try 170# to detect its format 171{ 172read l1 173read l2 174read l3 175case"$l1"in 176"From "* |"From: "*) 177 patch_format=mbox 178;; 179'# This series applies on GIT commit'*) 180 patch_format=stgit-series 181;; 182"# HG changeset patch") 183 patch_format=hg 184;; 185*) 186# if the second line is empty and the third is 187# a From, Author or Date entry, this is very 188# likely an StGIT patch 189case"$l2,$l3"in 190,"From: "* | ,"Author: "* | ,"Date: "*) 191 patch_format=stgit 192;; 193*) 194;; 195esac 196;; 197esac 198iftest -z"$patch_format"&& 199test -n"$l1"&& 200test -n"$l2"&& 201test -n"$l3" 202then 203# This begins with three non-empty lines. Is this a 204# piece of e-mail a-la RFC2822? Grab all the headers, 205# discarding the indented remainder of folded lines, 206# and see if it looks like that they all begin with the 207# header field names... 208tr-d'\015'<"$1"| 209sed-n -e'/^$/q'-e'/^[ ]/d'-e p | 210 sane_egrep -v'^[!-9;-~]+:'>/dev/null || 211 patch_format=mbox 212fi 213} <"$1"|| clean_abort 214} 215 216split_patches () { 217case"$patch_format"in 218 mbox) 219case"$rebasing"in 220'') 221 keep_cr= ;; 222 ?*) 223 keep_cr=--keep-cr;; 224esac 225 git mailsplit -d"$prec"-o"$dotest"-b$keep_cr--"$@">"$dotest/last"|| 226 clean_abort 227;; 228 stgit-series) 229iftest$#-ne1 230then 231 clean_abort "Only one StGIT patch series can be applied at once" 232fi 233 series_dir=`dirname "$1"` 234 series_file="$1" 235shift 236{ 237set x 238whileread filename 239do 240set"$@""$series_dir/$filename" 241done 242# remove the safety x 243shift 244# remove the arg coming from the first-line comment 245shift 246} <"$series_file"|| clean_abort 247# set the patch format appropriately 248 patch_format=stgit 249# now handle the actual StGIT patches 250 split_patches "$@" 251;; 252 stgit) 253 this=0 254for stgit in"$@" 255do 256 this=`expr "$this" + 1` 257 msgnum=`printf "%0${prec}d"$this` 258# Perl version of StGIT parse_patch. The first nonemptyline 259# not starting with Author, From or Date is the 260# subject, and the body starts with the next nonempty 261# line not starting with Author, From or Date 262 perl -ne'BEGIN {$subject= 0 } 263 if ($subject> 1) { print ; } 264 elsif (/^\s+$/) { next ; } 265 elsif (/^Author:/) { print s/Author/From/ ; } 266 elsif (/^(From|Date)/) { print ; } 267 elsif ($subject) { 268$subject= 2 ; 269 print "\n" ; 270 print ; 271 } else { 272 print "Subject: ",$_; 273$subject= 1; 274 } 275 '<"$stgit">"$dotest/$msgnum"|| clean_abort 276done 277echo"$this">"$dotest/last" 278 this= 279 msgnum= 280;; 281*) 282iftest -n"$parse_patch";then 283 clean_abort "Patch format$patch_formatis not supported." 284else 285 clean_abort "Patch format detection failed." 286fi 287;; 288esac 289} 290 291prec=4 292dotest="$GIT_DIR/rebase-apply" 293sign= utf8=t keep= skip= interactive= resolved= rebasing= abort= 294resolvemsg= resume= scissors= no_inbody_headers= 295git_apply_opt= 296committer_date_is_author_date= 297ignore_date= 298allow_rerere_autoupdate= 299 300whiletest$#!=0 301do 302case"$1"in 303-i|--interactive) 304 interactive=t ;; 305-b|--binary) 306: ;; 307-3|--3way) 308 threeway=t ;; 309-s|--signoff) 310 sign=t ;; 311-u|--utf8) 312 utf8=t ;;# this is now default 313--no-utf8) 314 utf8= ;; 315-k|--keep) 316 keep=t ;; 317-c|--scissors) 318 scissors=t ;; 319--no-scissors) 320 scissors=f ;; 321-r|--resolved) 322 resolved=t ;; 323--skip) 324 skip=t ;; 325--abort) 326 abort=t ;; 327--rebasing) 328 rebasing=t threeway=t keep=t scissors=f no_inbody_headers=t ;; 329-d|--dotest) 330 die "-d option is no longer supported. Do not use." 331;; 332--resolvemsg) 333shift; resolvemsg=$1;; 334--whitespace|--directory) 335 git_apply_opt="$git_apply_opt$(sq "$1=$2")";shift;; 336-C|-p) 337 git_apply_opt="$git_apply_opt$(sq "$1$2")";shift;; 338--patch-format) 339shift; patch_format="$1";; 340--reject|--ignore-whitespace|--ignore-space-change) 341 git_apply_opt="$git_apply_opt$1";; 342--committer-date-is-author-date) 343 committer_date_is_author_date=t ;; 344--ignore-date) 345 ignore_date=t ;; 346--rerere-autoupdate|--no-rerere-autoupdate) 347 allow_rerere_autoupdate="$1";; 348-q|--quiet) 349 GIT_QUIET=t ;; 350--) 351shift;break;; 352*) 353 usage ;; 354esac 355shift 356done 357 358# If the dotest directory exists, but we have finished applying all the 359# patches in them, clear it out. 360iftest -d"$dotest"&& 361 last=$(cat "$dotest/last")&& 362 next=$(cat "$dotest/next")&& 363test$#!=0&& 364test"$next"-gt"$last" 365then 366rm-fr"$dotest" 367fi 368 369iftest -d"$dotest" 370then 371case"$#,$skip$resolved$abort"in 3720,*t*) 373# Explicit resume command and we do not have file, so 374# we are happy. 375: ;; 3760,) 377# No file input but without resume parameters; catch 378# user error to feed us a patch from standard input 379# when there is already $dotest. This is somewhat 380# unreliable -- stdin could be /dev/null for example 381# and the caller did not intend to feed us a patch but 382# wanted to continue unattended. 383test -t0 384;; 385*) 386 false 387;; 388esac|| 389 die "previous rebase directory$doteststill exists but mbox given." 390 resume=yes 391 392case"$skip,$abort"in 393 t,t) 394 die "Please make up your mind. --skip or --abort?" 395;; 396 t,) 397 git rerere clear 398 git read-tree --reset -u HEAD HEAD 399 orig_head=$(cat "$GIT_DIR/ORIG_HEAD") 400 git reset HEAD 401 git update-ref ORIG_HEAD $orig_head 402;; 403,t) 404iftest -f"$dotest/rebasing" 405then 406exec git rebase --abort 407fi 408 git rerere clear 409test -f"$dotest/dirtyindex"|| { 410 git read-tree --reset -u HEAD ORIG_HEAD 411 git reset ORIG_HEAD 412} 413rm-fr"$dotest" 414exit;; 415esac 416rm-f"$dotest/dirtyindex" 417else 418# Make sure we are not given --skip, --resolved, nor --abort 419test"$skip$resolved$abort"=""|| 420 die "Resolve operation not in progress, we are not resuming." 421 422# Start afresh. 423mkdir-p"$dotest"||exit 424 425iftest -n"$prefix"&&test$#!=0 426then 427 first=t 428for arg 429do 430test -n"$first"&& { 431set x 432 first= 433} 434case"$arg"in 435/*) 436set"$@""$arg";; 437*) 438set"$@""$prefix$arg";; 439esac 440done 441shift 442fi 443 444 check_patch_format "$@" 445 446 split_patches "$@" 447 448# -i can and must be given when resuming; everything 449# else is kept 450echo"$git_apply_opt">"$dotest/apply-opt" 451echo"$threeway">"$dotest/threeway" 452echo"$sign">"$dotest/sign" 453echo"$utf8">"$dotest/utf8" 454echo"$keep">"$dotest/keep" 455echo"$scissors">"$dotest/scissors" 456echo"$no_inbody_headers">"$dotest/no_inbody_headers" 457echo"$GIT_QUIET">"$dotest/quiet" 458echo1>"$dotest/next" 459iftest -n"$rebasing" 460then 461: >"$dotest/rebasing" 462else 463: >"$dotest/applying" 464iftest -n"$HAS_HEAD" 465then 466 git update-ref ORIG_HEAD HEAD 467else 468 git update-ref -d ORIG_HEAD >/dev/null 2>&1 469fi 470fi 471fi 472 473case"$resolved"in 474'') 475case"$HAS_HEAD"in 476'') 477 files=$(git ls-files);; 478 ?*) 479 files=$(git diff-index --cached --name-only HEAD --);; 480esac||exit 481iftest"$files" 482then 483test -n"$HAS_HEAD"&& : >"$dotest/dirtyindex" 484 die "Dirty index: cannot apply patches (dirty:$files)" 485fi 486esac 487 488iftest"$(cat "$dotest/utf8")"= t 489then 490 utf8=-u 491else 492 utf8=-n 493fi 494iftest"$(cat "$dotest/keep")"= t 495then 496 keep=-k 497fi 498case"$(cat "$dotest/scissors")"in 499t) 500 scissors=--scissors;; 501f) 502 scissors=--no-scissors;; 503esac 504iftest"$(cat "$dotest/no_inbody_headers")"= t 505then 506 no_inbody_headers=--no-inbody-headers 507else 508 no_inbody_headers= 509fi 510iftest"$(cat "$dotest/quiet")"= t 511then 512 GIT_QUIET=t 513fi 514iftest"$(cat "$dotest/threeway")"= t 515then 516 threeway=t 517fi 518git_apply_opt=$(cat "$dotest/apply-opt") 519iftest"$(cat "$dotest/sign")"= t 520then 521 SIGNOFF=`git var GIT_COMMITTER_IDENT | sed -e ' 522 s/>.*/>/ 523 s/^/Signed-off-by: /' 524 ` 525else 526 SIGNOFF= 527fi 528 529last=`cat "$dotest/last"` 530this=`cat "$dotest/next"` 531iftest"$skip"= t 532then 533 this=`expr "$this" + 1` 534 resume= 535fi 536 537iftest"$this"-gt"$last" 538then 539 say Nothing to do. 540rm-fr"$dotest" 541exit 542fi 543 544whiletest"$this"-le"$last" 545do 546 msgnum=`printf "%0${prec}d"$this` 547 next=`expr "$this" + 1` 548test -f"$dotest/$msgnum"|| { 549 resume= 550 go_next 551continue 552} 553 554# If we are not resuming, parse and extract the patch information 555# into separate files: 556# - info records the authorship and title 557# - msg is the rest of commit log message 558# - patch is the patch body. 559# 560# When we are resuming, these files are either already prepared 561# by the user, or the user can tell us to do so by --resolved flag. 562case"$resume"in 563'') 564 git mailinfo $keep $no_inbody_headers $scissors $utf8"$dotest/msg""$dotest/patch" \ 565<"$dotest/$msgnum">"$dotest/info"|| 566 stop_here $this 567 568# skip pine's internal folder data 569 sane_grep '^Author: Mail System Internal Data$' \ 570<"$dotest"/info >/dev/null && 571 go_next &&continue 572 573test -s"$dotest/patch"|| { 574echo"Patch is empty. Was it split wrong?" 575 stop_here $this 576} 577iftest -f"$dotest/rebasing"&& 578 commit=$(sed -e 's/^From \([0-9a-f]*\) .*/\1/' \ 579 -e q "$dotest/$msgnum") && 580 test "$(git cat-file -t "$commit")" = commit 581 then 582 git cat-file commit "$commit" | 583 sed -e '1,/^$/d' >"$dotest/msg-clean" 584 else 585 { 586 sed -n '/^Subject/ s/Subject: //p' "$dotest/info" 587 echo 588 cat "$dotest/msg" 589 } | 590 git stripspace > "$dotest/msg-clean" 591 fi 592 ;; 593 esac 594 595 GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$dotest/info")" 596 GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$dotest/info")" 597 GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$dotest/info")" 598 599 if test -z "$GIT_AUTHOR_EMAIL" 600 then 601 echo "Patch does not have a valid e-mail address." 602 stop_here$this 603 fi 604 605 export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE 606 607 case "$resume" in 608 '') 609 if test '' != "$SIGNOFF" 610 then 611 LAST_SIGNED_OFF_BY=` 612 sed -ne '/^Signed-off-by: /p' \ 613 "$dotest/msg-clean" | 614 sed -ne '$p' 615 ` 616 ADD_SIGNOFF=` 617 test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || { 618 test '' = "$LAST_SIGNED_OFF_BY" && echo 619 echo "$SIGNOFF" 620 }` 621 else 622 ADD_SIGNOFF= 623 fi 624 { 625 if test -s "$dotest/msg-clean" 626 then 627 cat "$dotest/msg-clean" 628 fi 629 if test '' != "$ADD_SIGNOFF" 630 then 631 echo "$ADD_SIGNOFF" 632 fi 633 } >"$dotest/final-commit" 634 ;; 635 *) 636 case "$resolved$interactive" in 637 tt) 638 # This is used only for interactive view option. 639 git diff-index -p --cached HEAD -- >"$dotest/patch" 640 ;; 641 esac 642 esac 643 644 resume= 645 if test "$interactive" = t 646 then 647 test -t 0 || 648 die "cannot be interactive without stdin connected to a terminal." 649 action=again 650 while test "$action" = again 651 do 652 echo "Commit Body is:" 653 echo "--------------------------" 654 cat "$dotest/final-commit" 655 echo "--------------------------" 656 printf "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " 657 read reply 658 case "$reply" in 659 [yY]*) action=yes ;; 660 [aA]*) action=yes interactive= ;; 661 [nN]*) action=skip ;; 662 [eE]*) git_editor "$dotest/final-commit" 663 action=again ;; 664 [vV]*) action=again 665 :${GIT_PAGER=$(git var GIT_PAGER)} 666 :${LESS=-FRSX} 667 export LESS 668$GIT_PAGER"$dotest/patch" ;; 669 *) action=again ;; 670 esac 671 done 672 else 673 action=yes 674 fi 675 FIRSTLINE=$(sed 1q "$dotest/final-commit") 676 677 if test$action= skip 678 then 679 go_next 680 continue 681 fi 682 683 if test -x "$GIT_DIR"/hooks/applypatch-msg 684 then 685 "$GIT_DIR"/hooks/applypatch-msg "$dotest/final-commit" || 686 stop_here$this 687 fi 688 689 say "Applying:$FIRSTLINE" 690 691 case "$resolved" in 692 '') 693 # When we are allowed to fall back to 3-way later, don't give 694# false errors during the initial attempt. 695 squelch= 696iftest"$threeway"= t 697then 698 squelch='>/dev/null 2>&1 ' 699fi 700eval"git apply$squelch$git_apply_opt"' --index "$dotest/patch"' 701 apply_status=$? 702;; 703 t) 704# Resolved means the user did all the hard work, and 705# we do not have to do any patch application. Just 706# trust what the user has in the index file and the 707# working tree. 708 resolved= 709 git diff-index --quiet --cached HEAD --&& { 710echo"No changes - did you forget to use 'git add'?" 711 stop_here_user_resolve $this 712} 713 unmerged=$(git ls-files -u) 714iftest -n"$unmerged" 715then 716echo"You still have unmerged paths in your index" 717echo"did you forget to use 'git add'?" 718 stop_here_user_resolve $this 719fi 720 apply_status=0 721 git rerere 722;; 723esac 724 725iftest$apply_status=1&&test"$threeway"= t 726then 727if(fall_back_3way) 728then 729# Applying the patch to an earlier tree and merging the 730# result may have produced the same tree as ours. 731 git diff-index --quiet --cached HEAD --&& { 732 say No changes -- Patch already applied. 733 go_next 734continue 735} 736# clear apply_status -- we have successfully merged. 737 apply_status=0 738fi 739fi 740iftest$apply_status!=0 741then 742printf'Patch failed at %s %s\n'"$msgnum""$FIRSTLINE" 743 stop_here_user_resolve $this 744fi 745 746iftest -x"$GIT_DIR"/hooks/pre-applypatch 747then 748"$GIT_DIR"/hooks/pre-applypatch|| stop_here $this 749fi 750 751 tree=$(git write-tree)&& 752 commit=$( 753iftest -n"$ignore_date" 754then 755 GIT_AUTHOR_DATE= 756fi 757 parent=$(git rev-parse --verify -q HEAD)|| 758 say >&2"applying to an empty history" 759 760iftest -n"$committer_date_is_author_date" 761then 762 GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" 763export GIT_COMMITTER_DATE 764fi&& 765 git commit-tree$tree ${parent:+-p} $parent<"$dotest/final-commit" 766) && 767 git update-ref -m"$GIT_REFLOG_ACTION:$FIRSTLINE" HEAD $commit $parent|| 768 stop_here $this 769 770iftest -x"$GIT_DIR"/hooks/post-applypatch 771then 772"$GIT_DIR"/hooks/post-applypatch 773fi 774 775 go_next 776done 777 778git gc --auto 779 780rm-fr"$dotest"