3 # Copyright (c) 2005 Junio C Hamano
6 USAGE='[-n | -k] [-o <dir> | --stdout] [--signoff] [--check] [--mbox] [--diff-options] <upstream> [<our-head>]'
7 LONG_USAGE='Prepare each commit with its patch since our-head forked from upstream,
8 one file per patch, for e-mail submission. Each output file is
9 numbered sequentially from 1, and uses the first line of the commit
10 message (massaged for pathname safety) as the filename.
12 There are three output modes. By default, output files are created in
13 the current working directory; when -o is specified, they are created
14 in that directory instead; when --stdout is specified, they are spit
15 on standard output, and can be piped to git-am.
17 When -n is specified, instead of "[PATCH] Subject", the first line is formatted
18 as "[PATCH N/M] Subject", unless you have only one patch.
20 When --mbox is specified, the output is formatted to resemble
21 UNIX mailbox format, and can be concatenated together for processing
25 # Force diff to run in C locale.
34 while case "$#" in 0) break;; esac
37 -c|--c|--ch|--che|--chec|--check)
39 -a|--a|--au|--aut|--auth|--autho|--author|\
40 -d|--d|--da|--dat|--date|\
41 -m|--m|--mb|--mbo|--mbox) # now noop
43 -k|--k|--ke|--kee|--keep|--keep-|--keep-s|--keep-su|--keep-sub|\
44 --keep-subj|--keep-subje|--keep-subjec|--keep-subject)
46 -n|--n|--nu|--num|--numb|--numbe|--number|--numbere|--numbered)
48 -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
50 --st|--std|--stdo|--stdou|--stdout)
51 stdout=t mbox=t date=t author=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
62 -h|--h|--he|--hel|--help)
65 -*' '* | -*"$LF"* | -*' '*)
66 # Ignore diff option that has whitespace for now.
68 -*) diff_opts="$diff_opts$1 " ;;
74 case "$keep_subject$numbered" in
76 die '--keep-subject and --numbered are incompatible.' ;;
80 trap 'rm -f $tmp-*' 0 1 2 3 15
86 # Backward compatible argument parsing hack.
88 # Historically, we supported:
89 # 1. "rev1" is equivalent to "rev1..HEAD"
91 # 3. "rev1" "rev2 is equivalent to "rev1..rev2"
93 # We want to take a sequence of "rev1..rev2" in general.
94 # Also, "rev1.." should mean "rev1..HEAD"; git-diff users are
95 # familiar with that syntax.
102 # single "rev1.." should mean "rev1..HEAD"
112 # not traditional "rev1" "rev2"
120 # Now we have what we want in $@
125 rev1=`expr "$revpair" : '\(.*\)\.\.'`
126 rev2=`expr "$revpair" : '.*\.\.\(.*\)'`
133 git-rev-parse --verify "$rev1^0" >/dev/null 2>&1 ||
134 die "Not a valid rev $rev1 ($revpair)"
135 git-rev-parse --verify "$rev2^0" >/dev/null 2>&1 ||
136 die "Not a valid rev $rev2 ($revpair)"
137 git-cherry -v "$rev1" "$rev2" |
138 while read sign rev comment
142 echo >&2 "Merged already: $comment"
151 me=`git-var GIT_AUTHOR_IDENT | sed -e 's/>.*/>/'`
155 *) outdir="$outdir/" ;;
157 test -d "$outdir" || mkdir -p "$outdir" || exit
162 s/^\[PATCH[^]]*\] *//
163 s/[^-a-z.A-Z_0-9]/-/g
176 my ($keep_subject, $num, $signoff, $commsg) = @ARGV;
177 my ($signoff_pattern, $done_header, $done_subject, $signoff_seen,
181 $signoff = `git-var GIT_COMMITTER_IDENT`;
182 $signoff =~ s/>.*/>/;
183 $signoff_pattern = quotemeta($signoff);
186 my @weekday_names = qw(Sun Mon Tue Wed Thu Fri Sat);
187 my @month_names = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
190 my ($time, $tz) = @_;
191 my $minutes = abs($tz);
192 $minutes = ($minutes / 100) * 60 + ($minutes % 100);
194 $minutes = -$minutes;
196 my $t = $time + $minutes * 60;
197 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime($t);
198 return sprintf("%s %s %d %02d:%02d:%02d %d %+05d",
199 $weekday_names[$wday],
201 $mday, $hour, $min, $sec,
205 print "From nobody Mon Sep 17 00:00:00 2001\n";
206 open FH, "git stripspace <$commsg |" or die "open $commsg pipe";
208 unless ($done_header) {
212 elsif (/^author (.*>) (.*)$/) {
213 my ($author_ident, $author_date) = ($1, $2);
214 my ($utc, $off) = ($author_date =~ /^(\d+) ([-+]?\d+)$/);
215 $author_date = show_date($utc, $off);
217 print "From: $author_ident\n";
218 print "Date: $author_date\n";
222 unless ($done_subject) {
223 unless ($keep_subject) {
224 s/^\[PATCH[^]]*\]\s*//;
232 $last_was_signoff = 0;
233 if (/Signed-off-by:/i) {
234 if ($signoff ne "" && /Signed-off-by:\s*$signoff_pattern$/i) {
240 if (!$signoff_seen && $signoff ne "") {
241 if (!$last_was_signoff) {
247 close FH or die "close $commsg pipe";
248 ' "$keep_subject" "$num" "$signoff" $commsg
250 git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
252 git-diff-tree -p $diff_opts "$commit"
254 echo "@@GIT_VERSION@@"
259 total=`wc -l <$series | tr -dc "[0-9]"`
260 case "$total,$numbered" in
264 numfmt=`echo "$total" | wc -c`
265 numfmt=$(($numfmt-1))
266 numfmt=" %0${numfmt}d/$total"
272 git-cat-file commit "$commit" | git-stripspace >$commsg
273 title=`sed -ne "$titleScript" <$commsg`
277 num=`printf "$numfmt" $i` ;;
280 file=`printf '%04d-%stxt' $i "$title"`
281 if test '' = "$stdout"
284 process_one >"$outdir$file"
287 # This is slightly modified from Andrew Morton's Perfect Patch.
288 # Lines you introduce should not have trailing whitespace.
289 # Also check for an indentation that has SP before a TAB.
290 grep -n '^+\([ ]* .*\|.*[ ]\)$' "$outdir$file"