gitchangelog.sh: update to version 1.3
[archives2git.git] / gitchangelog.sh
blob92dd6dbed0a43fd159deda717e8751daa9f1cd8e
1 #!/bin/sh
2 # Copyright © 2013,2014 Géraud Meyer <graud@gmx.com>
4 # This program is free software; you can redistribute it and/or modify it under
5 # the terms of the GNU General Public License version 2 as published by the
6 # Free Software Foundation.
8 # This program is distributed in the hope that it will be useful, but WITHOUT
9 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11 # details.
13 # You should have received a copy of the GNU General Public License along with
14 # this program. If not, see <http://www.gnu.org/licenses/>.
16 PROGRAM_NAME="gitchangelog.sh"
17 PROGRAM_VERSION="1.3"
18 help_usage () {
19 cat <<"HelpMessage"
20 Name
21 gitchangelog.sh - portable script generating a GNU-like changelog from a Git log
22 Usage
23 gitchangelog.sh [<options>] [--] [ {-|<outfile>} [<git_log_args>] ]
24 gitchangelog.sh [<options>] [--] {-|<outfile>} -
25 Options
26 --tags
27 Prepend changelog entries by tag names in brackets.
28 --tag-pattern <sed_BRE>
29 Tags to consider for marking entries. The pattern should not match
30 across spaces; the default is "[^ ]\{1,\}".
31 --merge
32 Prepend changelog entries by merge marks.
33 --title-only
34 Only keep the title of a commit. This implies --title-star, that can
35 be disabled by a supplemental --git-body.
36 --title-star
37 Prepend the title by a star as is done with the other paragraphs.
38 --git-body
39 Do not reformat the commit message, only reindent it.
40 --no-blankline
41 Do not separate the title from the rest by a blank line.
42 --version
43 --help, --helpm
44 HelpMessage
46 help_message () {
47 help_usage
48 cat <<"HelpMessage"
49 Description
50 Each commit message is made into a changelog entry. Each paragraph of a
51 Git commit message body is made into a star item of the changelog. The
52 message title is kept on a separate line. Text lines are never broken nor
53 joined.
55 By default git is run to get the log, with the required options. If a dash
56 is given in place of additional <git_log_args>, then the log is read from
57 the standard input; in that case pass the option --date=short and possibly
58 also --decorate to git to get the appropriate log format.
59 Portability
60 The script is portable to POSIX sh and to other less comformant shells such
61 as pdksh.
63 The sed code is portable to POSIX sed but requires only Simple Regular
64 Expressions (SRE) instead of Basic Regular Expressions (BRE) which makes it
65 prone to work under Solaris and old BSDs. git-log is required if the log
66 is not read from stdin.
67 Exit Status
68 The exit status of sed is returned if it fails; otherwise the one of the
69 command generating the git log (git or cat) is returned.
70 Examples
71 $ ./gitchangelog.sh --title-star --no-blankline GNUChangeLog
72 $ ./gitchangelog.sh --tags --tag-pattern 'release\/[^ ]*' -- - --date-order |
73 sed 's/^\[release/^L\[release/' > ChangeLog
74 $ git log --date=short --decorate --first-parent |
75 ./gitchangelog.sh --merge ChangeLog -
76 Author
77 gitchangelog.sh was written by G.raud Meyer.
78 See also
79 git-log(1)
80 HelpMessage
83 # parameters
84 GITBODY= NO_GITBODY=yes
85 BLANKLINE=yes
86 TAGS=
87 TAG_PATTERN='[^ ]\+'
88 MERGE=
89 TITLE= NO_TITLE=yes
90 TITLESTAR=
91 while [ $# -gt 0 ]
93 case $1 in
94 --tags)
95 TAGS=yes ;;
96 --tag-pattern)
97 shift; TAG_PATTERN=${1-} ;;
98 --merge)
99 MERGE=yes ;;
100 --title-only)
101 TITLE=yes NO_TITLE= TITLESTAR=yes ;;
102 --title-star)
103 TITLESTAR=yes ;;
104 --git-body)
105 GITBODY=yes NO_GITBODY= ;;
106 --no-blankline)
107 BLANKLINE= ;;
108 --version)
109 echo "$PROGRAM_NAME version $PROGRAM_VERSION"
110 exit ;;
111 --help)
112 help_usage; exit ;;
113 --helpm)
114 help_message; exit ;;
115 --?*)
116 echo "$0: unknown option $1" >&2
117 exit 255 ;;
119 shift; break ;;
121 break ;;
122 esac
123 shift
124 done
125 ANNOTATE=
126 [ -n "$TAGS" ] || [ -n "$MERGE" ] && ANNOTATE=yes
127 # git repository check
128 test x"${2-}" != x"-" &&
129 if test -d .git || git rev-parse --git-dir >/dev/null
130 then :
131 else
132 echo >&2 "$0: ERROR not in a git repository"
133 exit 254
135 # output file
136 if test $# -gt 0
137 then
138 test x"${1-}" != x"-" &&
139 exec >"$1"
140 shift
143 # input source
144 B='{' b='}'
145 s='\'
146 # Some shells, like the family of pdksh, behave differently regarding
147 # the backslash in variable substitutions inside a here document.
148 NL='
150 # pdksh and posh do not keep a newline preceded by a backslash inside a
151 # single quoted string inside two levels of command substitution (when the
152 # second level is double quoted).
153 exec 4>&1 # to pass stdout to the following process substitution
154 eval "$( exec 3>&1 1>&4 4>&- # eval will set $gitrc and $rc
155 if test x"${1-}" = x"-"
156 then cat; echo >&3 gitrc=$?
157 else git log --date=short ${ANNOTATE:+--decorate} ${1+"$@"}; echo >&3 gitrc=$?
158 fi |
159 # processing
160 LC_ALL=C sed -e "$(# Transform the GNU sed program into a more portable one
161 LC_ALL=C sed -e 's/\\s/[ \\t]/g
162 s/\\+/\\{1,\\}/g
163 s/; /\'"$NL"'/g
164 s/@n/\\\'"$NL"'/g
165 s/\\t/ /g
166 s/^ *#/#/' <<EOF
167 # Put the tags in the hold space
168 /^commit / {
169 # parse the refs
170 s/^commit [a-zA-Z0-9]\+//; s/^ \+(\(.*\))\$/, \1/
171 s/^/@n/; s/, /@n /g
172 # conditionnal branch to reset
173 ${TAGS:+t a;} s/.*//; t e
174 # extract the desired tags
175 :a; s/\n\$//; t e
176 s/\(.*\)\n tag: \($TAG_PATTERN\)\$/[\2]@n\1/; t a
177 s/\(.*\)\n [^ ]*\$/\1/; t a
178 s/\(.*\)\n [a-zA-Z]\+: *[^ ]*\$/\1/; t a
179 :e; s/\n/ /g; h; d
181 # Add the merge marker to the hold space
182 /^Merge: / { ${MERGE:+x; s/\$/${B}M$b /; x;} d; }
183 /^Author:/ {
184 # Process author, date, tag
185 ${ANNOTATE:+x; s/${s}s*\$/@n/; x; b s;} x; s/.*/@n/; x${ANNOTATE:+; :s}
186 N; G; s/^Author:\s*\(.*\) \s*\(<[^<>]*>\)\s*\nDate:\s*\(.*\)\n\(.*\n\)\$/\4\3 \1 \2@n/
187 s/^\n//
188 # Process title
189 n; N; s/^.*\n /\t${TITLESTAR:+${NO_GITBODY:+* }}/
190 t t; :t; n; s/^ \(.\+\)\$/\t${TITLESTAR:+${NO_GITBODY:+ }}\1/; t t
191 # If non empty body, print an extra line
192 ${NO_TITLE:+${NO_GITBODY:+${BLANKLINE:+/^\$/ !$B s/^ /${s}t/p; s/^${s}t/ /; $b}}}
194 ${TITLE:+/^ / d}
195 # First line of the paragraph
196 :b; /^ \$/ { N; s/^ \n//; s/^ \(.\)/${GITBODY:+${s}t@n}\t${NO_GITBODY:+* }\1/; b b; }
197 # Rest of the paragraph
198 s/^ /\t${NO_GITBODY:+ }/
199 # Reset the hold space for the next entry
200 /^\$/ h
202 )" # sed
203 echo >&3 rc=$?
204 )" # eval
205 exec 4>&-
207 # error check
208 test $gitrc -eq 0 ||
209 echo >&2 "$0: ERROR git or cat failed with #$gitrc"
210 test $rc -eq 0 ||
211 { echo >&2 "$0: ERROR sed failed with #$rc"; exit $rc; }
212 exit $gitrc