Code

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