topgit: fully qualify more refs
[topgit/pro.git] / tg-patch.sh
blob33629b28631ec8bbca0375fb1506e03ddb664b30
1 #!/bin/sh
2 # TopGit - A different patch queue manager
3 # Copyright (C) Petr Baudis <pasky@suse.cz> 2008
4 # All rights reserved.
5 # GPLv2
7 name=
8 head_from=
9 binary=
10 quiet=
11 fixfrom=
12 fromaddr=
14 gec=0
15 bool="$(git config --get --bool topgit.from 2>/dev/null)" || gec=$?
16 if [ $gec -eq 128 ]; then
17 fromaddr="$(git config --get topgit.from 2>/dev/null)" || :
18 if [ "$fromaddr" = "quiet" ]; then
19 quiet=1
20 else
21 [ -z "$fromaddr" ] || fixfrom=1
23 elif [ $gec -eq 0 ]; then
24 [ "$bool" = "false" ] || fixfrom=1
27 ## Parse options
29 while [ -n "$1" ]; do
30 arg="$1"
31 case "$arg" in
32 --)
33 case "$2" in
34 -*)
35 shift; break;;
37 break;;
38 esac;;
39 -|-h|--help)
40 echo "Usage: ${tgname:-tg} [...] patch [-q] [-i | -w] [--binary] [<name>] [--] [<git-diff-tree-option>...]" >&2
41 exit 1;;
42 -i|-w)
43 [ -z "$head_from" ] || die "-i and -w are mutually exclusive"
44 head_from="$arg";;
45 --binary)
46 binary=1;;
47 -q|--quiet)
48 quiet=1;;
49 --no-from)
50 fixfrom= fromaddr=;;
51 --from)
52 fixfrom=1;;
53 --from=*)
54 fixfrom=1 fromaddr="${1#--from=}";;
55 -?*)
56 if test="$(verify_topgit_branch "$arg" -f)"; then
57 [ -z "$name" ] || die "name already specified ($name)"
58 name="$arg"
59 else
60 break
61 fi;;
63 [ -z "$name" ] || die "name already specified ($name)"
64 name="$arg";;
65 esac
66 shift
67 done
69 head="$(git symbolic-ref -q HEAD)" || :
70 head="${head#refs/heads/}"
72 [ -n "$name" ] ||
73 name="${head:-HEAD}"
74 name="$(verify_topgit_branch "$name")"
75 base_rev="$(git rev-parse --short --verify "refs/$topbases/$name^0" -- 2>/dev/null)" ||
76 die "not a TopGit-controlled branch"
78 if [ -n "$head_from" ] && [ "$name" != "$head" ]; then
79 die "$head_from makes only sense for the current branch"
82 usesob=
83 [ -z "$fixfrom" ] || [ -n "$fromaddr" ] || {
84 fromaddr="$(git var GIT_AUTHOR_IDENT)" || exit
85 usesob=1
88 # We now collect the rest of the code in this file into a function
89 # so we can redirect the output to the pager.
90 output()
93 # put out the commit message
94 # and put an empty line out, if the last one in the message was not an empty line
95 # and put out "---" if the commit message does not have one yet
96 result=0
97 cat_file "refs/heads/$name:.topmsg" $head_from |
98 awk -v "fixfrom=$fixfrom" -v "fromaddr=$fromaddr" -v "usesob=$usesob" '
99 function trimfb(s) {
100 sub(/^[ \t]+/, "", s)
101 sub(/[ \t]+$/, "", s)
102 return s
104 function fixident(val, fixmt, _name, _email) {
105 val = trimfb(val)
106 if (!fixmt && val == "") return ""
107 _name=""
108 _email=""
109 if ((leftangle = index(val, "<")) > 0) {
110 _name=trimfb(substr(val, 1, leftangle - 1))
111 _email=substr(val, leftangle+1)
112 sub(/>[^>]*$/, "", _email)
113 _email=trimfb(_email)
114 } else {
115 if ((atsign = index(val, "@")) > 0) {
116 _name=trimfb(substr(val, 1, atsign - 1))
117 _email=trimfb(val)
118 } else {
119 _name=trimfb(val)
120 if (_name != "") _email="-"
123 if (!fixmt && _name == "" && _email == "") return ""
124 if (_name == "") _name = "-"
125 if (_email == "") _email = "-"
126 return _name " <" _email ">"
128 BEGIN {
129 hdrline = 0
130 sawfrom = 0
131 sobname = ""
132 if (fixfrom) {
133 fromaddr = fixident(fromaddr)
134 if (fromaddr == "" && !usesob) fixfrom = 0
136 inhdr = 1
137 bodyline = 0
139 inhdr && /^[Ff][Rr][Oo][Mm][ \t]*:/ {
140 val = $0
141 sub(/^[^:]*:/, "", val)
142 val = fixident(val)
143 if (val != "") sawfrom = 1
144 if (val != "" || !fixfrom) hdrs[++hdrline] = $0
145 next
147 inhdr && /^[ \t]*$/ {
148 inhdr = 0
149 next
151 inhdr { hdrs[++hdrline] = $0; next; }
152 function writehdrs() {
153 if (!sawfrom && fixfrom && fromaddr != "") {
154 print "From: " fromaddr
155 sawfrom = 1
157 for (i=1; i <= hdrline; ++i) print hdrs[i]
158 print ""
160 /^---/ { has_3dash=1 }
161 usesob && /^[Ss][Ii][Gg][Nn][Ee][Dd]-[Oo][Ff][Ff]-[Bb][Yy][ \t]*:[ \t]*[^ \t]/ {
162 val = $0
163 sub(/^[^:]*:/, "", val)
164 val = fixident(val)
165 if (val != "") fromaddr=val
168 need_empty = 1
169 if ($0 == "") need_empty = 0
170 body[++bodyline] = $0
172 END {
173 writehdrs()
174 for (i = 1; i <= bodyline; ++i) print body[i]
175 if (need_empty) print ""
176 if (!has_3dash) print "---"
177 exit sawfrom ? 0 : 67 # EX_NOUSER
179 ' || result=$?
180 if [ "$result" = "67" ]; then
181 [ -n "$quiet" ] ||
182 echo "### tg: missing From: in .topmsg, 'git am' will barf (use --from to add)" >&2
183 result=0
185 [ "${result:-0}" = "0" ] || exit "$result"
187 b_tree=$(pretty_tree -t "$name" -b)
188 t_tree=$(pretty_tree -t "$name" $head_from)
190 if [ $b_tree = $t_tree ]; then
191 echo "No changes."
192 else
193 hasdd=
194 for a; do
195 [ "$a" != "--" ] || { hasdd=1; break; }
196 done
197 if [ -z "$hasdd" ]; then
198 git diff-tree -p --stat --summary ${binary:+--binary} "$@" $b_tree $t_tree
199 else
200 cmd="git diff-tree -p --stat --summary ${binary:+--binary}"
201 while [ $# -gt 0 -a "$1" != "--" ]; do
202 cmd="$cmd $(quotearg "$1")"
203 shift
204 done
205 cmd="$cmd $(quotearg "$b_tree") $(quotearg "$t_tree")"
206 while [ $# -gt 0 ]; do
207 cmd="$cmd $(quotearg "$1")"
208 shift
209 done
210 eval "$cmd"
214 echo ''
215 echo '-- '
216 depon="$(cat_file "refs/heads/$name:.topdeps" $head_from 2>/dev/null | paste -s -d ' ' -)"
217 echo "$tgname: ($base_rev..) $name${depon:+ (depends on: $depon)}"
218 branch_contains "refs/heads/$name" "refs/$topbases/$name" ||
219 echo "$tgname: The patch is out-of-date wrt. the base! Run \`$tgdisplay update\`."
222 USE_PAGER_TYPE=diff
223 page output "$@"
224 # ... and then we run it through the pager with the page function