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") && 361test"$(git cat-file -t "$commit")"= commit 362then 363 git cat-file commit "$commit"| 364sed-e'1,/^$/d'>"$dotest/msg-clean" 365else 366 SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")" 367case"$keep_subject"in-k) SUBJECT="[PATCH]$SUBJECT";;esac 368 369(printf'%s\n\n'"$SUBJECT";cat"$dotest/msg") | 370 git stripspace >"$dotest/msg-clean" 371fi 372;; 373esac 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 379iftest -z"$GIT_AUTHOR_EMAIL" 380then 381echo"Patch does not have a valid e-mail address." 382 stop_here $this 383fi 384 385export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE 386 387case"$resume"in 388'') 389iftest''!="$SIGNOFF" 390then 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 }` 401else 402 ADD_SIGNOFF= 403fi 404{ 405iftest -s"$dotest/msg-clean" 406then 407cat"$dotest/msg-clean" 408fi 409iftest''!="$ADD_SIGNOFF" 410then 411echo"$ADD_SIGNOFF" 412fi 413} >"$dotest/final-commit" 414;; 415*) 416case"$resolved$interactive"in 417 tt) 418# This is used only for interactive view option. 419 git diff-index -p --cached HEAD -->"$dotest/patch" 420;; 421esac 422esac 423 424 resume= 425iftest"$interactive"= t 426then 427test -t0|| 428 die "cannot be interactive without stdin connected to a terminal." 429 action=again 430whiletest"$action"= again 431do 432echo"Commit Body is:" 433echo"--------------------------" 434cat"$dotest/final-commit" 435echo"--------------------------" 436printf"Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " 437read reply 438case"$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 ;; 447esac 448done 449else 450 action=yes 451fi 452 FIRSTLINE=$(sed1q "$dotest/final-commit") 453 454iftest$action= skip 455then 456 go_next 457continue 458fi 459 460iftest -x"$GIT_DIR"/hooks/applypatch-msg 461then 462"$GIT_DIR"/hooks/applypatch-msg "$dotest/final-commit"|| 463 stop_here $this 464fi 465 466printf'Applying: %s\n'"$FIRSTLINE" 467 468case"$resolved"in 469'') 470eval'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 --&& { 480echo"No changes - did you forget to use 'git add'?" 481 stop_here_user_resolve $this 482} 483 unmerged=$(git ls-files -u) 484iftest -n"$unmerged" 485then 486echo"You still have unmerged paths in your index" 487echo"did you forget to use 'git add'?" 488 stop_here_user_resolve $this 489fi 490 apply_status=0 491 git rerere 492;; 493esac 494 495iftest$apply_status=1&&test"$threeway"= t 496then 497if(fall_back_3way) 498then 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 --&& { 502echo No changes -- Patch already applied. 503 go_next 504continue 505} 506# clear apply_status -- we have successfully merged. 507 apply_status=0 508fi 509fi 510iftest$apply_status!=0 511then 512printf'Patch failed at %s %s\n'"$msgnum""$FIRSTLINE" 513 stop_here_user_resolve $this 514fi 515 516iftest -x"$GIT_DIR"/hooks/pre-applypatch 517then 518"$GIT_DIR"/hooks/pre-applypatch || stop_here $this 519fi 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 527iftest -x"$GIT_DIR"/hooks/post-applypatch 528then 529"$GIT_DIR"/hooks/post-applypatch 530fi 531 532 go_next 533done 534 535git gc --auto 536 537rm-fr"$dotest"