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