Merge with gitk.
[git.git] / git-format-patch-script
1 #!/bin/sh
2 #
3 # Copyright (c) 2005 Junio C Hamano
4 #
5
6 . git-sh-setup-script || die "Not a git archive."
7
8 usage () {
9     echo >&2 "usage: $0"' [-n] [-o dir] [--mbox] [--check] [-<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     -n|--n|--nu|--num|--numb|--numbe|--number|--numbere|--numbered)
48     numbered=t ;;
49     -o=*|--o=*|--ou=*|--out=*|--outp=*|--outpu=*|--output=*|--output-=*|\
50     --output-d=*|--output-di=*|--output-dir=*|--output-dire=*|\
51     --output-direc=*|--output-direct=*|--output-directo=*|\
52     --output-director=*|--output-directory=*)
53     outdir=`expr "$1" : '-[^=]*=\(.*\)'` ;;
54     -o|--o|--ou|--out|--outp|--outpu|--output|--output-|--output-d|\
55     --output-di|--output-dir|--output-dire|--output-direc|--output-direct|\
56     --output-directo|--output-director|--output-directory)
57     case "$#" in 1) usage ;; esac; shift
58     outdir="$1" ;;
59     -*) diff_opts="$diff_opts$LF$1" ;;
60     *) break ;;
61     esac
62     shift
63 done
64
65 revpair=
66 case "$#" in
67 2)
68     revpair="$1..$2" ;;
69 1)
70     case "$1" in
71     *..*)
72         revpair="$1";;
73     *)
74         revpair="$1..HEAD";;
75     esac ;;
76 *)
77     usage ;;
78 esac
79
80 me=`git-var GIT_AUTHOR_IDENT | sed -e 's/>.*/>/'`
81
82 case "$outdir" in
83 */) ;;
84 *) outdir="$outdir/" ;;
85 esac
86 test -d "$outdir" || mkdir -p "$outdir" || exit
87
88 tmp=.tmp-series$$
89 trap 'rm -f $tmp-*' 0 1 2 3 15
90
91 series=$tmp-series
92 commsg=$tmp-commsg
93 filelist=$tmp-files
94
95 titleScript='
96         /./d
97         /^$/n
98         s/^\[PATCH[^]]*\] *//
99         s/[^-a-z.A-Z_0-9]/-/g
100         s/\.\.\.*/\./g
101         s/\.*$//
102         s/--*/-/g
103         s/^-//
104         s/-$//
105         s/$/./
106         p
107         q
108 '
109
110 whosepatchScript='
111 /^author /{
112         s/author \(.*>\) \(.*\)$/au='\''\1'\'' ad='\''\2'\''/p
113         q
114 }'
115
116 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
117 _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
118 stripCommitHead='/^'"$_x40"' (from '"$_x40"')$/d'
119
120 git-rev-list --no-merges --merge-order \
121         $(git-rev-parse --revs-only "$revpair") >$series
122 total=`wc -l <$series | tr -dc "[0-9]"`
123 i=$total
124 while read commit
125 do
126     git-cat-file commit "$commit" | git-stripspace >$commsg
127     title=`sed -ne "$titleScript" <$commsg`
128     case "$numbered" in
129     '') num= ;;
130     *)
131         case $total in
132         1) num= ;;
133         *) num=' '`printf "%d/%d" $i $total` ;;
134         esac
135     esac
136
137     file=`printf '%04d-%stxt' $i "$title"`
138     i=`expr "$i" - 1`
139     echo >&2 "* $file"
140     {
141         mailScript='
142         /./d
143         /^$/n
144         s|^\[PATCH[^]]*\] *||'
145
146         case "$mbox" in
147         t)
148             echo 'From nobody Mon Sep 17 00:00:00 2001' ;# UNIX "From" line
149             mailScript="$mailScript"'
150             s|^|Subject: [PATCH'"$num"'] |'
151             ;;
152         *)
153             mailScript="$mailScript"'
154             s|^|[PATCH'"$num"'] |'
155             ;;
156         esac
157
158         eval "$(sed -ne "$whosepatchScript" $commsg)"
159         test "$author,$au" = ",$me" || {
160                 mailScript="$mailScript"'
161         a\
162 From: '"$au"
163         }
164         test "$date,$au" = ",$me" || {
165                 mailScript="$mailScript"'
166         a\
167 Date: '"$ad"
168         }
169
170         mailScript="$mailScript"'
171         : body
172         p
173         n
174         b body'
175
176         sed -ne "$mailScript" <$commsg
177         echo '---'
178         echo
179         git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
180         echo
181         git-diff-tree -p $diff_opts "$commit" | sed -e "$stripCommitHead"
182
183         case "$mbox" in
184         t)
185                 echo
186                 ;;
187         esac
188     } >"$outdir$file"
189     case "$check" in
190     t)
191         # This is slightly modified from Andrew Morton's Perfect Patch.
192         # Lines you introduce should not have trailing whitespace.
193         # Also check for an indentation that has SP before a TAB.
194         grep -n '^+\([  ]*      .*\|.*[         ]\)$' "$outdir$file"
195
196         : do not exit with non-zero because we saw no problem in the last one.
197     esac
198 done <$series