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/.*/'\''&'\''/' 42 done 43} 44 45stop_here () { 46 echo "$1" >"$dotest/next" 47 exit 1 48} 49 50stop_here_user_resolve () { 51 if [ -n "$resolvemsg" ]; then 52 printf '%s\n' "$resolvemsg" 53 stop_here$1 54 fi 55 cmdline="git am" 56 if test '' != "$interactive" 57 then 58 cmdline="$cmdline-i" 59 fi 60 if test '' != "$threeway" 61 then 62 cmdline="$cmdline-3" 63 fi 64 echo "When you have resolved this problem run\"$cmdline--resolved\"." 65 echo "If you would prefer to skip this patch, instead run\"$cmdline--skip\"." 66 echo "To restore the original branch and stop patching run\"$cmdline--abort\"." 67 68 stop_here$1 69} 70 71go_next () { 72 rm -f "$dotest/$msgnum" "$dotest/msg" "$dotest/msg-clean" \ 73 "$dotest/patch" "$dotest/info" 74 echo "$next" >"$dotest/next" 75 this=$next 76} 77 78cannot_fallback () { 79 echo "$1" 80 echo "Cannot fall back to three-way merge." 81 exit 1 82} 83 84fall_back_3way () { 85 O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd` 86 87 rm -fr "$dotest"/patch-merge-* 88 mkdir "$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 97 echo Using index info to reconstruct a base tree... 98 if GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \ 99 git apply --cached <"$dotest/patch" 100 then 101 mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base" 102 mv "$dotest/patch-merge-tmp-index" "$dotest/patch-merge-index" 103 else 104 cannot_fallback "Did you hand edit your patch? 105It does not apply to blobs recorded in its index." 106 fi 107 108 test -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")&& 111 rm -fr "$dotest"/patch-merge-* || exit 1 112 113 echo 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 121 eval GITHEAD_$his_tree='"$FIRSTLINE"' 122 export GITHEAD_$his_tree 123 git-merge-recursive$orig_tree-- HEAD$his_tree|| { 124 git rerere 125 echo Failed to merge in the changes. 126 exit 1 127 } 128 unset 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 137while test$#!= 0 138do 139 case "$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) 166 shift; 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 --) 172 shift; break ;; 173 *) 174 usage ;; 175 esac 176 shift 177done 178 179# If the dotest directory exists, but we have finished applying all the 180# patches in them, clear it out. 181if test -d "$dotest" && 182 last=$(cat "$dotest/last")&& 183 next=$(cat "$dotest/next")&& 184 test$#!= 0 && 185 test "$next" -gt "$last" 186then 187 rm -fr "$dotest" 188fi 189 190if test -d "$dotest" 191then 192 case "$#,$skip$resolved$abort" in 193 0,*t*) 194 # Explicit resume command and we do not have file, so 195 # we are happy. 196 : ;; 197 0,) 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 ;; 209 esac || 210 die "previous rebase directory$doteststill exists but mbox given." 211 resume=yes 212 213 case "$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 225 rm -fr "$dotest" 226 exit ;; 227 esac 228else 229 # Make sure we are not given --skip, --resolved, nor --abort 230 test "$skip$resolved$abort" = "" || 231 die "Resolve operation not in progress, we are not resuming." 232 233 # Start afresh. 234 mkdir -p "$dotest" || exit 235 236 if test -n "$prefix" && test$#!= 0 237 then 238 first=t 239 for arg 240 do 241 test -n "$first" && { 242 set x 243 first= 244 } 245 case "$arg" in 246 /*) 247 set "$@" "$arg" ;; 248 *) 249 set "$@" "$prefix$arg" ;; 250 esac 251 done 252 shift 253 fi 254 git mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" || { 255 rm -fr "$dotest" 256 exit 1 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. 262 echo "$git_apply_opt" >"$dotest/apply-opt" 263 echo "$threeway" >"$dotest/threeway" 264 echo "$sign" >"$dotest/sign" 265 echo "$utf8" >"$dotest/utf8" 266 echo "$keep" >"$dotest/keep" 267 echo 1 >"$dotest/next" 268 if test -n "$rebasing" 269 then 270 : >"$dotest/rebasing" 271 else 272 : >"$dotest/applying" 273 git update-ref ORIG_HEAD HEAD 274 fi 275fi 276 277case "$resolved" in 278'') 279 files=$(git diff-index --cached --name-only HEAD --)|| exit 280 if [ "$files" ]; then 281 echo "Dirty index: cannot apply patches (dirty:$files)" >&2 282 exit 1 283 fi 284esac 285 286if test "$(cat "$dotest/utf8")" = t 287then 288 utf8=-u 289else 290 utf8=-n 291fi 292if test "$(cat "$dotest/keep")" = t 293then 294 keep=-k 295fi 296if test "$(cat "$dotest/threeway")" = t 297then 298 threeway=t 299fi 300git_apply_opt=$(cat "$dotest/apply-opt") 301if test "$(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"` 313if test "$skip" = t 314then 315 this=`expr "$this" + 1` 316 resume= 317fi 318 319if test "$this" -gt "$last" 320then 321 echo Nothing to do. 322 rm -fr "$dotest" 323 exit 324fi 325 326while test "$this" -le "$last" 327do 328 msgnum=`printf "%0${prec}d"$this` 329 next=`expr "$this" + 1` 330 test -f "$dotest/$msgnum" || { 331 resume= 332 go_next 333 continue 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. 344 case "$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"