git-format-patch: silly typo fix.
[git.git] / git-format-patch.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2005 Junio C Hamano
4 #
5
6 . git-sh-setup || die "Not a git archive."
7
8 usage () {
9     echo >&2 "usage: $0"' [-n] [-o dir | --stdout] [--keep-subject] [--mbox]
10     [--check] [--signoff] [-<diff options>...]
11     ( from..to ... | upstream [ our-head ] )
12
13 Prepare each commit with its patch since our-head forked from upstream,
14 one file per patch, for e-mail submission.  Each output file is
15 numbered sequentially from 1, and uses the first line of the commit
16 message (massaged for pathname safety) as the filename.
17
18 When -o is specified, output files are created in that directory; otherwise in
19 the current working directory.
20
21 When -n is specified, instead of "[PATCH] Subject", the first line is formatted
22 as "[PATCH N/M] Subject", unless you have only one patch.
23
24 When --mbox is specified, the output is formatted to resemble
25 UNIX mailbox format, and can be concatenated together for processing
26 with applymbox.
27 '
28     exit 1
29 }
30
31 diff_opts=
32 LF='
33 '
34
35 outdir=./
36 while case "$#" in 0) break;; esac
37 do
38     case "$1" in
39     -a|--a|--au|--aut|--auth|--autho|--author)
40     author=t ;;
41     -c|--c|--ch|--che|--chec|--check)
42     check=t ;;
43     -d|--d|--da|--dat|--date)
44     date=t ;;
45     -m|--m|--mb|--mbo|--mbox)
46     date=t author=t mbox=t ;;
47     -k|--k|--ke|--kee|--keep|--keep-|--keep-s|--keep-su|--keep-sub|\
48     --keep-subj|--keep-subje|--keep-subjec|--keep-subject)
49     keep_subject=t ;;
50     -n|--n|--nu|--num|--numb|--numbe|--number|--numbere|--numbered)
51     numbered=t ;;
52     -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
53     signoff=t ;;
54     --st|--std|--stdo|--stdou|--stdout)
55     stdout=t mbox=t date=t author=t ;;
56     -o=*|--o=*|--ou=*|--out=*|--outp=*|--outpu=*|--output=*|--output-=*|\
57     --output-d=*|--output-di=*|--output-dir=*|--output-dire=*|\
58     --output-direc=*|--output-direct=*|--output-directo=*|\
59     --output-director=*|--output-directory=*)
60     outdir=`expr "$1" : '-[^=]*=\(.*\)'` ;;
61     -o|--o|--ou|--out|--outp|--outpu|--output|--output-|--output-d|\
62     --output-di|--output-dir|--output-dire|--output-direc|--output-direct|\
63     --output-directo|--output-director|--output-directory)
64     case "$#" in 1) usage ;; esac; shift
65     outdir="$1" ;;
66     -*' '* | -*"$LF"* | -*'     '*)
67         # Ignore diff option that has whitespace for now.
68         ;;
69     -*) diff_opts="$diff_opts$1 " ;;
70     *) break ;;
71     esac
72     shift
73 done
74
75 case "$keep_subject$numbered" in
76 tt)
77         die '--keep-subject and --numbered are incompatible.' ;;
78 esac
79
80 tmp=.tmp-series$$
81 trap 'rm -f $tmp-*' 0 1 2 3 15
82
83 series=$tmp-series
84 commsg=$tmp-commsg
85 filelist=$tmp-files
86
87 # Backward compatible argument parsing hack.
88 #
89 # Historically, we supported:
90 # 1. "rev1"             is equivalent to "rev1..HEAD"
91 # 2. "rev1..rev2"
92 # 3. "rev1" "rev2       is equivalent to "rev1..rev2"
93 #
94 # We want to take a sequence of "rev1..rev2" in general.
95 # Also, "rev1.." should mean "rev1..HEAD"; git-diff users are
96 # familiar with that syntax.
97
98 case "$#,$1" in
99 1,?*..?*)
100         # single "rev1..rev2"
101         ;;
102 1,?*..)
103         # single "rev1.." should mean "rev1..HEAD"
104         set x "$1"HEAD
105         shift
106         ;;
107 1,*)
108         # single rev1
109         set x "$1..HEAD"
110         shift
111         ;;
112 2,?*..?*)
113         # not traditional "rev1" "rev2"
114         ;;
115 2,*)
116         set x "$1..$2"
117         shift
118         ;;
119 esac
120
121 # Now we have what we want in $@
122 for revpair
123 do
124         case "$revpair" in
125         ?*..?*)
126                 rev1=`expr "$revpair" : '\(.*\)\.\.'`
127                 rev2=`expr "$revpair" : '.*\.\.\(.*\)'`
128                 ;;
129         *)
130                 usage
131                 ;;
132         esac
133         git-rev-parse --verify "$rev1^0" >/dev/null 2>&1 ||
134                 die "Not a valid rev $rev1 ($revpair)"
135         git-rev-parse --verify "$rev2^0" >/dev/null 2>&1 ||
136                 die "Not a valid rev $rev2 ($revpair)"
137         git-cherry -v "$rev1" "$rev2" |
138         while read sign rev comment
139         do
140                 case "$sign" in
141                 '-')
142                         echo >&2 "Merged already: $comment"
143                         ;;
144                 *)
145                         echo $rev
146                         ;;
147                 esac
148         done
149 done >$series
150
151 me=`git-var GIT_AUTHOR_IDENT | sed -e 's/>.*/>/'`
152
153 case "$outdir" in
154 */) ;;
155 *) outdir="$outdir/" ;;
156 esac
157 test -d "$outdir" || mkdir -p "$outdir" || exit
158
159 titleScript='
160         /./d
161         /^$/n
162         s/^\[PATCH[^]]*\] *//
163         s/[^-a-z.A-Z_0-9]/-/g
164         s/\.\.\.*/\./g
165         s/\.*$//
166         s/--*/-/g
167         s/^-//
168         s/-$//
169         s/$/./
170         p
171         q
172 '
173
174 whosepatchScript='
175 /^author /{
176         s/author \(.*>\) \(.*\)$/au='\''\1'\'' ad='\''\2'\''/p
177         q
178 }'
179
180 process_one () {
181         mailScript='
182         /./d
183         /^$/n'
184         case "$keep_subject" in
185         t)  ;;
186         *)
187             mailScript="$mailScript"'
188             s|^\[PATCH[^]]*\] *||
189             s|^|[PATCH'"$num"'] |'
190             ;;
191         esac
192         mailScript="$mailScript"'
193         s|^|Subject: |'
194         case "$mbox" in
195         t)
196             echo 'From nobody Mon Sep 17 00:00:00 2001' ;# UNIX "From" line
197             ;;
198         esac
199
200         eval "$(sed -ne "$whosepatchScript" $commsg)"
201         test "$author,$au" = ",$me" || {
202                 mailScript="$mailScript"'
203         a\
204 From: '"$au"
205         }
206         test "$date,$au" = ",$me" || {
207                 mailScript="$mailScript"'
208         a\
209 Date: '"$ad"
210         }
211
212         mailScript="$mailScript"'
213         : body
214         p
215         n
216         b body'
217
218         (cat $commsg ; echo; echo) |
219         sed -ne "$mailScript" |
220         git-stripspace
221
222         test "$signoff" = "t" && {
223                 offsigner=`git-var GIT_COMMITTER_IDENT | sed -e 's/>.*/>/'`
224                 line="Signed-off-by: $offsigner"
225                 grep -q "^$line\$" $commsg || {
226                         echo
227                         echo "$line"
228                         echo
229                 }
230         }
231         echo
232         echo '---'
233         echo
234         git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
235         echo
236         git-cat-file commit "$commit^" | sed -e 's/^tree /applies-to: /' -e q
237         git-diff-tree -p $diff_opts "$commit"
238         echo "---"
239         echo "@@GIT_VERSION@@"
240
241         case "$mbox" in
242         t)
243                 echo
244                 ;;
245         esac
246 }
247
248 total=`wc -l <$series | tr -dc "[0-9]"`
249 i=1
250 while read commit
251 do
252     git-cat-file commit "$commit" | git-stripspace >$commsg
253     title=`sed -ne "$titleScript" <$commsg`
254     case "$numbered" in
255     '') num= ;;
256     *)
257         case $total in
258         1) num= ;;
259         *) num=' '`printf "%d/%d" $i $total` ;;
260         esac
261     esac
262
263     file=`printf '%04d-%stxt' $i "$title"`
264     if test '' = "$stdout"
265     then
266             echo "* $file"
267             process_one >"$outdir$file"
268             if test t = "$check"
269             then
270                 # This is slightly modified from Andrew Morton's Perfect Patch.
271                 # Lines you introduce should not have trailing whitespace.
272                 # Also check for an indentation that has SP before a TAB.
273                 grep -n '^+\([  ]*      .*\|.*[         ]\)$' "$outdir$file"
274                 :
275             fi
276     else
277             echo >&2 "* $file"
278             process_one
279     fi
280     i=`expr "$i" + 1`
281 done <$series