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