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