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