]> git.ipfire.org Git - thirdparty/git.git/blob - git-format-patch.sh
2844799535a4c63f61f6c94cf7a66c88d0052656
[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] [--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 -o=*|--o=*|--ou=*|--out=*|--outp=*|--outpu=*|--output=*|--output-=*|\
53 --output-d=*|--output-di=*|--output-dir=*|--output-dire=*|\
54 --output-direc=*|--output-direct=*|--output-directo=*|\
55 --output-director=*|--output-directory=*)
56 outdir=`expr "$1" : '-[^=]*=\(.*\)'` ;;
57 -o|--o|--ou|--out|--outp|--outpu|--output|--output-|--output-d|\
58 --output-di|--output-dir|--output-dire|--output-direc|--output-direct|\
59 --output-directo|--output-director|--output-directory)
60 case "$#" in 1) usage ;; esac; shift
61 outdir="$1" ;;
62 -*' '* | -*"$LF"* | -*' '*)
63 # Ignore diff option that has whitespace for now.
64 ;;
65 -*) diff_opts="$diff_opts$1 " ;;
66 *) break ;;
67 esac
68 shift
69 done
70
71 case "$keep_subject$numbered" in
72 tt)
73 die '--keep-subject and --numbered are incompatible.' ;;
74 esac
75
76 rev1= rev2=
77 case "$#" in
78 2)
79 rev1="$1" rev2="$2" ;;
80 1)
81 case "$1" in
82 *..*)
83 rev1=`expr "$1" : '\(.*\)\.\.'`
84 rev2=`expr "$1" : '.*\.\.\(.*\)'`
85 ;;
86 *)
87 rev1="$1"
88 rev2="HEAD"
89 ;;
90 esac ;;
91 *)
92 usage ;;
93 esac
94
95 me=`git-var GIT_AUTHOR_IDENT | sed -e 's/>.*/>/'`
96
97 case "$outdir" in
98 */) ;;
99 *) outdir="$outdir/" ;;
100 esac
101 test -d "$outdir" || mkdir -p "$outdir" || exit
102
103 tmp=.tmp-series$$
104 trap 'rm -f $tmp-*' 0 1 2 3 15
105
106 series=$tmp-series
107 commsg=$tmp-commsg
108 filelist=$tmp-files
109
110 titleScript='
111 /./d
112 /^$/n
113 s/^\[PATCH[^]]*\] *//
114 s/[^-a-z.A-Z_0-9]/-/g
115 s/\.\.\.*/\./g
116 s/\.*$//
117 s/--*/-/g
118 s/^-//
119 s/-$//
120 s/$/./
121 p
122 q
123 '
124
125 whosepatchScript='
126 /^author /{
127 s/author \(.*>\) \(.*\)$/au='\''\1'\'' ad='\''\2'\''/p
128 q
129 }'
130
131 git-cherry -v "$rev1" "$rev2" |
132 while read sign rev comment
133 do
134 case "$sign" in
135 '-')
136 echo >&2 "Merged already: $comment"
137 ;;
138 *)
139 echo $rev
140 ;;
141 esac
142 done >$series
143
144 total=`wc -l <$series | tr -dc "[0-9]"`
145 i=1
146 while read commit
147 do
148 git-cat-file commit "$commit" | git-stripspace >$commsg
149 title=`sed -ne "$titleScript" <$commsg`
150 case "$numbered" in
151 '') num= ;;
152 *)
153 case $total in
154 1) num= ;;
155 *) num=' '`printf "%d/%d" $i $total` ;;
156 esac
157 esac
158
159 file=`printf '%04d-%stxt' $i "$title"`
160 i=`expr "$i" + 1`
161 echo "* $file"
162 {
163 mailScript='
164 /./d
165 /^$/n'
166 case "$keep_subject" in
167 t) ;;
168 *)
169 mailScript="$mailScript"'
170 s|^\[PATCH[^]]*\] *||
171 s|^|[PATCH'"$num"'] |'
172 ;;
173 esac
174 mailScript="$mailScript"'
175 s|^|Subject: |'
176 case "$mbox" in
177 t)
178 echo 'From nobody Mon Sep 17 00:00:00 2001' ;# UNIX "From" line
179 ;;
180 esac
181 eval "$(sed -ne "$whosepatchScript" $commsg)"
182 test "$author,$au" = ",$me" || {
183 mailScript="$mailScript"'
184 a\
185 From: '"$au"
186 }
187 test "$date,$au" = ",$me" || {
188 mailScript="$mailScript"'
189 a\
190 Date: '"$ad"
191 }
192
193 mailScript="$mailScript"'
194 : body
195 p
196 n
197 b body'
198
199 sed -ne "$mailScript" <$commsg
200
201 test "$signoff" = "t" && {
202 offsigner=`git-var GIT_COMMITTER_IDENT | sed -e 's/>.*/>/'`
203 line="Signed-off-by: $offsigner"
204 grep -q "^$line\$" $commsg || {
205 echo
206 echo "$line"
207 echo
208 }
209 }
210 echo
211 echo '---'
212 echo
213 git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
214 echo
215 git-diff-tree -p $diff_opts "$commit"
216
217 case "$mbox" in
218 t)
219 echo
220 ;;
221 esac
222 } >"$outdir$file"
223 case "$check" in
224 t)
225 # This is slightly modified from Andrew Morton's Perfect Patch.
226 # Lines you introduce should not have trailing whitespace.
227 # Also check for an indentation that has SP before a TAB.
228 grep -n '^+\([ ]* .*\|.*[ ]\)$' "$outdir$file"
229
230 : do not exit with non-zero because we saw no problem in the last one.
231 esac
232 done <$series