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