]> git.ipfire.org Git - thirdparty/git.git/blob - git-format-patch.sh
Big tool rename.
[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 IFS='
31 '
32 LF='
33 '
34
35 outdir=./
36 while case "$#" in 0) break;; esac
37 do
38 case "$1" in
39 -a|--a|--au|--aut|--auth|--autho|--author)
40 author=t ;;
41 -c|--c|--ch|--che|--chec|--check)
42 check=t ;;
43 -d|--d|--da|--dat|--date)
44 date=t ;;
45 -m|--m|--mb|--mbo|--mbox)
46 date=t author=t mbox=t ;;
47 -k|--k|--ke|--kee|--keep|--keep-|--keep-s|--keep-su|--keep-sub|\
48 --keep-subj|--keep-subje|--keep-subjec|--keep-subject)
49 keep_subject=t ;;
50 -n|--n|--nu|--num|--numb|--numbe|--number|--numbere|--numbered)
51 numbered=t ;;
52 -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
53 signoff=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 -*) diff_opts="$diff_opts$LF$1" ;;
65 *) break ;;
66 esac
67 shift
68 done
69
70 case "$keep_subject$numbered" in
71 tt)
72 die '--keep-subject and --numbered are incompatible.' ;;
73 esac
74
75 revpair=
76 case "$#" in
77 2)
78 revpair="$1..$2" ;;
79 1)
80 case "$1" in
81 *..*)
82 revpair="$1";;
83 *)
84 revpair="$1..HEAD";;
85 esac ;;
86 *)
87 usage ;;
88 esac
89
90 me=`git-var GIT_AUTHOR_IDENT | sed -e 's/>.*/>/'`
91
92 case "$outdir" in
93 */) ;;
94 *) outdir="$outdir/" ;;
95 esac
96 test -d "$outdir" || mkdir -p "$outdir" || exit
97
98 tmp=.tmp-series$$
99 trap 'rm -f $tmp-*' 0 1 2 3 15
100
101 series=$tmp-series
102 commsg=$tmp-commsg
103 filelist=$tmp-files
104
105 titleScript='
106 /./d
107 /^$/n
108 s/^\[PATCH[^]]*\] *//
109 s/[^-a-z.A-Z_0-9]/-/g
110 s/\.\.\.*/\./g
111 s/\.*$//
112 s/--*/-/g
113 s/^-//
114 s/-$//
115 s/$/./
116 p
117 q
118 '
119
120 whosepatchScript='
121 /^author /{
122 s/author \(.*>\) \(.*\)$/au='\''\1'\'' ad='\''\2'\''/p
123 q
124 }'
125
126 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
127 _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
128 stripCommitHead='/^'"$_x40"' (from '"$_x40"')$/d'
129
130 git-rev-list --no-merges --merge-order \
131 $(git-rev-parse --revs-only "$revpair") >$series
132 total=`wc -l <$series | tr -dc "[0-9]"`
133 i=$total
134 while read commit
135 do
136 git-cat-file commit "$commit" | git-stripspace >$commsg
137 title=`sed -ne "$titleScript" <$commsg`
138 case "$numbered" in
139 '') num= ;;
140 *)
141 case $total in
142 1) num= ;;
143 *) num=' '`printf "%d/%d" $i $total` ;;
144 esac
145 esac
146
147 file=`printf '%04d-%stxt' $i "$title"`
148 i=`expr "$i" - 1`
149 echo "* $file"
150 {
151 mailScript='
152 /./d
153 /^$/n'
154 case "$keep_subject" in
155 t) ;;
156 *)
157 mailScript="$mailScript"'
158 s|^\[PATCH[^]]*\] *||
159 s|^|[PATCH'"$num"'] |'
160 ;;
161 esac
162 mailScript="$mailScript"'
163 s|^|Subject: |'
164 case "$mbox" in
165 t)
166 echo 'From nobody Mon Sep 17 00:00:00 2001' ;# UNIX "From" line
167 ;;
168 esac
169 eval "$(sed -ne "$whosepatchScript" $commsg)"
170 test "$author,$au" = ",$me" || {
171 mailScript="$mailScript"'
172 a\
173 From: '"$au"
174 }
175 test "$date,$au" = ",$me" || {
176 mailScript="$mailScript"'
177 a\
178 Date: '"$ad"
179 }
180
181 mailScript="$mailScript"'
182 : body
183 p
184 n
185 b body'
186
187 sed -ne "$mailScript" <$commsg
188
189 test "$signoff" = "t" && {
190 offsigner=`git-var GIT_COMMITTER_IDENT | sed -e 's/>.*/>/'`
191 line="Signed-off-by: $offsigner"
192 grep -q "^$line\$" $commsg || {
193 echo
194 echo "$line"
195 echo
196 }
197 }
198 echo
199 echo '---'
200 echo
201 git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
202 echo
203 git-diff-tree -p $diff_opts "$commit" | sed -e "$stripCommitHead"
204
205 case "$mbox" in
206 t)
207 echo
208 ;;
209 esac
210 } >"$outdir$file"
211 case "$check" in
212 t)
213 # This is slightly modified from Andrew Morton's Perfect Patch.
214 # Lines you introduce should not have trailing whitespace.
215 # Also check for an indentation that has SP before a TAB.
216 grep -n '^+\([ ]* .*\|.*[ ]\)$' "$outdir$file"
217
218 : do not exit with non-zero because we saw no problem in the last one.
219 esac
220 done <$series