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