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