3 # A hook script to check the commit log message to ensure that it has
4 # a well-formed commit summary and body, a valid Signed-off-by: line,
5 # and a Gerrit Change-Id: line (added automatically if missing).
7 # Called by git-commit with one argument, the name of the file
8 # that has the commit message. The hook should exit with non-zero
9 # status after issuing an appropriate message if it wants to stop the
10 # commit. The hook is allowed to edit the commit message file.
12 # Should be installed as .git/hooks/commit-msg.
16 REVISED="$(mktemp "$ORIGINAL.XXXXXX")"
17 SAVE="$(basename $ORIGINAL).$(date +%Y%m%d.%H%M%S)"
18 SIGNOFF="Signed-off-by"
23 # Check for, and add if missing, a unique Change-Id
26 git var GIT_AUTHOR_IDENT
27 git var GIT_COMMITTER_IDENT
29 git rev-parse HEAD 2>/dev/null
30 grep -v "^$SIGNOFF" "$ORIGINAL" | git stripspace -s
31 } | git hash-object --stdin)
32 if [ -z "$NEWID" ]; then
33 error "$0: git hash-object failed for $CHANGEID:"
37 echo "$CHANGEID: I$NEWID"
42 [ "$LINE" ] && echo "line $NUM: $LINE" 1>&2
43 [ "$1" ] && echo "error: commit message $1" 1>&2
44 [ "$2" ] && echo "$2" 1>&2
52 See http://wiki.whamcloud.com/display/PUB/Commit+Comments
53 for full details. An example valid commit comment is:
55 LU-nnn component: short description of change under 64 columns
57 The "component:" should be a lower-case single-word subsystem of the
58 Lustre code that best encompasses the change being made. Examples of
59 components include modules like: llite, lov, lmv, osc, mdc, ldlm, lnet,
60 ptlrpc, mds, oss, osd, ldiskfs, libcfs, socklnd, o2iblnd; functional
61 subsystems like: recovery, quota, grant; and auxilliary areas like:
62 build, tests, docs. This list is not exhaustive, but is a guideline.
64 The commit comment should contain a detailed explanation of the change
65 being made. This can be as long as you'd like. Please give details
66 of what problem was solved (including error messages or problems that
67 were seen), a good high-level description of how it was solved, and
68 which parts of the code were changed (including important functions
69 that were changed, if this is useful to understand the patch, and
70 for easier searching). Wrap lines at/under $WIDTH_REG columns.
72 $SIGNOFF: Your Real Name <your_email@domain.name>
73 $CHANGEID: Ixxxx(added automatically if missing)xxxx
77 mv "$ORIGINAL" "$SAVE" &&
78 echo "$0: saved original commit comment to $SAVE" 1>&2
81 export HAS_ERROR=false
82 export HAS_SUMMARY=false
83 export HAS_LAST_BLANK=false
85 export HAS_SIGNOFF=false
86 case $(grep -c "^$CHANGEID:" "$ORIGINAL") in
87 0) export HAS_CHANGEID=false ;;
88 1) export HAS_CHANGEID=true ;;
89 *) error "with multiple $CHANGEID: lines not allowed."
90 export HAS_CHANGEID=true
93 export HAS_COMMENTS=false
99 IFS="" # don't eat whitespace, to preserve message formatting
101 WIDTH=$(($(echo $LINE | wc -c) - 1)) # -1 for end-of-line character
105 # Signed-off-by: First Last <email@host.domain>
106 HAS_SOB=$(echo "$LINE" | grep "^$SIGNOFF: .* .* <.*@[^.]*\..*>")
107 if [ -z "$HAS_SOB" ]; then
108 error "missing valid commit summary line to show" \
109 "agreement with code submission requirements."
110 elif ! $HAS_SUMMARY; then
111 error "missing summary before $SIGNOFF:."
112 elif ! $HAS_LAST_BLANK; then
113 error "missing blank line before $SIGNOFF:."
114 elif ! $HAS_BODY; then
115 error "missing useful comments before $SIGNOFF:."
117 HAS_SIGNOFF=true # allow multiple signoff lines
120 ! $HAS_CHANGEID && new_changeid
123 # Change-Id: I762ab50568f25527176ae54e92c446cf06112097
124 HAS_ID=$(echo "$LINE" | grep "^$CHANGEID: I[0-9a-fA-F]\{40\}")
125 if [ -z "$HAS_ID" ]; then
126 error "has invalid $CHANGEID: line for Gerrit tracking"
127 elif ! $HAS_SUMMARY; then
128 error "missing summary before $CHANGEID:."
129 elif ! $HAS_BODY; then
130 error "missing useful comments before $CHANGEID:."
132 # $CHANGEID used to come before $SIGNOFF in old commits.
133 # Allow this to continue for some time, until they are gone.
134 # elif ! $HAS_SIGNOFF; then
135 # error "missing $SIGNOFF: before $CHANGEID:."
137 # $HAS_CHANGEID was already checked and set above
138 #elif $HAS_CHANGEID; then
139 # error "does not allow multiple $CHANGEID: lines."
146 [ $HAS_SUMMARY -a ! $HAS_BODY ] && HAS_LAST_BLANK=true
147 [ $HAS_BODY ] && HAS_LAST_BLANK=true
151 # Beginning of uncommented diffstat from "commit -v". If
152 # there are diff and index lines, skip the rest of the input.
153 # diff --git a/build/commit-msg b/build/commit-msg
154 # index 80a3442..acb4c50 100755
155 DIFF=$(echo "$LINE" | grep -- "^diff --git a/")
156 [ "$DIFF" ] && HAS_DIFF=true && continue
157 INDEX=$(echo "$LINE" | grep -- "^index [0-9a-fA-F]\{6,\}\.\.")
158 [ $HAS_DIFF -a "$INDEX" ] && break || HAS_DIFF=false
164 *) if [ $NUM -eq 1 ]; then
165 FMT="^[A-Z]\{2,5\}-[0-9]\{1,5\} [-a-z0-9]\{2,9\}: "
166 HAS_JIRA_COMPONENT=$(echo "$LINE" | grep "$FMT")
167 if [ -z "$HAS_JIRA_COMPONENT" ]; then
168 FMT="^[A-Z]\{2,5\}-[0-9]\{1,5\} "
169 HAS_JIRA=$(echo "$LINE" | grep "$FMT")
170 if [ "$HAS_JIRA" ]; then
171 error "has no component in summary."
173 error "missing JIRA ticket number."
175 elif [ $WIDTH -gt $WIDTH_SUM ]; then
176 error "summary longer than $WIDTH_SUM columns."
180 elif $HAS_SIGNOFF; then
181 error "trailing garbage after $SIGNOFF: line."
182 elif [ $WIDTH -gt $WIDTH_REG ]; then
183 error "has line longer than $WIDTH_REG columns."
184 elif ! $HAS_BODY && ! $HAS_LAST_BLANK; then
185 error "has no blank line after summary."
196 done < "$ORIGINAL" > "$REVISED"
198 [ $NUM -eq 1 ] && exit 1 # empty file
201 if ! $HAS_SUMMARY; then
202 error "missing commit summary line."
203 elif ! $HAS_BODY; then
204 error "missing commit description."
205 elif ! $HAS_SIGNOFF; then
206 error "missing valid $SIGNOFF: line."
207 elif ! $HAS_CHANGEID; then
208 error "missing valid $CHANGEID: line."
216 mv "$REVISED" "$ORIGINAL"