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*) 195echo"Patch format$patch_formatis not supported." 196exit1 197;; 198esac 199} 200 201prec=4 202dotest="$GIT_DIR/rebase-apply" 203sign= utf8=t keep= skip= interactive= resolved= rebasing= abort= 204resolvemsg= resume= 205git_apply_opt= 206committer_date_is_author_date= 207ignore_date= 208 209whiletest$#!=0 210do 211case"$1"in 212-i|--interactive) 213 interactive=t ;; 214-b|--binary) 215: ;; 216-3|--3way) 217 threeway=t ;; 218-s|--signoff) 219 sign=t ;; 220-u|--utf8) 221 utf8=t ;;# this is now default 222--no-utf8) 223 utf8= ;; 224-k|--keep) 225 keep=t ;; 226-r|--resolved) 227 resolved=t ;; 228--skip) 229 skip=t ;; 230--abort) 231 abort=t ;; 232--rebasing) 233 rebasing=t threeway=t keep=t ;; 234-d|--dotest) 235 die "-d option is no longer supported. Do not use." 236;; 237--resolvemsg) 238shift; resolvemsg=$1;; 239--whitespace|--directory) 240 git_apply_opt="$git_apply_opt$(sq "$1=$2")";shift;; 241-C|-p) 242 git_apply_opt="$git_apply_opt$(sq "$1$2")";shift;; 243--patch-format) 244shift; patch_format="$1";; 245--reject) 246 git_apply_opt="$git_apply_opt$1";; 247--committer-date-is-author-date) 248 committer_date_is_author_date=t ;; 249--ignore-date) 250 ignore_date=t ;; 251--) 252shift;break;; 253*) 254 usage ;; 255esac 256shift 257done 258 259# If the dotest directory exists, but we have finished applying all the 260# patches in them, clear it out. 261iftest -d"$dotest"&& 262 last=$(cat "$dotest/last")&& 263 next=$(cat "$dotest/next")&& 264test$#!=0&& 265test"$next"-gt"$last" 266then 267rm-fr"$dotest" 268fi 269 270iftest -d"$dotest" 271then 272case"$#,$skip$resolved$abort"in 2730,*t*) 274# Explicit resume command and we do not have file, so 275# we are happy. 276: ;; 2770,) 278# No file input but without resume parameters; catch 279# user error to feed us a patch from standard input 280# when there is already $dotest. This is somewhat 281# unreliable -- stdin could be /dev/null for example 282# and the caller did not intend to feed us a patch but 283# wanted to continue unattended. 284test -t0 285;; 286*) 287 false 288;; 289esac|| 290 die "previous rebase directory$doteststill exists but mbox given." 291 resume=yes 292 293case"$skip,$abort"in 294 t,t) 295 die "Please make up your mind. --skip or --abort?" 296;; 297 t,) 298 git rerere clear 299 git read-tree --reset -u HEAD HEAD 300 orig_head=$(cat "$GIT_DIR/ORIG_HEAD") 301 git reset HEAD 302 git update-ref ORIG_HEAD $orig_head 303;; 304,t) 305iftest -f"$dotest/rebasing" 306then 307exec git rebase --abort 308fi 309 git rerere clear 310test -f"$dotest/dirtyindex"|| { 311 git read-tree --reset -u HEAD ORIG_HEAD 312 git reset ORIG_HEAD 313} 314rm-fr"$dotest" 315exit;; 316esac 317rm-f"$dotest/dirtyindex" 318else 319# Make sure we are not given --skip, --resolved, nor --abort 320test"$skip$resolved$abort"=""|| 321 die "Resolve operation not in progress, we are not resuming." 322 323# Start afresh. 324mkdir-p"$dotest"||exit 325 326iftest -n"$prefix"&&test$#!=0 327then 328 first=t 329for arg 330do 331test -n"$first"&& { 332set x 333 first= 334} 335case"$arg"in 336/*) 337set"$@""$arg";; 338*) 339set"$@""$prefix$arg";; 340esac 341done 342shift 343fi 344 345 check_patch_format "$@" 346 347 split_patches "$@" 348 349# -s, -u, -k, --whitespace, -3, -C and -p flags are kept 350# for the resuming session after a patch failure. 351# -i can and must be given when resuming. 352echo"$git_apply_opt">"$dotest/apply-opt" 353echo"$threeway">"$dotest/threeway" 354echo"$sign">"$dotest/sign" 355echo"$utf8">"$dotest/utf8" 356echo"$keep">"$dotest/keep" 357echo1>"$dotest/next" 358iftest -n"$rebasing" 359then 360: >"$dotest/rebasing" 361else 362: >"$dotest/applying" 363iftest -n"$HAS_HEAD" 364then 365 git update-ref ORIG_HEAD HEAD 366else 367 git update-ref -d ORIG_HEAD >/dev/null 2>&1 368fi 369fi 370fi 371 372case"$resolved"in 373'') 374case"$HAS_HEAD"in 375'') 376 files=$(git ls-files);; 377 ?*) 378 files=$(git diff-index --cached --name-only HEAD --);; 379esac||exit 380iftest"$files" 381then 382test -n"$HAS_HEAD"&& : >"$dotest/dirtyindex" 383 die "Dirty index: cannot apply patches (dirty:$files)" 384fi 385esac 386 387iftest"$(cat "$dotest/utf8")"= t 388then 389 utf8=-u 390else 391 utf8=-n 392fi 393iftest"$(cat "$dotest/keep")"= t 394then 395 keep=-k 396fi 397iftest"$(cat "$dotest/threeway")"= t 398then 399 threeway=t 400fi 401git_apply_opt=$(cat "$dotest/apply-opt") 402iftest"$(cat "$dotest/sign")"= t 403then 404 SIGNOFF=`git var GIT_COMMITTER_IDENT | sed -e ' 405 s/>.*/>/ 406 s/^/Signed-off-by: /' 407 ` 408else 409 SIGNOFF= 410fi 411 412last=`cat "$dotest/last"` 413this=`cat "$dotest/next"` 414iftest"$skip"= t 415then 416 this=`expr "$this" + 1` 417 resume= 418fi 419 420iftest"$this"-gt"$last" 421then 422echo Nothing to do. 423rm-fr"$dotest" 424exit 425fi 426 427whiletest"$this"-le"$last" 428do 429 msgnum=`printf "%0${prec}d"$this` 430 next=`expr "$this" + 1` 431test -f"$dotest/$msgnum"|| { 432 resume= 433 go_next 434continue 435} 436 437# If we are not resuming, parse and extract the patch information 438# into separate files: 439# - info records the authorship and title 440# - msg is the rest of commit log message 441# - patch is the patch body. 442# 443# When we are resuming, these files are either already prepared 444# by the user, or the user can tell us to do so by --resolved flag. 445case"$resume"in 446'') 447 git mailinfo $keep $utf8"$dotest/msg""$dotest/patch" \ 448<"$dotest/$msgnum">"$dotest/info"|| 449 stop_here $this 450 451# skip pine's internal folder data 452grep'^Author: Mail System Internal Data$' \ 453<"$dotest"/info >/dev/null && 454 go_next &&continue 455 456test -s"$dotest/patch"|| { 457echo"Patch is empty. Was it split wrong?" 458 stop_here $this 459} 460iftest -f"$dotest/rebasing"&& 461 commit=$(sed -e 's/^From \([0-9a-f]*\) .*/\1/' \ 462 -e q "$dotest/$msgnum") && 463 test "$(git cat-file -t "$commit")" = commit 464 then 465 git cat-file commit "$commit" | 466 sed -e '1,/^$/d' >"$dotest/msg-clean" 467 else 468 SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")" 469 case "$keep_subject" in -k) SUBJECT="[PATCH]$SUBJECT" ;; esac 470 471 (printf '%s\n\n' "$SUBJECT"; cat "$dotest/msg") | 472 git stripspace > "$dotest/msg-clean" 473 fi 474 ;; 475 esac 476 477 GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$dotest/info")" 478 GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$dotest/info")" 479 GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$dotest/info")" 480 481 if test -z "$GIT_AUTHOR_EMAIL" 482 then 483 echo "Patch does not have a valid e-mail address." 484 stop_here$this 485 fi 486 487 export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE 488 489 case "$resume" in 490 '') 491 if test '' != "$SIGNOFF" 492 then 493 LAST_SIGNED_OFF_BY=` 494 sed -ne '/^Signed-off-by: /p' \ 495 "$dotest/msg-clean" | 496 sed -ne '$p' 497 ` 498 ADD_SIGNOFF=` 499 test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || { 500 test '' = "$LAST_SIGNED_OFF_BY" && echo 501 echo "$SIGNOFF" 502 }` 503 else 504 ADD_SIGNOFF= 505 fi 506 { 507 if test -s "$dotest/msg-clean" 508 then 509 cat "$dotest/msg-clean" 510 fi 511 if test '' != "$ADD_SIGNOFF" 512 then 513 echo "$ADD_SIGNOFF" 514 fi 515 } >"$dotest/final-commit" 516 ;; 517 *) 518 case "$resolved$interactive" in 519 tt) 520 # This is used only for interactive view option. 521 git diff-index -p --cached HEAD -- >"$dotest/patch" 522 ;; 523 esac 524 esac 525 526 resume= 527 if test "$interactive" = t 528 then 529 test -t 0 || 530 die "cannot be interactive without stdin connected to a terminal." 531 action=again 532 while test "$action" = again 533 do 534 echo "Commit Body is:" 535 echo "--------------------------" 536 cat "$dotest/final-commit" 537 echo "--------------------------" 538 printf "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " 539 read reply 540 case "$reply" in 541 [yY]*) action=yes ;; 542 [aA]*) action=yes interactive= ;; 543 [nN]*) action=skip ;; 544 [eE]*) git_editor "$dotest/final-commit" 545 action=again ;; 546 [vV]*) action=again 547 LESS=-S${PAGER:-less}"$dotest/patch" ;; 548 *) action=again ;; 549 esac 550 done 551 else 552 action=yes 553 fi 554 FIRSTLINE=$(sed 1q "$dotest/final-commit") 555 556 if test$action= skip 557 then 558 go_next 559 continue 560 fi 561 562 if test -x "$GIT_DIR"/hooks/applypatch-msg 563 then 564 "$GIT_DIR"/hooks/applypatch-msg "$dotest/final-commit" || 565 stop_here$this 566 fi 567 568 printf 'Applying: %s\n' "$FIRSTLINE" 569 570 case "$resolved" in 571 '') 572 eval 'git apply '"$git_apply_opt"'--index"$dotest/patch"' 573 apply_status=$? 574 ;; 575 t) 576 # Resolved means the user did all the hard work, and 577 # we do not have to do any patch application. Just 578 # trust what the user has in the index file and the 579 # working tree. 580 resolved= 581 git diff-index --quiet --cached HEAD -- && { 582 echo "No changes - did you forget to use 'git add'?" 583 stop_here_user_resolve$this 584 } 585 unmerged=$(git ls-files -u) 586 if test -n "$unmerged" 587 then 588 echo "You still have unmerged paths in your index" 589 echo "did you forget to use 'git add'?" 590 stop_here_user_resolve$this 591 fi 592 apply_status=0 593 git rerere 594 ;; 595 esac 596 597 if test$apply_status= 1 && test "$threeway" = t 598 then 599 if (fall_back_3way) 600 then 601 # Applying the patch to an earlier tree and merging the 602 # result may have produced the same tree as ours. 603 git diff-index --quiet --cached HEAD -- && { 604 echo No changes -- Patch already applied. 605 go_next 606 continue 607 } 608 # clear apply_status -- we have successfully merged. 609 apply_status=0 610 fi 611 fi 612 if test$apply_status!= 0 613 then 614 printf 'Patch failed at%s %s\n' "$msgnum" "$FIRSTLINE" 615 stop_here_user_resolve$this 616 fi 617 618 if test -x "$GIT_DIR"/hooks/pre-applypatch 619 then 620 "$GIT_DIR"/hooks/pre-applypatch || stop_here$this 621 fi 622 623 tree=$(git write-tree)&& 624 commit=$( 625 if test -n "$ignore_date" 626 then 627 GIT_AUTHOR_DATE= 628 fi 629 parent=$(git rev-parse --verify -q HEAD)|| 630 echo >&2 "applying to an empty history" 631 632 if test -n "$committer_date_is_author_date" 633 then 634 GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" 635 export GIT_COMMITTER_DATE 636 fi && 637 git commit-tree$tree${parent:+-p}$parent<"$dotest/final-commit" 638 ) && 639 git update-ref -m "$GIT_REFLOG_ACTION:$FIRSTLINE" HEAD$commit$parent|| 640 stop_here$this 641 642 if test -x "$GIT_DIR"/hooks/post-applypatch 643 then 644 "$GIT_DIR"/hooks/post-applypatch 645 fi 646 647 go_next 648done 649 650git gc --auto 651 652rm -fr "$dotest"