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