]> git.ipfire.org Git - thirdparty/git.git/blob - git-format-patch.sh
Merge branch 'fixes'
[thirdparty/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] [--check] [--signoff] [-<diff options>...] upstream [ our-head ]
10
11 Prepare each commit with its patch since our-head forked from upstream,
12 one file per patch, for e-mail submission. Each output file is
13 numbered sequentially from 1, and uses the first line of the commit
14 message (massaged for pathname safety) as the filename.
15
16 When -o is specified, output files are created in that directory; otherwise in
17 the current working directory.
18
19 When -n is specified, instead of "[PATCH] Subject", the first line is formatted
20 as "[PATCH N/M] Subject", unless you have only one patch.
21
22 When --mbox is specified, the output is formatted to resemble
23 UNIX mailbox format, and can be concatenated together for processing
24 with applymbox.
25 '
26 exit 1
27 }
28
29 diff_opts=
30 LF='
31 '
32
33 outdir=./
34 while case "$#" in 0) break;; esac
35 do
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 -*' '* | -*"$LF"* | -*' '*)
65 # Ignore diff option that has whitespace for now.
66 ;;
67 -*) diff_opts="$diff_opts$1 " ;;
68 *) break ;;
69 esac
70 shift
71 done
72
73 case "$keep_subject$numbered" in
74 tt)
75 die '--keep-subject and --numbered are incompatible.' ;;
76 esac
77
78 rev1= rev2=
79 case "$#" in
80 2)
81 rev1="$1" rev2="$2" ;;
82 1)
83 case "$1" in
84 *..*)
85 rev1=`expr "$1" : '\(.*\)\.\.'`
86 rev2=`expr "$1" : '.*\.\.\(.*\)'`
87 ;;
88 *)
89 rev1="$1"
90 rev2="HEAD"
91 ;;
92 esac ;;
93 *)
94 usage ;;
95 esac
96
97 me=`git-var GIT_AUTHOR_IDENT | sed -e 's/>.*/>/'`
98
99 case "$outdir" in
100 */) ;;
101 *) outdir="$outdir/" ;;
102 esac
103 test -d "$outdir" || mkdir -p "$outdir" || exit
104
105 tmp=.tmp-series$$
106 trap 'rm -f $tmp-*' 0 1 2 3 15
107
108 series=$tmp-series
109 commsg=$tmp-commsg
110 filelist=$tmp-files
111
112 titleScript='
113 /./d
114 /^$/n
115 s/^\[PATCH[^]]*\] *//
116 s/[^-a-z.A-Z_0-9]/-/g
117 s/\.\.\.*/\./g
118 s/\.*$//
119 s/--*/-/g
120 s/^-//
121 s/-$//
122 s/$/./
123 p
124 q
125 '
126
127 whosepatchScript='
128 /^author /{
129 s/author \(.*>\) \(.*\)$/au='\''\1'\'' ad='\''\2'\''/p
130 q
131 }'
132
133 git-cherry -v "$rev1" "$rev2" |
134 while read sign rev comment
135 do
136 case "$sign" in
137 '-')
138 echo >&2 "Merged already: $comment"
139 ;;
140 *)
141 echo $rev
142 ;;
143 esac
144 done >$series
145
146 process_one () {
147 mailScript='
148 /./d
149 /^$/n'
150 case "$keep_subject" in
151 t) ;;
152 *)
153 mailScript="$mailScript"'
154 s|^\[PATCH[^]]*\] *||
155 s|^|[PATCH'"$num"'] |'
156 ;;
157 esac
158 mailScript="$mailScript"'
159 s|^|Subject: |'
160 case "$mbox" in
161 t)
162 echo 'From nobody Mon Sep 17 00:00:00 2001' ;# UNIX "From" line
163 ;;
164 esac
165
166 eval "$(sed -ne "$whosepatchScript" $commsg)"
167 test "$author,$au" = ",$me" || {
168 mailScript="$mailScript"'
169 a\
170 From: '"$au"
171 }
172 test "$date,$au" = ",$me" || {
173 mailScript="$mailScript"'
174 a\
175 Date: '"$ad"
176 }
177
178 mailScript="$mailScript"'
179 : body
180 p
181 n
182 b body'
183
184 (cat $commsg ; echo; echo) |
185 sed -ne "$mailScript" |
186 git-stripspace
187
188 test "$signoff" = "t" && {
189 offsigner=`git-var GIT_COMMITTER_IDENT | sed -e 's/>.*/>/'`
190 line="Signed-off-by: $offsigner"
191 grep -q "^$line\$" $commsg || {
192 echo
193 echo "$line"
194 echo
195 }
196 }
197 echo
198 echo '---'
199 echo
200 git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
201 echo
202 git-cat-file commit "$commit^" | sed -e 's/^tree /applies-to: /' -e q
203 git-diff-tree -p $diff_opts "$commit"
204 echo "---"
205 echo "@@GIT_VERSION@@"
206
207 case "$mbox" in
208 t)
209 echo
210 ;;
211 esac
212 }
213
214 total=`wc -l <$series | tr -dc "[0-9]"`
215 i=1
216 while read commit
217 do
218 git-cat-file commit "$commit" | git-stripspace >$commsg
219 title=`sed -ne "$titleScript" <$commsg`
220 case "$numbered" in
221 '') num= ;;
222 *)
223 case $total in
224 1) num= ;;
225 *) num=' '`printf "%d/%d" $i $total` ;;
226 esac
227 esac
228
229 file=`printf '%04d-%stxt' $i "$title"`
230 if test '' = "$stdout"
231 then
232 echo "* $file"
233 process_one >"$outdir$file"
234 if test t = "$check"
235 then
236 # This is slightly modified from Andrew Morton's Perfect Patch.
237 # Lines you introduce should not have trailing whitespace.
238 # Also check for an indentation that has SP before a TAB.
239 grep -n '^+\([ ]* .*\|.*[ ]\)$' "$outdir$file"
240 :
241 fi
242 else
243 echo >&2 "* $file"
244 process_one
245 fi
246 i=`expr "$i" + 1`
247 done <$series