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