update-index: work with c-quoted name
[git/jrn.git] / git-format-patch.sh
blobd3979d76318a19746b02c3efcba1212de2fcce20
1 #!/bin/sh
3 # Copyright (c) 2005 Junio C Hamano
6 USAGE='[-n | -k] [-o <dir> | --stdout] [--signoff] [--check] [--mbox] [--diff-options] <upstream> [<our-head>]'
7 LONG_USAGE='Prepare each commit with its patch since our-head forked from upstream,
8 one file per patch, for e-mail submission. Each output file is
9 numbered sequentially from 1, and uses the first line of the commit
10 message (massaged for pathname safety) as the filename.
12 There are three output modes. By default, output files are created in
13 the current working directory; when -o is specified, they are created
14 in that directory instead; when --stdout is specified, they are spit
15 on standard output, and can be piped to git-am.
17 When -n is specified, instead of "[PATCH] Subject", the first line is formatted
18 as "[PATCH N/M] Subject", unless you have only one patch.
20 When --mbox is specified, the output is formatted to resemble
21 UNIX mailbox format, and can be concatenated together for processing
22 with applymbox.'
23 . git-sh-setup
25 # Force diff to run in C locale.
26 LANG=C LC_ALL=C
27 export LANG LC_ALL
29 diff_opts=
30 LF='
33 outdir=./
34 while case "$#" in 0) break;; esac
36 case "$1" in
37 -a|--a|--au|--aut|--auth|--autho|--author)
38 author=t ;;
39 -c|--c|--ch|--che|--chec|--check)
40 check=t ;;
41 -d|--d|--da|--dat|--date)
42 date=t ;;
43 -m|--m|--mb|--mbo|--mbox)
44 date=t author=t mbox=t ;;
45 -k|--k|--ke|--kee|--keep|--keep-|--keep-s|--keep-su|--keep-sub|\
46 --keep-subj|--keep-subje|--keep-subjec|--keep-subject)
47 keep_subject=t ;;
48 -n|--n|--nu|--num|--numb|--numbe|--number|--numbere|--numbered)
49 numbered=t ;;
50 -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
51 signoff=t ;;
52 --st|--std|--stdo|--stdou|--stdout)
53 stdout=t mbox=t date=t author=t ;;
54 -o=*|--o=*|--ou=*|--out=*|--outp=*|--outpu=*|--output=*|--output-=*|\
55 --output-d=*|--output-di=*|--output-dir=*|--output-dire=*|\
56 --output-direc=*|--output-direct=*|--output-directo=*|\
57 --output-director=*|--output-directory=*)
58 outdir=`expr "$1" : '-[^=]*=\(.*\)'` ;;
59 -o|--o|--ou|--out|--outp|--outpu|--output|--output-|--output-d|\
60 --output-di|--output-dir|--output-dire|--output-direc|--output-direct|\
61 --output-directo|--output-director|--output-directory)
62 case "$#" in 1) usage ;; esac; shift
63 outdir="$1" ;;
64 -h|--h|--he|--hel|--help)
65 usage
67 -*' '* | -*"$LF"* | -*' '*)
68 # Ignore diff option that has whitespace for now.
70 -*) diff_opts="$diff_opts$1 " ;;
71 *) break ;;
72 esac
73 shift
74 done
76 case "$keep_subject$numbered" in
77 tt)
78 die '--keep-subject and --numbered are incompatible.' ;;
79 esac
81 tmp=.tmp-series$$
82 trap 'rm -f $tmp-*' 0 1 2 3 15
84 series=$tmp-series
85 commsg=$tmp-commsg
86 filelist=$tmp-files
88 # Backward compatible argument parsing hack.
90 # Historically, we supported:
91 # 1. "rev1" is equivalent to "rev1..HEAD"
92 # 2. "rev1..rev2"
93 # 3. "rev1" "rev2 is equivalent to "rev1..rev2"
95 # We want to take a sequence of "rev1..rev2" in general.
96 # Also, "rev1.." should mean "rev1..HEAD"; git-diff users are
97 # familiar with that syntax.
99 case "$#,$1$2" in
100 1,?*..?*)
101 # single "rev1..rev2"
103 1,?*..)
104 # single "rev1.." should mean "rev1..HEAD"
105 set x "$1"HEAD
106 shift
108 1,*)
109 # single rev1
110 set x "$1..HEAD"
111 shift
113 2,?*..?*)
114 # not traditional "rev1" "rev2"
116 2,*)
117 set x "$1..$2"
118 shift
120 esac
122 # Now we have what we want in $@
123 for revpair
125 case "$revpair" in
126 ?*..?*)
127 rev1=`expr "$revpair" : '\(.*\)\.\.'`
128 rev2=`expr "$revpair" : '.*\.\.\(.*\)'`
131 rev1="$revpair^"
132 rev2="$revpair"
134 esac
135 git-rev-parse --verify "$rev1^0" >/dev/null 2>&1 ||
136 die "Not a valid rev $rev1 ($revpair)"
137 git-rev-parse --verify "$rev2^0" >/dev/null 2>&1 ||
138 die "Not a valid rev $rev2 ($revpair)"
139 git-cherry -v "$rev1" "$rev2" |
140 while read sign rev comment
142 case "$sign" in
143 '-')
144 echo >&2 "Merged already: $comment"
147 echo $rev
149 esac
150 done
151 done >$series
153 me=`git-var GIT_AUTHOR_IDENT | sed -e 's/>.*/>/'`
155 case "$outdir" in
156 */) ;;
157 *) outdir="$outdir/" ;;
158 esac
159 test -d "$outdir" || mkdir -p "$outdir" || exit
161 titleScript='
162 /./d
163 /^$/n
164 s/^\[PATCH[^]]*\] *//
165 s/[^-a-z.A-Z_0-9]/-/g
166 s/\.\.\.*/\./g
167 s/\.*$//
168 s/--*/-/g
169 s/^-//
170 s/-$//
171 s/$/./
176 whosepatchScript='
177 /^author /{
178 s/'\''/'\''\\'\'\''/g
179 s/author \(.*>\) \(.*\)$/au='\''\1'\'' ad='\''\2'\''/p
183 process_one () {
184 mailScript='
185 /./d
186 /^$/n'
187 case "$keep_subject" in
188 t) ;;
190 mailScript="$mailScript"'
191 s|^\[PATCH[^]]*\] *||
192 s|^|[PATCH'"$num"'] |'
194 esac
195 mailScript="$mailScript"'
196 s|^|Subject: |'
197 case "$mbox" in
199 echo 'From nobody Mon Sep 17 00:00:00 2001' ;# UNIX "From" line
201 esac
203 eval "$(sed -ne "$whosepatchScript" $commsg)"
204 test "$author,$au" = ",$me" || {
205 mailScript="$mailScript"'
207 From: '"$au"
209 test "$date,$au" = ",$me" || {
210 mailScript="$mailScript"'
212 Date: '"$ad"
215 mailScript="$mailScript"'
218 : body
221 b body'
223 (cat $commsg ; echo; echo) |
224 sed -ne "$mailScript" |
225 git-stripspace
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
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@@"
245 case "$mbox" in
247 echo
249 esac
252 total=`wc -l <$series | tr -dc "[0-9]"`
253 case "$total,$numbered" in
254 1,*)
255 numfmt='' ;;
256 *,t)
257 numfmt=`echo "$total" | wc -c`
258 numfmt=$(($numfmt-1))
259 numfmt=" %0${numfmt}d/$total"
260 esac
263 while read commit
265 git-cat-file commit "$commit" | git-stripspace >$commsg
266 title=`sed -ne "$titleScript" <$commsg`
267 case "$numbered" in
268 '') num= ;;
270 num=`printf "$numfmt" $i` ;;
271 esac
273 file=`printf '%04d-%stxt' $i "$title"`
274 if test '' = "$stdout"
275 then
276 echo "$file"
277 process_one >"$outdir$file"
278 if test t = "$check"
279 then
280 # This is slightly modified from Andrew Morton's Perfect Patch.
281 # Lines you introduce should not have trailing whitespace.
282 # Also check for an indentation that has SP before a TAB.
283 grep -n '^+\([ ]* .*\|.*[ ]\)$' "$outdir$file"
286 else
287 echo >&2 "$file"
288 process_one
290 i=`expr "$i" + 1`
291 done <$series