git-am.shon commit Merge branch 'jc/make' (3bd5c81)
   1#!/bin/sh
   2#
   3# Copyright (c) 2005, 2006 Junio C Hamano
   4
   5USAGE='[--signoff] [--dotest=<dir>] [--utf8] [--binary] [--3way]
   6  [--interactive] [--whitespace=<option>] <mbox>...
   7  or, when resuming [--skip | --resolved]'
   8. git-sh-setup
   9set_reflog_action am
  10
  11git var GIT_COMMITTER_IDENT >/dev/null || exit
  12
  13stop_here () {
  14    echo "$1" >"$dotest/next"
  15    exit 1
  16}
  17
  18stop_here_user_resolve () {
  19    if [ -n "$resolvemsg" ]; then
  20            echo "$resolvemsg"
  21            stop_here $1
  22    fi
  23    cmdline=$(basename $0)
  24    if test '' != "$interactive"
  25    then
  26        cmdline="$cmdline -i"
  27    fi
  28    if test '' != "$threeway"
  29    then
  30        cmdline="$cmdline -3"
  31    fi
  32    if test '.dotest' != "$dotest"
  33    then
  34        cmdline="$cmdline -d=$dotest"
  35    fi
  36    echo "When you have resolved this problem run \"$cmdline --resolved\"."
  37    echo "If you would prefer to skip this patch, instead run \"$cmdline --skip\"."
  38
  39    stop_here $1
  40}
  41
  42go_next () {
  43        rm -f "$dotest/$msgnum" "$dotest/msg" "$dotest/msg-clean" \
  44                "$dotest/patch" "$dotest/info"
  45        echo "$next" >"$dotest/next"
  46        this=$next
  47}
  48
  49cannot_fallback () {
  50        echo "$1"
  51        echo "Cannot fall back to three-way merge."
  52        exit 1
  53}
  54
  55fall_back_3way () {
  56    O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
  57
  58    rm -fr "$dotest"/patch-merge-*
  59    mkdir "$dotest/patch-merge-tmp-dir"
  60
  61    # First see if the patch records the index info that we can use.
  62    git-apply -z --index-info "$dotest/patch" \
  63        >"$dotest/patch-merge-index-info" &&
  64    GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
  65    git-update-index -z --index-info <"$dotest/patch-merge-index-info" &&
  66    GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
  67    git-write-tree >"$dotest/patch-merge-base+" ||
  68    cannot_fallback "Patch does not record usable index information."
  69
  70    echo Using index info to reconstruct a base tree...
  71    if GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
  72        git-apply $binary --cached <"$dotest/patch"
  73    then
  74        mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base"
  75        mv "$dotest/patch-merge-tmp-index" "$dotest/patch-merge-index"
  76    else
  77        cannot_fallback "Did you hand edit your patch?
  78It does not apply to blobs recorded in its index."
  79    fi
  80
  81    test -f "$dotest/patch-merge-index" &&
  82    his_tree=$(GIT_INDEX_FILE="$dotest/patch-merge-index" git-write-tree) &&
  83    orig_tree=$(cat "$dotest/patch-merge-base") &&
  84    rm -fr "$dotest"/patch-merge-* || exit 1
  85
  86    echo Falling back to patching base and 3-way merge...
  87
  88    # This is not so wrong.  Depending on which base we picked,
  89    # orig_tree may be wildly different from ours, but his_tree
  90    # has the same set of wildly different changes in parts the
  91    # patch did not touch, so resolve ends up canceling them,
  92    # saying that we reverted all those changes.
  93
  94    git-merge-resolve $orig_tree -- HEAD $his_tree || {
  95            if test -d "$GIT_DIR/rr-cache"
  96            then
  97                git-rerere
  98            fi
  99            echo Failed to merge in the changes.
 100            exit 1
 101    }
 102}
 103
 104prec=4
 105dotest=.dotest sign= utf8= keep= skip= interactive= resolved= binary= ws= resolvemsg=
 106
 107while case "$#" in 0) break;; esac
 108do
 109        case "$1" in
 110        -d=*|--d=*|--do=*|--dot=*|--dote=*|--dotes=*|--dotest=*)
 111        dotest=`expr "z$1" : 'z-[^=]*=\(.*\)'`; shift ;;
 112        -d|--d|--do|--dot|--dote|--dotes|--dotest)
 113        case "$#" in 1) usage ;; esac; shift
 114        dotest="$1"; shift;;
 115
 116        -i|--i|--in|--int|--inte|--inter|--intera|--interac|--interact|\
 117        --interacti|--interactiv|--interactive)
 118        interactive=t; shift ;;
 119
 120        -b|--b|--bi|--bin|--bina|--binar|--binary)
 121        binary=t; shift ;;
 122
 123        -3|--3|--3w|--3wa|--3way)
 124        threeway=t; shift ;;
 125        -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
 126        sign=t; shift ;;
 127        -u|--u|--ut|--utf|--utf8)
 128        utf8=t; shift ;;
 129        -k|--k|--ke|--kee|--keep)
 130        keep=t; shift ;;
 131
 132        -r|--r|--re|--res|--reso|--resol|--resolv|--resolve|--resolved)
 133        resolved=t; shift ;;
 134
 135        --sk|--ski|--skip)
 136        skip=t; shift ;;
 137
 138        --whitespace=*)
 139        ws=$1; shift ;;
 140
 141        --resolvemsg=*)
 142        resolvemsg=$(echo "$1" | sed -e "s/^--resolvemsg=//"); shift ;;
 143
 144        --)
 145        shift; break ;;
 146        -*)
 147        usage ;;
 148        *)
 149        break ;;
 150        esac
 151done
 152
 153# If the dotest directory exists, but we have finished applying all the
 154# patches in them, clear it out.
 155if test -d "$dotest" &&
 156   last=$(cat "$dotest/last") &&
 157   next=$(cat "$dotest/next") &&
 158   test $# != 0 &&
 159   test "$next" -gt "$last"
 160then
 161   rm -fr "$dotest"
 162fi
 163
 164if test -d "$dotest"
 165then
 166        case "$#,$skip$resolved" in
 167        0,*t*)
 168                # Explicit resume command and we do not have file, so
 169                # we are happy.
 170                : ;;
 171        0,)
 172                # No file input but without resume parameters; catch
 173                # user error to feed us a patch from standard input
 174                # when there is already .dotest.  This is somewhat
 175                # unreliable -- stdin could be /dev/null for example
 176                # and the caller did not intend to feed us a patch but
 177                # wanted to continue unattended.
 178                tty -s
 179                ;;
 180        *)
 181                false
 182                ;;
 183        esac ||
 184        die "previous dotest directory $dotest still exists but mbox given."
 185        resume=yes
 186else
 187        # Make sure we are not given --skip nor --resolved
 188        test ",$skip,$resolved," = ,,, ||
 189                die "Resolve operation not in progress, we are not resuming."
 190
 191        # Start afresh.
 192        mkdir -p "$dotest" || exit
 193
 194        git-mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" ||  {
 195                rm -fr "$dotest"
 196                exit 1
 197        }
 198
 199        # -b, -s, -u, -k and --whitespace flags are kept for the
 200        # resuming session after a patch failure.
 201        # -3 and -i can and must be given when resuming.
 202        echo "$binary" >"$dotest/binary"
 203        echo " $ws" >"$dotest/whitespace"
 204        echo "$sign" >"$dotest/sign"
 205        echo "$utf8" >"$dotest/utf8"
 206        echo "$keep" >"$dotest/keep"
 207        echo 1 >"$dotest/next"
 208fi
 209
 210case "$resolved" in
 211'')
 212        files=$(git-diff-index --cached --name-only HEAD) || exit
 213        if [ "$files" ]; then
 214           echo "Dirty index: cannot apply patches (dirty: $files)" >&2
 215           exit 1
 216        fi
 217esac
 218
 219if test "$(cat "$dotest/binary")" = t
 220then
 221        binary=--allow-binary-replacement
 222fi
 223if test "$(cat "$dotest/utf8")" = t
 224then
 225        utf8=-u
 226fi
 227if test "$(cat "$dotest/keep")" = t
 228then
 229        keep=-k
 230fi
 231ws=`cat "$dotest/whitespace"`
 232if test "$(cat "$dotest/sign")" = t
 233then
 234        SIGNOFF=`git-var GIT_COMMITTER_IDENT | sed -e '
 235                        s/>.*/>/
 236                        s/^/Signed-off-by: /'
 237                `
 238else
 239        SIGNOFF=
 240fi
 241
 242last=`cat "$dotest/last"`
 243this=`cat "$dotest/next"`
 244if test "$skip" = t
 245then
 246        if test -d "$GIT_DIR/rr-cache"
 247        then
 248                git-rerere clear
 249        fi
 250        this=`expr "$this" + 1`
 251        resume=
 252fi
 253
 254if test "$this" -gt "$last"
 255then
 256        echo Nothing to do.
 257        rm -fr "$dotest"
 258        exit
 259fi
 260
 261while test "$this" -le "$last"
 262do
 263        msgnum=`printf "%0${prec}d" $this`
 264        next=`expr "$this" + 1`
 265        test -f "$dotest/$msgnum" || {
 266                resume=
 267                go_next
 268                continue
 269        }
 270
 271        # If we are not resuming, parse and extract the patch information
 272        # into separate files:
 273        #  - info records the authorship and title
 274        #  - msg is the rest of commit log message
 275        #  - patch is the patch body.
 276        #
 277        # When we are resuming, these files are either already prepared
 278        # by the user, or the user can tell us to do so by --resolved flag.
 279        case "$resume" in
 280        '')
 281                git-mailinfo $keep $utf8 "$dotest/msg" "$dotest/patch" \
 282                        <"$dotest/$msgnum" >"$dotest/info" ||
 283                        stop_here $this
 284                git-stripspace < "$dotest/msg" > "$dotest/msg-clean"
 285                ;;
 286        esac
 287
 288        GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$dotest/info")"
 289        GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$dotest/info")"
 290        GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$dotest/info")"
 291
 292        if test -z "$GIT_AUTHOR_EMAIL"
 293        then
 294                echo "Patch does not have a valid e-mail address."
 295                stop_here $this
 296        fi
 297
 298        export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
 299
 300        SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")"
 301        case "$keep_subject" in -k)  SUBJECT="[PATCH] $SUBJECT" ;; esac
 302
 303        case "$resume" in
 304        '')
 305            if test '' != "$SIGNOFF"
 306            then
 307                LAST_SIGNED_OFF_BY=`
 308                    sed -ne '/^Signed-off-by: /p' \
 309                    "$dotest/msg-clean" |
 310                    tail -n 1
 311                `
 312                ADD_SIGNOFF=`
 313                    test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || {
 314                    test '' = "$LAST_SIGNED_OFF_BY" && echo
 315                    echo "$SIGNOFF"
 316                }`
 317            else
 318                ADD_SIGNOFF=
 319            fi
 320            {
 321                echo "$SUBJECT"
 322                if test -s "$dotest/msg-clean"
 323                then
 324                        echo
 325                        cat "$dotest/msg-clean"
 326                fi
 327                if test '' != "$ADD_SIGNOFF"
 328                then
 329                        echo "$ADD_SIGNOFF"
 330                fi
 331            } >"$dotest/final-commit"
 332            ;;
 333        *)
 334                case "$resolved$interactive" in
 335                tt)
 336                        # This is used only for interactive view option.
 337                        git-diff-index -p --cached HEAD >"$dotest/patch"
 338                        ;;
 339                esac
 340        esac
 341
 342        resume=
 343        if test "$interactive" = t
 344        then
 345            test -t 0 ||
 346            die "cannot be interactive without stdin connected to a terminal."
 347            action=again
 348            while test "$action" = again
 349            do
 350                echo "Commit Body is:"
 351                echo "--------------------------"
 352                cat "$dotest/final-commit"
 353                echo "--------------------------"
 354                printf "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
 355                read reply
 356                case "$reply" in
 357                [yY]*) action=yes ;;
 358                [aA]*) action=yes interactive= ;;
 359                [nN]*) action=skip ;;
 360                [eE]*) "${VISUAL:-${EDITOR:-vi}}" "$dotest/final-commit"
 361                       action=again ;;
 362                [vV]*) action=again
 363                       LESS=-S ${PAGER:-less} "$dotest/patch" ;;
 364                *)     action=again ;;
 365                esac
 366            done
 367        else
 368            action=yes
 369        fi
 370
 371        if test $action = skip
 372        then
 373                go_next
 374                continue
 375        fi
 376
 377        if test -x "$GIT_DIR"/hooks/applypatch-msg
 378        then
 379                "$GIT_DIR"/hooks/applypatch-msg "$dotest/final-commit" ||
 380                stop_here $this
 381        fi
 382
 383        echo
 384        echo "Applying '$SUBJECT'"
 385        echo
 386
 387        case "$resolved" in
 388        '')
 389                git-apply $binary --index $ws "$dotest/patch"
 390                apply_status=$?
 391                ;;
 392        t)
 393                # Resolved means the user did all the hard work, and
 394                # we do not have to do any patch application.  Just
 395                # trust what the user has in the index file and the
 396                # working tree.
 397                resolved=
 398                changed="$(git-diff-index --cached --name-only HEAD)"
 399                if test '' = "$changed"
 400                then
 401                        echo "No changes - did you forget to use 'git add'?"
 402                        stop_here_user_resolve $this
 403                fi
 404                unmerged=$(git-ls-files -u)
 405                if test -n "$unmerged"
 406                then
 407                        echo "You still have unmerged paths in your index"
 408                        echo "did you forget to use 'git add'?"
 409                        stop_here_user_resolve $this
 410                fi
 411                apply_status=0
 412                if test -d "$GIT_DIR/rr-cache"
 413                then
 414                        git rerere
 415                fi
 416                ;;
 417        esac
 418
 419        if test $apply_status = 1 && test "$threeway" = t
 420        then
 421                if (fall_back_3way)
 422                then
 423                    # Applying the patch to an earlier tree and merging the
 424                    # result may have produced the same tree as ours.
 425                    changed="$(git-diff-index --cached --name-only HEAD)"
 426                    if test '' = "$changed"
 427                    then
 428                            echo No changes -- Patch already applied.
 429                            go_next
 430                            continue
 431                    fi
 432                    # clear apply_status -- we have successfully merged.
 433                    apply_status=0
 434                fi
 435        fi
 436        if test $apply_status != 0
 437        then
 438                echo Patch failed at $msgnum.
 439                stop_here_user_resolve $this
 440        fi
 441
 442        if test -x "$GIT_DIR"/hooks/pre-applypatch
 443        then
 444                "$GIT_DIR"/hooks/pre-applypatch || stop_here $this
 445        fi
 446
 447        tree=$(git-write-tree) &&
 448        echo Wrote tree $tree &&
 449        parent=$(git-rev-parse --verify HEAD) &&
 450        commit=$(git-commit-tree $tree -p $parent <"$dotest/final-commit") &&
 451        echo Committed: $commit &&
 452        git-update-ref -m "$GIT_REFLOG_ACTION: $SUBJECT" HEAD $commit $parent ||
 453        stop_here $this
 454
 455        if test -x "$GIT_DIR"/hooks/post-applypatch
 456        then
 457                "$GIT_DIR"/hooks/post-applypatch
 458        fi
 459
 460        go_next
 461done
 462
 463rm -fr "$dotest"