git-commit.shon commit Merge branch 'master' of git://git.kernel.org/pub/scm/gitk/gitk (f8db788)
   1#!/bin/sh
   2#
   3# Copyright (c) 2005 Linus Torvalds
   4# Copyright (c) 2006 Junio C Hamano
   5
   6USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [[-i | -o] <path>...]'
   7SUBDIRECTORY_OK=Yes
   8. git-sh-setup
   9require_work_tree
  10
  11git rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
  12
  13case "$0" in
  14*status)
  15        status_only=t
  16        ;;
  17*commit)
  18        status_only=
  19        ;;
  20esac
  21
  22refuse_partial () {
  23        echo >&2 "$1"
  24        echo >&2 "You might have meant to say 'git commit -i paths...', perhaps?"
  25        exit 1
  26}
  27
  28THIS_INDEX="$GIT_DIR/index"
  29NEXT_INDEX="$GIT_DIR/next-index$$"
  30rm -f "$NEXT_INDEX"
  31save_index () {
  32        cp -p "$THIS_INDEX" "$NEXT_INDEX"
  33}
  34
  35run_status () {
  36        # If TMP_INDEX is defined, that means we are doing
  37        # "--only" partial commit, and that index file is used
  38        # to build the tree for the commit.  Otherwise, if
  39        # NEXT_INDEX exists, that is the index file used to
  40        # make the commit.  Otherwise we are using as-is commit
  41        # so the regular index file is what we use to compare.
  42        if test '' != "$TMP_INDEX"
  43        then
  44                GIT_INDEX_FILE="$TMP_INDEX"
  45                export GIT_INDEX_FILE
  46        elif test -f "$NEXT_INDEX"
  47        then
  48                GIT_INDEX_FILE="$NEXT_INDEX"
  49                export GIT_INDEX_FILE
  50        fi
  51
  52        case "$status_only" in
  53        t) color= ;;
  54        *) color=--nocolor ;;
  55        esac
  56        git runstatus ${color} \
  57                ${verbose:+--verbose} \
  58                ${amend:+--amend} \
  59                ${untracked_files:+--untracked}
  60}
  61
  62trap '
  63        test -z "$TMP_INDEX" || {
  64                test -f "$TMP_INDEX" && rm -f "$TMP_INDEX"
  65        }
  66        rm -f "$NEXT_INDEX"
  67' 0
  68
  69################################################################
  70# Command line argument parsing and sanity checking
  71
  72all=
  73also=
  74interactive=
  75only=
  76logfile=
  77use_commit=
  78amend=
  79edit_flag=
  80no_edit=
  81log_given=
  82log_message=
  83verify=t
  84quiet=
  85verbose=
  86signoff=
  87force_author=
  88only_include_assumed=
  89untracked_files=
  90while case "$#" in 0) break;; esac
  91do
  92        case "$1" in
  93        -F|--F|-f|--f|--fi|--fil|--file)
  94                case "$#" in 1) usage ;; esac
  95                shift
  96                no_edit=t
  97                log_given=t$log_given
  98                logfile="$1"
  99                shift
 100                ;;
 101        -F*|-f*)
 102                no_edit=t
 103                log_given=t$log_given
 104                logfile=`expr "z$1" : 'z-[Ff]\(.*\)'`
 105                shift
 106                ;;
 107        --F=*|--f=*|--fi=*|--fil=*|--file=*)
 108                no_edit=t
 109                log_given=t$log_given
 110                logfile=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 111                shift
 112                ;;
 113        -a|--a|--al|--all)
 114                all=t
 115                shift
 116                ;;
 117        --au=*|--aut=*|--auth=*|--autho=*|--author=*)
 118                force_author=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 119                shift
 120                ;;
 121        --au|--aut|--auth|--autho|--author)
 122                case "$#" in 1) usage ;; esac
 123                shift
 124                force_author="$1"
 125                shift
 126                ;;
 127        -e|--e|--ed|--edi|--edit)
 128                edit_flag=t
 129                shift
 130                ;;
 131        -i|--i|--in|--inc|--incl|--inclu|--includ|--include)
 132                also=t
 133                shift
 134                ;;
 135        --int|--inte|--inter|--intera|--interac|--interact|--interacti|\
 136        --interactiv|--interactive)
 137                interactive=t
 138                shift
 139                ;;
 140        -o|--o|--on|--onl|--only)
 141                only=t
 142                shift
 143                ;;
 144        -m|--m|--me|--mes|--mess|--messa|--messag|--message)
 145                case "$#" in 1) usage ;; esac
 146                shift
 147                log_given=m$log_given
 148                if test "$log_message" = ''
 149                then
 150                    log_message="$1"
 151                else
 152                    log_message="$log_message
 153
 154$1"
 155                fi
 156                no_edit=t
 157                shift
 158                ;;
 159        -m*)
 160                log_given=m$log_given
 161                if test "$log_message" = ''
 162                then
 163                    log_message=`expr "z$1" : 'z-m\(.*\)'`
 164                else
 165                    log_message="$log_message
 166
 167`expr "z$1" : 'z-m\(.*\)'`"
 168                fi
 169                no_edit=t
 170                shift
 171                ;;
 172        --m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
 173                log_given=m$log_given
 174                if test "$log_message" = ''
 175                then
 176                    log_message=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 177                else
 178                    log_message="$log_message
 179
 180`expr "z$1" : 'zq-[^=]*=\(.*\)'`"
 181                fi
 182                no_edit=t
 183                shift
 184                ;;
 185        -n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|\
 186        --no-verify)
 187                verify=
 188                shift
 189                ;;
 190        --a|--am|--ame|--amen|--amend)
 191                amend=t
 192                log_given=t$log_given
 193                use_commit=HEAD
 194                shift
 195                ;;
 196        -c)
 197                case "$#" in 1) usage ;; esac
 198                shift
 199                log_given=t$log_given
 200                use_commit="$1"
 201                no_edit=
 202                shift
 203                ;;
 204        --ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\
 205        --reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\
 206        --reedit-messag=*|--reedit-message=*)
 207                log_given=t$log_given
 208                use_commit=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 209                no_edit=
 210                shift
 211                ;;
 212        --ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
 213        --reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|\
 214        --reedit-message)
 215                case "$#" in 1) usage ;; esac
 216                shift
 217                log_given=t$log_given
 218                use_commit="$1"
 219                no_edit=
 220                shift
 221                ;;
 222        -C)
 223                case "$#" in 1) usage ;; esac
 224                shift
 225                log_given=t$log_given
 226                use_commit="$1"
 227                no_edit=t
 228                shift
 229                ;;
 230        --reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\
 231        --reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\
 232        --reuse-message=*)
 233                log_given=t$log_given
 234                use_commit=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 235                no_edit=t
 236                shift
 237                ;;
 238        --reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\
 239        --reuse-mess|--reuse-messa|--reuse-messag|--reuse-message)
 240                case "$#" in 1) usage ;; esac
 241                shift
 242                log_given=t$log_given
 243                use_commit="$1"
 244                no_edit=t
 245                shift
 246                ;;
 247        -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
 248                signoff=t
 249                shift
 250                ;;
 251        -q|--q|--qu|--qui|--quie|--quiet)
 252                quiet=t
 253                shift
 254                ;;
 255        -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
 256                verbose=t
 257                shift
 258                ;;
 259        -u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|\
 260        --untracked|--untracked-|--untracked-f|--untracked-fi|--untracked-fil|\
 261        --untracked-file|--untracked-files)
 262                untracked_files=t
 263                shift
 264                ;;
 265        --)
 266                shift
 267                break
 268                ;;
 269        -*)
 270                usage
 271                ;;
 272        *)
 273                break
 274                ;;
 275        esac
 276done
 277case "$edit_flag" in t) no_edit= ;; esac
 278
 279################################################################
 280# Sanity check options
 281
 282case "$amend,$initial_commit" in
 283t,t)
 284        die "You do not have anything to amend." ;;
 285t,)
 286        if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
 287                die "You are in the middle of a merge -- cannot amend."
 288        fi ;;
 289esac
 290
 291case "$log_given" in
 292tt*)
 293        die "Only one of -c/-C/-F/--amend can be used." ;;
 294*tm*|*mt*)
 295        die "Option -m cannot be combined with -c/-C/-F/--amend." ;;
 296esac
 297
 298case "$#,$also,$only,$amend" in
 299*,t,t,*)
 300        die "Only one of --include/--only can be used." ;;
 3010,t,,* | 0,,t,)
 302        die "No paths with --include/--only does not make sense." ;;
 3030,,t,t)
 304        only_include_assumed="# Clever... amending the last one with dirty index." ;;
 3050,,,*)
 306        ;;
 307*,,,*)
 308        only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
 309        also=
 310        ;;
 311esac
 312unset only
 313case "$all,$interactive,$also,$#" in
 314*t,*t,*)
 315        die "Cannot use -a, --interactive or -i at the same time." ;;
 316t,,[1-9]*)
 317        die "Paths with -a does not make sense." ;;
 318,t,[1-9]*)
 319        die "Paths with --interactive does not make sense." ;;
 320,,t,0)
 321        die "No paths with -i does not make sense." ;;
 322esac
 323
 324################################################################
 325# Prepare index to have a tree to be committed
 326
 327case "$all,$also" in
 328t,)
 329        if test ! -f "$THIS_INDEX"
 330        then
 331                die 'nothing to commit (use "git add file1 file2" to include for commit)'
 332        fi
 333        save_index &&
 334        (
 335                cd_to_toplevel &&
 336                GIT_INDEX_FILE="$NEXT_INDEX" &&
 337                export GIT_INDEX_FILE &&
 338                git diff-files --name-only -z |
 339                git update-index --remove -z --stdin
 340        ) || exit
 341        ;;
 342,t)
 343        save_index &&
 344        git ls-files --error-unmatch -- "$@" >/dev/null || exit
 345
 346        git diff-files --name-only -z -- "$@"  |
 347        (
 348                cd_to_toplevel &&
 349                GIT_INDEX_FILE="$NEXT_INDEX" &&
 350                export GIT_INDEX_FILE &&
 351                git update-index --remove -z --stdin
 352        ) || exit
 353        ;;
 354,)
 355        if test "$interactive" = t; then
 356                git add --interactive || exit
 357        fi
 358        case "$#" in
 359        0)
 360                ;; # commit as-is
 361        *)
 362                if test -f "$GIT_DIR/MERGE_HEAD"
 363                then
 364                        refuse_partial "Cannot do a partial commit during a merge."
 365                fi
 366                TMP_INDEX="$GIT_DIR/tmp-index$$"
 367                commit_only=`git ls-files --error-unmatch -- "$@"` || exit
 368
 369                # Build a temporary index and update the real index
 370                # the same way.
 371                if test -z "$initial_commit"
 372                then
 373                        GIT_INDEX_FILE="$THIS_INDEX" \
 374                        git read-tree --index-output="$TMP_INDEX" -i -m HEAD
 375                else
 376                        rm -f "$TMP_INDEX"
 377                fi || exit
 378
 379                printf '%s\n' "$commit_only" |
 380                GIT_INDEX_FILE="$TMP_INDEX" \
 381                git update-index --add --remove --stdin &&
 382
 383                save_index &&
 384                printf '%s\n' "$commit_only" |
 385                (
 386                        GIT_INDEX_FILE="$NEXT_INDEX"
 387                        export GIT_INDEX_FILE
 388                        git update-index --remove --stdin
 389                ) || exit
 390                ;;
 391        esac
 392        ;;
 393esac
 394
 395################################################################
 396# If we do as-is commit, the index file will be THIS_INDEX,
 397# otherwise NEXT_INDEX after we make this commit.  We leave
 398# the index as is if we abort.
 399
 400if test -f "$NEXT_INDEX"
 401then
 402        USE_INDEX="$NEXT_INDEX"
 403else
 404        USE_INDEX="$THIS_INDEX"
 405fi
 406
 407case "$status_only" in
 408t)
 409        # This will silently fail in a read-only repository, which is
 410        # what we want.
 411        GIT_INDEX_FILE="$USE_INDEX" git update-index -q --unmerged --refresh
 412        run_status
 413        exit $?
 414        ;;
 415'')
 416        GIT_INDEX_FILE="$USE_INDEX" git update-index -q --refresh || exit
 417        ;;
 418esac
 419
 420################################################################
 421# Grab commit message, write out tree and make commit.
 422
 423if test t = "$verify" && test -x "$GIT_DIR"/hooks/pre-commit
 424then
 425        if test "$TMP_INDEX"
 426        then
 427                GIT_INDEX_FILE="$TMP_INDEX" "$GIT_DIR"/hooks/pre-commit
 428        else
 429                GIT_INDEX_FILE="$USE_INDEX" "$GIT_DIR"/hooks/pre-commit
 430        fi || exit
 431fi
 432
 433if test "$log_message" != ''
 434then
 435        printf '%s\n' "$log_message"
 436elif test "$logfile" != ""
 437then
 438        if test "$logfile" = -
 439        then
 440                test -t 0 &&
 441                echo >&2 "(reading log message from standard input)"
 442                cat
 443        else
 444                cat <"$logfile"
 445        fi
 446elif test "$use_commit" != ""
 447then
 448        encoding=$(git config i18n.commitencoding || echo UTF-8)
 449        git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
 450        sed -e '1,/^$/d' -e 's/^    //'
 451elif test -f "$GIT_DIR/MERGE_MSG"
 452then
 453        cat "$GIT_DIR/MERGE_MSG"
 454elif test -f "$GIT_DIR/SQUASH_MSG"
 455then
 456        cat "$GIT_DIR/SQUASH_MSG"
 457fi | git stripspace >"$GIT_DIR"/COMMIT_EDITMSG
 458
 459case "$signoff" in
 460t)
 461        sign=$(git-var GIT_COMMITTER_IDENT | sed -e '
 462                s/>.*/>/
 463                s/^/Signed-off-by: /
 464                ')
 465        blank_before_signoff=
 466        tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
 467        grep 'Signed-off-by:' >/dev/null || blank_before_signoff='
 468'
 469        tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
 470        grep "$sign"$ >/dev/null ||
 471        printf '%s%s\n' "$blank_before_signoff" "$sign" \
 472                >>"$GIT_DIR"/COMMIT_EDITMSG
 473        ;;
 474esac
 475
 476if test -f "$GIT_DIR/MERGE_HEAD" && test -z "$no_edit"; then
 477        echo "#"
 478        echo "# It looks like you may be committing a MERGE."
 479        echo "# If this is not correct, please remove the file"
 480        printf '%s\n' "#        $GIT_DIR/MERGE_HEAD"
 481        echo "# and try again"
 482        echo "#"
 483fi >>"$GIT_DIR"/COMMIT_EDITMSG
 484
 485# Author
 486if test '' != "$use_commit"
 487then
 488        eval "$(get_author_ident_from_commit "$use_commit")"
 489        export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
 490fi
 491if test '' != "$force_author"
 492then
 493        GIT_AUTHOR_NAME=`expr "z$force_author" : 'z\(.*[^ ]\) *<.*'` &&
 494        GIT_AUTHOR_EMAIL=`expr "z$force_author" : '.*\(<.*\)'` &&
 495        test '' != "$GIT_AUTHOR_NAME" &&
 496        test '' != "$GIT_AUTHOR_EMAIL" ||
 497        die "malformed --author parameter"
 498        export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
 499fi
 500
 501PARENTS="-p HEAD"
 502if test -z "$initial_commit"
 503then
 504        rloga='commit'
 505        if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
 506                rloga='commit (merge)'
 507                PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
 508        elif test -n "$amend"; then
 509                rloga='commit (amend)'
 510                PARENTS=$(git cat-file commit HEAD |
 511                        sed -n -e '/^$/q' -e 's/^parent /-p /p')
 512        fi
 513        current="$(git rev-parse --verify HEAD)"
 514else
 515        if [ -z "$(git ls-files)" ]; then
 516                echo >&2 'nothing to commit (use "git add file1 file2" to include for commit)'
 517                exit 1
 518        fi
 519        PARENTS=""
 520        rloga='commit (initial)'
 521        current=''
 522fi
 523set_reflog_action "$rloga"
 524
 525if test -z "$no_edit"
 526then
 527        {
 528                echo ""
 529                echo "# Please enter the commit message for your changes."
 530                echo "# (Comment lines starting with '#' will not be included)"
 531                test -z "$only_include_assumed" || echo "$only_include_assumed"
 532                run_status
 533        } >>"$GIT_DIR"/COMMIT_EDITMSG
 534else
 535        # we need to check if there is anything to commit
 536        run_status >/dev/null
 537fi
 538if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" -a -z "$amend" ]
 539then
 540        rm -f "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
 541        run_status
 542        exit 1
 543fi
 544
 545case "$no_edit" in
 546'')
 547        case "${VISUAL:-$EDITOR},$TERM" in
 548        ,dumb)
 549                echo >&2 "Terminal is dumb but no VISUAL nor EDITOR defined."
 550                echo >&2 "Please supply the commit log message using either"
 551                echo >&2 "-m or -F option.  A boilerplate log message has"
 552                echo >&2 "been prepared in $GIT_DIR/COMMIT_EDITMSG"
 553                exit 1
 554                ;;
 555        esac
 556        git-var GIT_AUTHOR_IDENT > /dev/null  || die
 557        git-var GIT_COMMITTER_IDENT > /dev/null  || die
 558        ${VISUAL:-${EDITOR:-vi}} "$GIT_DIR/COMMIT_EDITMSG"
 559        ;;
 560esac
 561
 562case "$verify" in
 563t)
 564        if test -x "$GIT_DIR"/hooks/commit-msg
 565        then
 566                "$GIT_DIR"/hooks/commit-msg "$GIT_DIR"/COMMIT_EDITMSG || exit
 567        fi
 568esac
 569
 570if test -z "$no_edit"
 571then
 572    sed -e '
 573        /^diff --git a\/.*/{
 574            s///
 575            q
 576        }
 577        /^#/d
 578    ' "$GIT_DIR"/COMMIT_EDITMSG
 579else
 580    cat "$GIT_DIR"/COMMIT_EDITMSG
 581fi |
 582git stripspace >"$GIT_DIR"/COMMIT_MSG
 583
 584if cnt=`grep -v -i '^Signed-off-by' "$GIT_DIR"/COMMIT_MSG |
 585        git stripspace |
 586        wc -l` &&
 587   test 0 -lt $cnt
 588then
 589        if test -z "$TMP_INDEX"
 590        then
 591                tree=$(GIT_INDEX_FILE="$USE_INDEX" git write-tree)
 592        else
 593                tree=$(GIT_INDEX_FILE="$TMP_INDEX" git write-tree) &&
 594                rm -f "$TMP_INDEX"
 595        fi &&
 596        commit=$(cat "$GIT_DIR"/COMMIT_MSG | git commit-tree $tree $PARENTS) &&
 597        rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
 598        git update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" &&
 599        rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
 600        if test -f "$NEXT_INDEX"
 601        then
 602                mv "$NEXT_INDEX" "$THIS_INDEX"
 603        else
 604                : ;# happy
 605        fi
 606else
 607        echo >&2 "* no commit message?  aborting commit."
 608        false
 609fi
 610ret="$?"
 611rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
 612
 613cd_to_toplevel
 614
 615git rerere
 616
 617if test "$ret" = 0
 618then
 619        if test -x "$GIT_DIR"/hooks/post-commit
 620        then
 621                "$GIT_DIR"/hooks/post-commit
 622        fi
 623        if test -z "$quiet"
 624        then
 625                commit=`git diff-tree --always --shortstat --pretty="format:%h: %s"\
 626                       --summary --root HEAD --`
 627                echo "Created${initial_commit:+ initial} commit $commit"
 628        fi
 629fi
 630
 631exit "$ret"