git-commit.shon commit Merge git://git.kernel.org/pub/scm/gitk/gitk (90768da)
   1#!/bin/sh
   2#
   3# Copyright (c) 2005 Linus Torvalds
   4# Copyright (c) 2006 Junio C Hamano
   5
   6USAGE='[-a] [-i] [-s] [-v | --no-verify]  [-m <message> | -F <logfile> | (-C|-c) <commit>] [-e] [--author <author>] [<path>...]'
   7
   8SUBDIRECTORY_OK=Yes
   9. git-sh-setup
  10
  11git-rev-parse --verify HEAD >/dev/null 2>&1 ||
  12initial_commit=t
  13
  14refuse_partial () {
  15        echo >&2 "$1"
  16        echo >&2 "You might have meant to say 'git commit -i paths...', perhaps?"
  17        exit 1
  18}
  19
  20SAVE_INDEX="$GIT_DIR/save-index$$"
  21save_index () {
  22        cp "$GIT_DIR/index" "$SAVE_INDEX"
  23}
  24
  25run_status () {
  26        (
  27                cd "$TOP"
  28                if test '' != "$TMP_INDEX"
  29                then
  30                        GIT_INDEX_FILE="$TMP_INDEX" git-status
  31                else
  32                        git-status
  33                fi
  34        )
  35}
  36
  37all=
  38also=
  39only=
  40logfile=
  41use_commit=
  42no_edit=
  43log_given=
  44log_message=
  45verify=t
  46signoff=
  47force_author=
  48while case "$#" in 0) break;; esac
  49do
  50  case "$1" in
  51  -F|--F|-f|--f|--fi|--fil|--file)
  52      case "$#" in 1) usage ;; esac
  53      shift
  54      no_edit=t
  55      log_given=t$log_given
  56      logfile="$1"
  57      shift
  58      ;;
  59  -F*|-f*)
  60      no_edit=t
  61      log_given=t$log_given
  62      logfile=`expr "$1" : '-[Ff]\(.*\)'`
  63      shift
  64      ;;
  65  --F=*|--f=*|--fi=*|--fil=*|--file=*)
  66      no_edit=t
  67      log_given=t$log_given
  68      logfile=`expr "$1" : '-[^=]*=\(.*\)'`
  69      shift
  70      ;;
  71  -a|--a|--al|--all)
  72      all=t
  73      shift
  74      ;;
  75  --au=*|--aut=*|--auth=*|--autho=*|--author=*)
  76      force_author=`expr "$1" : '-[^=]*=\(.*\)'`
  77      shift
  78      ;;
  79  --au|--aut|--auth|--autho|--author)
  80      case "$#" in 1) usage ;; esac
  81      shift
  82      force_author="$1"
  83      shift
  84      ;;
  85  -e|--e|--ed|--edi|--edit)
  86      no_edit=
  87      shift
  88      ;;
  89  -i|--i|--in|--inc|--incl|--inclu|--includ|--include)
  90      also=t
  91      shift
  92      ;;
  93  -o|--o|--on|--onl|--only)
  94      only=t
  95      shift
  96      ;;
  97  -m|--m|--me|--mes|--mess|--messa|--messag|--message)
  98      case "$#" in 1) usage ;; esac
  99      shift
 100      log_given=t$log_given
 101      log_message="$1"
 102      no_edit=t
 103      shift
 104      ;;
 105  -m*)
 106      log_given=t$log_given
 107      log_message=`expr "$1" : '-m\(.*\)'`
 108      no_edit=t
 109      shift
 110      ;;
 111  --m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
 112      log_given=t$log_given
 113      log_message=`expr "$1" : '-[^=]*=\(.*\)'`
 114      no_edit=t
 115      shift
 116      ;;
 117  -n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|--no-verify)
 118      verify=
 119      shift
 120      ;;
 121  -c)
 122      case "$#" in 1) usage ;; esac
 123      shift
 124      log_given=t$log_given
 125      use_commit="$1"
 126      no_edit=
 127      shift
 128      ;;
 129  --ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\
 130  --reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\
 131  --reedit-messag=*|--reedit-message=*)
 132      log_given=t$log_given
 133      use_commit=`expr "$1" : '-[^=]*=\(.*\)'`
 134      no_edit=
 135      shift
 136      ;;
 137  --ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
 138  --reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|--reedit-message)
 139      case "$#" in 1) usage ;; esac
 140      shift
 141      log_given=t$log_given
 142      use_commit="$1"
 143      no_edit=
 144      shift
 145      ;;
 146  -C)
 147      case "$#" in 1) usage ;; esac
 148      shift
 149      log_given=t$log_given
 150      use_commit="$1"
 151      no_edit=t
 152      shift
 153      ;;
 154  --reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\
 155  --reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\
 156  --reuse-message=*)
 157      log_given=t$log_given
 158      use_commit=`expr "$1" : '-[^=]*=\(.*\)'`
 159      no_edit=t
 160      shift
 161      ;;
 162  --reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\
 163  --reuse-mess|--reuse-messa|--reuse-messag|--reuse-message)
 164      case "$#" in 1) usage ;; esac
 165      shift
 166      log_given=t$log_given
 167      use_commit="$1"
 168      no_edit=t
 169      shift
 170      ;;
 171  -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
 172      signoff=t
 173      shift
 174      ;;
 175  -v|--v|--ve|--ver|--veri|--verif|--verify)
 176      verify=t
 177     shift
 178      ;;
 179  --)
 180      shift
 181      break
 182      ;;
 183  -*)
 184      usage
 185      ;;
 186  *)
 187      break
 188      ;;
 189  esac
 190done
 191
 192case "$log_given" in
 193tt*)
 194  die "Only one of -c/-C/-F/-m can be used." ;;
 195esac
 196
 197case "$#,$also$only" in
 198*,tt)
 199  die "Only one of --include/--only can be used." ;;
 2000,t)
 201  die "No paths with --include/--only does not make sense." ;;
 2020,)
 203  ;;
 204*,)
 205  echo >&2 "assuming --include paths..."
 206  also=t
 207  # Later when switch the defaults, we will replace them with these:
 208  # echo >&2 "assuming --only paths..."
 209  # also=
 210  ;;
 211esac
 212unset only
 213
 214TOP=`git-rev-parse --show-cdup`
 215if test -z "$TOP"
 216then
 217        TOP=./
 218fi
 219
 220case "$all,$also" in
 221t,t)
 222        die "Cannot use -a and -i at the same time." ;;
 223t,)
 224        case "$#" in
 225        0) ;;
 226        *) die "Paths with -a does not make sense." ;;
 227        esac
 228
 229        save_index &&
 230        (
 231                cd "$TOP"
 232                git-diff-files --name-only -z |
 233                git-update-index --remove -z --stdin
 234        )
 235        ;;
 236,t)
 237        case "$#" in
 238        0) die "No paths with -i does not make sense." ;;
 239        esac
 240
 241        save_index &&
 242        git-diff-files --name-only -z -- "$@"  |
 243        (cd "$TOP" && git-update-index --remove -z --stdin)
 244        ;;
 245,)
 246        case "$#" in
 247        0)
 248            ;; # commit as-is
 249        *)
 250            if test -f "$GIT_DIR/MERGE_HEAD"
 251            then
 252                refuse_partial "Cannot do a partial commit during a merge."
 253            fi
 254            TMP_INDEX="$GIT_DIR/tmp-index$$"
 255            if test -z "$initial_commit"
 256            then
 257                # make sure index is clean at the specified paths, or
 258                # they are additions.
 259                dirty_in_index=`git-diff-index --cached --name-status \
 260                        --diff-filter=DMTU HEAD -- "$@"`
 261                test -z "$dirty_in_index" ||
 262                refuse_partial "Different in index and the last commit:
 263$dirty_in_index"
 264            fi
 265            commit_only=`git-ls-files -- "$@"` ;;
 266        esac
 267        ;;
 268esac
 269
 270git-update-index -q --refresh || exit 1
 271
 272trap '
 273        test -z "$TMP_INDEX" || {
 274                test -f "$TMP_INDEX" && rm -f "$TMP_INDEX"
 275        }
 276        test -f "$SAVE_INDEX" && mv -f "$SAVE_INDEX" "$GIT_DIR/index"
 277' 0
 278
 279if test "$TMP_INDEX"
 280then
 281        if test -z "$initial_commit"
 282        then
 283                GIT_INDEX_FILE="$TMP_INDEX" git-read-tree HEAD
 284        else
 285                rm -f "$TMP_INDEX"
 286        fi || exit
 287        echo "$commit_only" |
 288        GIT_INDEX_FILE="$TMP_INDEX" git-update-index --add --remove --stdin &&
 289        save_index &&
 290        echo "$commit_only" |
 291        git-update-index --remove --stdin ||
 292        exit
 293fi
 294
 295if test t = "$verify" && test -x "$GIT_DIR"/hooks/pre-commit
 296then
 297        if test "$TMP_INDEX"
 298        then
 299                GIT_INDEX_FILE="$TMP_INDEX" "$GIT_DIR"/hooks/pre-commit
 300        else
 301                "$GIT_DIR"/hooks/pre-commit
 302        fi || exit
 303fi
 304
 305if test "$log_message" != ''
 306then
 307        echo "$log_message"
 308elif test "$logfile" != ""
 309then
 310        if test "$logfile" = -
 311        then
 312                test -t 0 &&
 313                echo >&2 "(reading log message from standard input)"
 314                cat
 315        else
 316                cat <"$logfile"
 317        fi
 318elif test "$use_commit" != ""
 319then
 320        git-cat-file commit "$use_commit" | sed -e '1,/^$/d'
 321elif test -f "$GIT_DIR/MERGE_HEAD" && test -f "$GIT_DIR/MERGE_MSG"
 322then
 323        cat "$GIT_DIR/MERGE_MSG"
 324fi | git-stripspace >"$GIT_DIR"/COMMIT_EDITMSG
 325
 326case "$signoff" in
 327t)
 328        {
 329                echo
 330                git-var GIT_COMMITTER_IDENT | sed -e '
 331                        s/>.*/>/
 332                        s/^/Signed-off-by: /
 333                '
 334        } >>"$GIT_DIR"/COMMIT_EDITMSG
 335        ;;
 336esac
 337
 338if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
 339        echo "#"
 340        echo "# It looks like you may be committing a MERGE."
 341        echo "# If this is not correct, please remove the file"
 342        echo "# $GIT_DIR/MERGE_HEAD"
 343        echo "# and try again"
 344        echo "#"
 345fi >>"$GIT_DIR"/COMMIT_EDITMSG
 346
 347# Author
 348if test '' != "$force_author"
 349then
 350        GIT_AUTHOR_NAME=`expr "$force_author" : '\(.*[^ ]\) *<.*'` &&
 351        GIT_AUTHOR_EMAIL=`expr "$force_author" : '.*\(<.*\)'` &&
 352        test '' != "$GIT_AUTHOR_NAME" &&
 353        test '' != "$GIT_AUTHOR_EMAIL" ||
 354        die "malformatted --author parameter"
 355        export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
 356elif test '' != "$use_commit"
 357then
 358        pick_author_script='
 359        /^author /{
 360                s/'\''/'\''\\'\'\''/g
 361                h
 362                s/^author \([^<]*\) <[^>]*> .*$/\1/
 363                s/'\''/'\''\'\'\''/g
 364                s/.*/GIT_AUTHOR_NAME='\''&'\''/p
 365
 366                g
 367                s/^author [^<]* <\([^>]*\)> .*$/\1/
 368                s/'\''/'\''\'\'\''/g
 369                s/.*/GIT_AUTHOR_EMAIL='\''&'\''/p
 370
 371                g
 372                s/^author [^<]* <[^>]*> \(.*\)$/\1/
 373                s/'\''/'\''\'\'\''/g
 374                s/.*/GIT_AUTHOR_DATE='\''&'\''/p
 375
 376                q
 377        }
 378        '
 379        set_author_env=`git-cat-file commit "$use_commit" |
 380        LANG=C LC_ALL=C sed -ne "$pick_author_script"`
 381        eval "$set_author_env"
 382        export GIT_AUTHOR_NAME
 383        export GIT_AUTHOR_EMAIL
 384        export GIT_AUTHOR_DATE
 385fi
 386
 387PARENTS="-p HEAD"
 388if test -z "$initial_commit"
 389then
 390        if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
 391                PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
 392        fi
 393else
 394        if [ -z "$(git-ls-files)" ]; then
 395                echo >&2 Nothing to commit
 396                exit 1
 397        fi
 398        PARENTS=""
 399fi
 400
 401
 402run_status >>"$GIT_DIR"/COMMIT_EDITMSG
 403if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" ]
 404then
 405        rm -f "$GIT_DIR/COMMIT_EDITMSG"
 406        run_status
 407        exit 1
 408fi
 409case "$no_edit" in
 410'')
 411        case "${VISUAL:-$EDITOR},$TERM" in
 412        ,dumb)
 413                echo >&2 "Terminal is dumb but no VISUAL nor EDITOR defined."
 414                echo >&2 "Please supply the commit log message using either"
 415                echo >&2 "-m or -F option.  A boilerplate log message has"
 416                echo >&2 "been prepared in $GIT_DIR/COMMIT_EDITMSG"
 417                exit 1
 418                ;;
 419        esac
 420        ${VISUAL:-${EDITOR:-vi}} "$GIT_DIR/COMMIT_EDITMSG"
 421        ;;
 422esac
 423
 424case "$verify" in
 425t)
 426        if test -x "$GIT_DIR"/hooks/commit-msg
 427        then
 428                "$GIT_DIR"/hooks/commit-msg "$GIT_DIR"/COMMIT_EDITMSG || exit
 429        fi
 430esac
 431
 432grep -v '^#' < "$GIT_DIR"/COMMIT_EDITMSG |
 433git-stripspace > "$GIT_DIR"/COMMIT_MSG
 434
 435if cnt=`grep -v -i '^Signed-off-by' "$GIT_DIR"/COMMIT_MSG |
 436        git-stripspace |
 437        wc -l` &&
 438   test 0 -lt $cnt
 439then
 440        if test -z "$TMP_INDEX"
 441        then
 442                tree=$(git-write-tree)
 443        else
 444                tree=$(GIT_INDEX_FILE="$TMP_INDEX" git-write-tree) &&
 445                rm -f "$TMP_INDEX"
 446        fi &&
 447        commit=$(cat "$GIT_DIR"/COMMIT_MSG | git-commit-tree $tree $PARENTS) &&
 448        git-update-ref HEAD $commit $current &&
 449        rm -f -- "$GIT_DIR/MERGE_HEAD"
 450else
 451        echo >&2 "* no commit message?  aborting commit."
 452        false
 453fi
 454ret="$?"
 455rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG"
 456git-rerere
 457
 458if test -x "$GIT_DIR"/hooks/post-commit && test "$ret" = 0
 459then
 460        "$GIT_DIR"/hooks/post-commit
 461fi
 462if test 0 -eq "$ret"
 463then
 464        rm -f "$SAVE_INDEX"
 465fi
 466exit "$ret"