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