[PATCH] git-format-patch: Prepare patches for e-mail submission.
[git.git] / git-format-patch-script
1 #!/bin/sh
2 #
3 # Copyright (c) 2005 Junio C Hamano
4 #
5
6 usage () {
7     echo >&2 "usage: $0"' [-n] [-o dir] [-<diff options>...] upstream [ our-head ]
8
9 Prepare each commit with its patch since our-head forked from upstream,
10 one file per patch, for e-mail submission.  Each output file is
11 numbered sequentially from 1, and uses the first line of the commit
12 message (massaged for pathname safety) as the filename.
13
14 When -o is specified, output files are created in that directory; otherwise in
15 the current working directory.
16
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.
19 '
20     exit 1
21 }
22
23 diff_opts=
24 IFS='
25 '
26 LF='
27 '
28 outdir=./
29
30 while case "$#" in 0) break;; esac
31 do
32     case "$1" in
33     -n|--n|--nu|--num|--numb|--numbe|--number|--numbere|--numbered)
34     numbered=t ;;
35     -o=*|--o=*|--ou=*|--out=*|--outp=*|--outpu=*|--output=*|--output-=*|\
36     --output-d=*|--output-di=*|--output-dir=*|--output-dire=*|\
37     --output-direc=*|--output-direct=*|--output-directo=*|\
38     --output-director=*|--output-directory=*)
39     outdir=`expr "$1" : '-[^=]*=\(.*\)'` ;;
40     -o|--o|--ou|--out|--outp|--outpu|--output|--output-|--output-d|\
41     --output-di|--output-dir|--output-dire|--output-direc|--output-direct|\
42     --output-directo|--output-director|--output-directory)
43     case "$#" in 1) usage ;; esac; shift
44     outdir="$1" ;;
45     -*) diff_opts="$diff_opts$LF$1" ;;
46     *) break ;;
47     esac
48     shift
49 done
50
51 case "$#" in
52 2)    linus="$1" junio="$2" ;;
53 1)    linus="$1" junio=HEAD ;;
54 *)    usage ;;
55 esac
56
57 case "$outdir" in
58 */) ;;
59 *) outdir="$outdir/" ;;
60 esac
61 test -d "$outdir" || mkdir -p "$outdir" || exit
62
63 tmp=.tmp-series$$
64 trap 'rm -f $tmp-*' 0 1 2 3 15
65
66 series=$tmp-series
67
68 titleScript='
69         1,/^$/d
70         : loop
71         /^$/b loop
72         s/[^-a-z.A-Z_0-9]/-/g
73         s/\.\.\.*/\./g
74         s/\.*$//
75         s/--*/-/g
76         s/^-//
77         s/-$//
78         s/$/./
79         q
80 '
81
82 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
83 _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
84 stripCommitHead='/^'"$_x40"' (from '"$_x40"')$/d'
85
86 git-rev-list --merge-order "$junio" "^$linus" >$series
87 total=`wc -l <$series`
88 i=$total
89 while read commit
90 do
91     title=`git-cat-file commit "$commit" | sed -e "$titleScript"`
92     case "$numbered" in
93     '') num= ;;
94     *)
95         case $total in
96         1) num= ;;
97         *) num=' '`printf "%d/%d" $i $total` ;;
98         esac
99     esac
100     file=`printf '%04d-%stxt' $i "$title"`
101     i=`expr "$i" - 1`
102     echo "$file"
103     {
104         mailScript='
105         1,/^$/d
106         : loop
107         /^$/b loop
108         s|^|[PATCH'"$num"'] |
109         : body
110         p
111         n
112         b body'
113
114         git-cat-file commit "$commit" | sed -ne "$mailScript"
115         echo '---'
116         echo
117         git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
118         echo
119         git-diff-tree -p $diff_opts "$commit" | sed -e "$stripCommitHead"
120     } >"$outdir$file"
121 done <$series