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