Add support for parallel HTTP transfers
[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