diff options
Diffstat (limited to 'git-am.sh')
-rwxr-xr-x | git-am.sh | 204 |
1 files changed, 151 insertions, 53 deletions
@@ -5,7 +5,7 @@ SUBDIRECTORY_OK=Yes OPTIONS_KEEPDASHDASH= OPTIONS_SPEC="\ -git am [options] [<mbox>|<Maildir>...] +git am [options] [(<mbox>|<Maildir>)...] git am [options] (--resolved | --skip | --abort) -- i,interactive run interactively @@ -15,18 +15,25 @@ q,quiet be quiet s,signoff add a Signed-off-by line to the commit message u,utf8 recode into utf8 (default) k,keep pass -k flag to git-mailinfo +keep-cr pass --keep-cr flag to git-mailsplit for mbox format +no-keep-cr do not pass --keep-cr flag to git-mailsplit independent of am.keepcr +c,scissors strip everything before a scissors line whitespace= pass it through git-apply +ignore-space-change pass it through git-apply +ignore-whitespace pass it through git-apply directory= pass it through git-apply C= pass it through git-apply p= pass it through git-apply patch-format= format the patch(es) are in reject pass it through git-apply resolvemsg= override error message when patch failure occurs -r,resolved to be used after a patch failure +continue continue applying patches after resolving a conflict +r,resolved synonyms for --continue skip skip the current patch abort restore the original branch and abort the patching operation. committer-date-is-author-date lie about committer date ignore-date use current timestamp for author date +rerere-autoupdate update the index with reused conflict resolution if possible rebasing* (internal use for git-rebase)" . git-sh-setup @@ -45,29 +52,52 @@ else HAS_HEAD= fi +cmdline="git am" +if test '' != "$interactive" +then + cmdline="$cmdline -i" +fi +if test '' != "$threeway" +then + cmdline="$cmdline -3" +fi + sq () { git rev-parse --sq-quote "$@" } stop_here () { echo "$1" >"$dotest/next" + git rev-parse --verify -q HEAD >"$dotest/abort-safety" exit 1 } +safe_to_abort () { + if test -f "$dotest/dirtyindex" + then + return 1 + fi + + if ! test -s "$dotest/abort-safety" + then + return 0 + fi + + abort_safety=$(cat "$dotest/abort-safety") + if test "z$(git rev-parse --verify -q HEAD)" = "z$abort_safety" + then + return 0 + fi + echo >&2 "You seem to have moved HEAD since the last 'am' failure." + echo >&2 "Not rewinding to ORIG_HEAD" + return 1 +} + stop_here_user_resolve () { if [ -n "$resolvemsg" ]; then printf '%s\n' "$resolvemsg" stop_here $1 fi - cmdline="git am" - if test '' != "$interactive" - then - cmdline="$cmdline -i" - fi - if test '' != "$threeway" - then - cmdline="$cmdline -3" - fi echo "When you have resolved this problem run \"$cmdline --resolved\"." echo "If you would prefer to skip this patch, instead run \"$cmdline --skip\"." echo "To restore the original branch and stop patching run \"$cmdline --abort\"." @@ -129,10 +159,10 @@ It does not apply to blobs recorded in its index." export GITHEAD_$his_tree if test -n "$GIT_QUIET" then - export GIT_MERGE_VERBOSITY=0 + GIT_MERGE_VERBOSITY=0 && export GIT_MERGE_VERBOSITY fi git-merge-recursive $orig_tree -- HEAD $his_tree || { - git rerere + git rerere $allow_rerere_autoupdate echo Failed to merge in the changes. exit 1 } @@ -201,8 +231,9 @@ check_patch_format () { # discarding the indented remainder of folded lines, # and see if it looks like that they all begin with the # header field names... - sed -n -e '/^$/q' -e '/^[ ]/d' -e p "$1" | - egrep -v '^[A-Za-z]+(-[A-Za-z]+)*:' >/dev/null || + tr -d '\015' <"$1" | + sed -n -e '/^$/q' -e '/^[ ]/d' -e p | + sane_egrep -v '^[!-9;-~]+:' >/dev/null || patch_format=mbox fi } < "$1" || clean_abort @@ -211,7 +242,13 @@ check_patch_format () { split_patches () { case "$patch_format" in mbox) - git mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" || + if test -n "$rebasing" || test t = "$keepcr" + then + keep_cr=--keep-cr + else + keep_cr= + fi + git mailsplit -d"$prec" -o"$dotest" -b $keep_cr -- "$@" > "$dotest/last" || clean_abort ;; stgit-series) @@ -280,11 +317,17 @@ split_patches () { prec=4 dotest="$GIT_DIR/rebase-apply" -sign= utf8=t keep= skip= interactive= resolved= rebasing= abort= -resolvemsg= resume= +sign= utf8=t keep= keepcr= skip= interactive= resolved= rebasing= abort= +resolvemsg= resume= scissors= no_inbody_headers= git_apply_opt= committer_date_is_author_date= ignore_date= +allow_rerere_autoupdate= + +if test "$(git config --bool --get am.keepcr)" = true +then + keepcr=t +fi while test $# != 0 do @@ -303,14 +346,18 @@ do utf8= ;; -k|--keep) keep=t ;; - -r|--resolved) + -c|--scissors) + scissors=t ;; + --no-scissors) + scissors=f ;; + -r|--resolved|--continue) resolved=t ;; --skip) skip=t ;; --abort) abort=t ;; --rebasing) - rebasing=t threeway=t keep=t ;; + rebasing=t threeway=t keep=t scissors=f no_inbody_headers=t ;; -d|--dotest) die "-d option is no longer supported. Do not use." ;; @@ -322,14 +369,20 @@ do git_apply_opt="$git_apply_opt $(sq "$1$2")"; shift ;; --patch-format) shift ; patch_format="$1" ;; - --reject) + --reject|--ignore-whitespace|--ignore-space-change) git_apply_opt="$git_apply_opt $1" ;; --committer-date-is-author-date) committer_date_is_author_date=t ;; --ignore-date) ignore_date=t ;; + --rerere-autoupdate|--no-rerere-autoupdate) + allow_rerere_autoupdate="$1" ;; -q|--quiet) GIT_QUIET=t ;; + --keep-cr) + keepcr=t ;; + --no-keep-cr) + keepcr=f ;; --) shift; break ;; *) @@ -389,10 +442,11 @@ then exec git rebase --abort fi git rerere clear - test -f "$dotest/dirtyindex" || { + if safe_to_abort + then git read-tree --reset -u HEAD ORIG_HEAD git reset ORIG_HEAD - } + fi rm -fr "$dotest" exit ;; esac @@ -414,12 +468,12 @@ else set x first= } - case "$arg" in - /*) - set "$@" "$arg" ;; - *) - set "$@" "$prefix$arg" ;; - esac + if is_absolute_path "$arg" + then + set "$@" "$arg" + else + set "$@" "$prefix$arg" + fi done shift fi @@ -428,14 +482,16 @@ else split_patches "$@" - # -s, -u, -k, --whitespace, -3, -C, -q and -p flags are kept - # for the resuming session after a patch failure. - # -i can and must be given when resuming. + # -i can and must be given when resuming; everything + # else is kept echo " $git_apply_opt" >"$dotest/apply-opt" echo "$threeway" >"$dotest/threeway" echo "$sign" >"$dotest/sign" echo "$utf8" >"$dotest/utf8" echo "$keep" >"$dotest/keep" + echo "$keepcr" >"$dotest/keepcr" + echo "$scissors" >"$dotest/scissors" + echo "$no_inbody_headers" >"$dotest/no_inbody_headers" echo "$GIT_QUIET" >"$dotest/quiet" echo 1 >"$dotest/next" if test -n "$rebasing" @@ -452,6 +508,8 @@ else fi fi +git update-index -q --refresh + case "$resolved" in '') case "$HAS_HEAD" in @@ -477,6 +535,24 @@ if test "$(cat "$dotest/keep")" = t then keep=-k fi +case "$(cat "$dotest/keepcr")" in +t) + keepcr=--keep-cr ;; +f) + keepcr=--no-keep-cr ;; +esac +case "$(cat "$dotest/scissors")" in +t) + scissors=--scissors ;; +f) + scissors=--no-scissors ;; +esac +if test "$(cat "$dotest/no_inbody_headers")" = t +then + no_inbody_headers=--no-inbody-headers +else + no_inbody_headers= +fi if test "$(cat "$dotest/quiet")" = t then GIT_QUIET=t @@ -504,13 +580,6 @@ then resume= fi -if test "$this" -gt "$last" -then - say Nothing to do. - rm -fr "$dotest" - exit -fi - while test "$this" -le "$last" do msgnum=`printf "%0${prec}d" $this` @@ -531,19 +600,22 @@ do # by the user, or the user can tell us to do so by --resolved flag. case "$resume" in '') - git mailinfo $keep $utf8 "$dotest/msg" "$dotest/patch" \ + git mailinfo $keep $no_inbody_headers $scissors $utf8 "$dotest/msg" "$dotest/patch" \ <"$dotest/$msgnum" >"$dotest/info" || stop_here $this # skip pine's internal folder data - grep '^Author: Mail System Internal Data$' \ + sane_grep '^Author: Mail System Internal Data$' \ <"$dotest"/info >/dev/null && go_next && continue test -s "$dotest/patch" || { echo "Patch is empty. Was it split wrong?" + echo "If you would prefer to skip this patch, instead run \"$cmdline --skip\"." + echo "To restore the original branch and stop patching run \"$cmdline --abort\"." stop_here $this } + rm -f "$dotest/original-commit" "$dotest/author-script" if test -f "$dotest/rebasing" && commit=$(sed -e 's/^From \([0-9a-f]*\) .*/\1/' \ -e q "$dotest/$msgnum") && @@ -551,19 +623,27 @@ do then git cat-file commit "$commit" | sed -e '1,/^$/d' >"$dotest/msg-clean" + echo "$commit" > "$dotest/original-commit" + get_author_ident_from_commit "$commit" > "$dotest/author-script" else - SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")" - case "$keep_subject" in -k) SUBJECT="[PATCH] $SUBJECT" ;; esac - - (printf '%s\n\n' "$SUBJECT"; cat "$dotest/msg") | - git stripspace > "$dotest/msg-clean" + { + sed -n '/^Subject/ s/Subject: //p' "$dotest/info" + echo + cat "$dotest/msg" + } | + git stripspace > "$dotest/msg-clean" fi ;; esac - GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$dotest/info")" - GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$dotest/info")" - GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$dotest/info")" + if test -f "$dotest/author-script" + then + eval $(cat "$dotest/author-script") + else + GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$dotest/info")" + GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$dotest/info")" + GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$dotest/info")" + fi if test -z "$GIT_AUTHOR_EMAIL" then @@ -631,14 +711,20 @@ do [eE]*) git_editor "$dotest/final-commit" action=again ;; [vV]*) action=again - LESS=-S ${PAGER:-less} "$dotest/patch" ;; + git_pager "$dotest/patch" ;; *) action=again ;; esac done else action=yes fi - FIRSTLINE=$(sed 1q "$dotest/final-commit") + + if test -f "$dotest/final-commit" + then + FIRSTLINE=$(sed 1q "$dotest/final-commit") + else + FIRSTLINE="" + fi if test $action = skip then @@ -674,6 +760,8 @@ do resolved= git diff-index --quiet --cached HEAD -- && { echo "No changes - did you forget to use 'git add'?" + echo "If there is nothing left to stage, chances are that something else" + echo "already introduced the same changes; you might want to skip this patch." stop_here_user_resolve $this } unmerged=$(git ls-files -u) @@ -688,7 +776,7 @@ do ;; esac - if test $apply_status = 1 && test "$threeway" = t + if test $apply_status != 0 && test "$threeway" = t then if (fall_back_3way) then @@ -733,6 +821,10 @@ do git update-ref -m "$GIT_REFLOG_ACTION: $FIRSTLINE" HEAD $commit $parent || stop_here $this + if test -f "$dotest/original-commit"; then + echo "$(cat "$dotest/original-commit") $commit" >> "$dotest/rewritten" + fi + if test -x "$GIT_DIR"/hooks/post-applypatch then "$GIT_DIR"/hooks/post-applypatch @@ -741,6 +833,12 @@ do go_next done -git gc --auto +if test -s "$dotest"/rewritten; then + git notes copy --for-rewrite=rebase < "$dotest"/rewritten + if test -x "$GIT_DIR"/hooks/post-rewrite; then + "$GIT_DIR"/hooks/post-rewrite rebase < "$dotest"/rewritten + fi +fi rm -fr "$dotest" +git gc --auto |