]> git.ipfire.org Git - thirdparty/git.git/blob - git-format-patch.sh
Merge branch 'jc/subdir'
[thirdparty/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 # Force diff to run in C locale.
9 LANG=C LC_ALL=C
10 export LANG LC_ALL
11
12 usage () {
13 echo >&2 "usage: $0"' [-n] [-o dir | --stdout] [--keep-subject] [--mbox]
14 [--check] [--signoff] [-<diff options>...]
15 [--help]
16 ( from..to ... | upstream [ our-head ] )
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.
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.
32 '
33 exit 1
34 }
35
36 diff_opts=
37 LF='
38 '
39
40 outdir=./
41 while case "$#" in 0) break;; esac
42 do
43 case "$1" in
44 -a|--a|--au|--aut|--auth|--autho|--author)
45 author=t ;;
46 -c|--c|--ch|--che|--chec|--check)
47 check=t ;;
48 -d|--d|--da|--dat|--date)
49 date=t ;;
50 -m|--m|--mb|--mbo|--mbox)
51 date=t author=t mbox=t ;;
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 ;;
55 -n|--n|--nu|--num|--numb|--numbe|--number|--numbere|--numbered)
56 numbered=t ;;
57 -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
58 signoff=t ;;
59 --st|--std|--stdo|--stdou|--stdout)
60 stdout=t mbox=t date=t author=t ;;
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" ;;
71 -h|--h|--he|--hel|--help)
72 usage
73 ;;
74 -*' '* | -*"$LF"* | -*' '*)
75 # Ignore diff option that has whitespace for now.
76 ;;
77 -*) diff_opts="$diff_opts$1 " ;;
78 *) break ;;
79 esac
80 shift
81 done
82
83 case "$keep_subject$numbered" in
84 tt)
85 die '--keep-subject and --numbered are incompatible.' ;;
86 esac
87
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.
103 # Also, "rev1.." should mean "rev1..HEAD"; git-diff users are
104 # familiar with that syntax.
105
106 case "$#,$1$2" in
107 1,?*..?*)
108 # single "rev1..rev2"
109 ;;
110 1,?*..)
111 # single "rev1.." should mean "rev1..HEAD"
112 set x "$1"HEAD
113 shift
114 ;;
115 1,*)
116 # single rev1
117 set x "$1..HEAD"
118 shift
119 ;;
120 2,?*..?*)
121 # not traditional "rev1" "rev2"
122 ;;
123 2,*)
124 set x "$1..$2"
125 shift
126 ;;
127 esac
128
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 *)
138 rev1="$revpair^"
139 rev2="$revpair"
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
160 me=`git-var GIT_AUTHOR_IDENT | sed -e 's/>.*/>/'`
161
162 case "$outdir" in
163 */) ;;
164 *) outdir="$outdir/" ;;
165 esac
166 test -d "$outdir" || mkdir -p "$outdir" || exit
167
168 titleScript='
169 /./d
170 /^$/n
171 s/^\[PATCH[^]]*\] *//
172 s/[^-a-z.A-Z_0-9]/-/g
173 s/\.\.\.*/\./g
174 s/\.*$//
175 s/--*/-/g
176 s/^-//
177 s/-$//
178 s/$/./
179 p
180 q
181 '
182
183 whosepatchScript='
184 /^author /{
185 s/author \(.*>\) \(.*\)$/au='\''\1'\'' ad='\''\2'\''/p
186 q
187 }'
188
189 process_one () {
190 mailScript='
191 /./d
192 /^$/n'
193 case "$keep_subject" in
194 t) ;;
195 *)
196 mailScript="$mailScript"'
197 s|^\[PATCH[^]]*\] *||
198 s|^|[PATCH'"$num"'] |'
199 ;;
200 esac
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
208
209 eval "$(sed -ne "$whosepatchScript" $commsg)"
210 test "$author,$au" = ",$me" || {
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"'
222 : body
223 p
224 n
225 b body'
226
227 (cat $commsg ; echo; echo) |
228 sed -ne "$mailScript" |
229 git-stripspace
230
231 test "$signoff" = "t" && {
232 offsigner=`git-var GIT_COMMITTER_IDENT | sed -e 's/>.*/>/'`
233 line="Signed-off-by: $offsigner"
234 grep -q "^$line\$" $commsg || {
235 echo
236 echo "$line"
237 echo
238 }
239 }
240 echo
241 echo '---'
242 echo
243 git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
244 echo
245 git-diff-tree -p $diff_opts "$commit"
246 echo "-- "
247 echo "@@GIT_VERSION@@"
248
249 case "$mbox" in
250 t)
251 echo
252 ;;
253 esac
254 }
255
256 total=`wc -l <$series | tr -dc "[0-9]"`
257 i=1
258 while read commit
259 do
260 git-cat-file commit "$commit" | git-stripspace >$commsg
261 title=`sed -ne "$titleScript" <$commsg`
262 case "$numbered" in
263 '') num= ;;
264 *)
265 case $total in
266 1) num= ;;
267 *) num=' '`printf "%d/%d" $i $total` ;;
268 esac
269 esac
270
271 file=`printf '%04d-%stxt' $i "$title"`
272 if test '' = "$stdout"
273 then
274 echo "$file"
275 process_one >"$outdir$file"
276 if test t = "$check"
277 then
278 # This is slightly modified from Andrew Morton's Perfect Patch.
279 # Lines you introduce should not have trailing whitespace.
280 # Also check for an indentation that has SP before a TAB.
281 grep -n '^+\([ ]* .*\|.*[ ]\)$' "$outdir$file"
282 :
283 fi
284 else
285 echo >&2 "$file"
286 process_one
287 fi
288 i=`expr "$i" + 1`
289 done <$series