2 # TopGit - A different patch queue manager
3 # Copyright (C) Petr Baudis <pasky@suse.cz> 2008
4 # Copyright (C) Kyle J. McKay <mackyle@gmail.com> 2015, 2016, 2017, 2018
8 Usage: ${tgname:-tg} [...] info [-i | -w] [--heads | --leaves | --series[=<head>]] [<name>]
9 Or: ${tgname:-tg} [...] info [-i | -w] [--deps | --dependencies | --dependents] [<name>]"
13 if [ "${1:-0}" != 0 ]; then
14 printf '%s\n' "$USAGE" >&2
16 printf '%s\n' "$USAGE"
33 while [ $# -gt 0 ]; do case "$1" in
38 [ -z "$head_from" ] || die
"-i and -w are mutually exclusive"
47 --deps|
--dependencies)
51 dependents
=1 datamode
=1
58 serieshead
="${1#--series=}"
61 verbose
=$
(( ${verbose:-0} + 1 ))
63 -vv|
-vvv|
-vvvv|
-vvvvv)
64 verbose
=$
(( ${verbose:-0} + ${#1} - 1 ))
67 echo "Unknown option: $1" >&2
74 [ -z "$datamode" ] ||
[ "$heads$leaves$deps$dependents$series" = "1" ] ||
75 die
"mutually exclusive options: --series --deps --heads --leaves --dependents"
76 [ $# -gt 0 ] ||
set -- HEAD
77 [ $# -eq 1 ] || die
"name already specified ($1)"
82 if [ -n "$_dep_is_tgish" ] && [ -z "$_dep_missing$_dep_annihilated" ]; then
83 printf '%s\n' "$_dep ${_depchain##* }"
87 if [ -n "$heads" ]; then
91 v_verify_topgit_branch tgbranch
"${name:-HEAD}" -f || tgbranch
=
92 [ -n "$tgbranch" ] || validate
=1 tgbranch
="$(cat_file HEAD:.topdeps $head_from 2>/dev/null | paste -d ' ' -s -)" ||
:
93 v_get_tdopt with_deps_opts
"$head_from"
94 if [ -n "$tgbranch" ]; then
95 # faster version with known TopGit branch name(s)
96 [ -z "$validate" ] || validate
="$(get_temp results)"
97 eval navigate_deps
"$with_deps_opts" -s=-1 -1 -- '"$tgbranch"' |
eval sort "${validate:+>\"\$validate\"}"
98 [ -n "$validate" ] ||
exit 0
100 hash="$(git rev-parse --verify --quiet "${name:-HEAD}^
0" --)" || die
"no such commit-ish: ${name:-HEAD}"
101 if [ -n "$validate" ] && [ -n "$tgbranch" ] && [ -s "$validate" ]; then
102 # If we were on a detached (or non-TopGit) HEAD the shortcut might produce answers that
103 # do not actually contain the HEAD commit and which are meaningless for an orphan branch
104 # (hence the requirement that HEAD actually point to an existing commit to get here)
106 while read -r abranch
; do
107 contained_by
"$hash" "refs/heads/$abranch" ||
continue
109 printf '%s\n' "$abranch"
111 [ -z "$ansok" ] ||
exit 0
112 # There might still be an answer, but not via the shortcut
114 depslist
="$(get_temp depslist)"
115 eval tg
--no-pager summary
$head_from --topgit-heads |
116 while read -r onetghead
; do
117 printf '%s %s\n' "$onetghead" "$onetghead"
118 recurse_deps process_dep
"$onetghead"
119 done |
sort -u >"$depslist"
120 git branch
--no-color --contains "$hash" |
sed -n "s/^..//;/^[^ $tab][^ $tab]*\$/p" |
121 join -o 2.2 - "$depslist" |
126 v_cntargs
() { eval "$1=$(( $# - 1 ))"; }
127 if [ -n "$series" ]; then
128 v_get_tdopt with_deps_opts
"$head_from"
129 if [ -z "$serieshead" ]; then
130 v_verify_topgit_branch name
"${name:-HEAD}"
131 heads
="$(eval navigate_deps "$with_deps_opts" -s=-1 -1 -- '"$name"' | sort | paste -d ' ' -s -)" || heads
="$name"
132 v_cntargs headcnt
$heads
133 if [ "$headcnt" -gt 1 ]; then
134 err
"multiple heads found"
135 info
"use the --series=<head> option on one of them:" >&2
136 for ahead
in $heads; do
137 info
"$tab$ahead" >&2
139 die
"--series requires exactly one head"
141 [ "$headcnt" = 1 ] || die
"programmer bug"
144 v_verify_topgit_branch serieshead
"$serieshead"
145 v_verify_topgit_branch name
"${name:-HEAD}" -f || name
=
147 seriesf
="$(get_temp series)"
148 recurse_deps_internal
--series -- "$serieshead" |
awk '{print $0 " " NR}' |
sort >"$seriesf"
150 [ -z "$tg_read_only" ] ||
[ -z "$tg_ref_cache" ] ||
! [ -s "$tg_ref_cache" ] ||
151 refslist
="-r=\"$tg_ref_cache\""
153 [ -z "$name" ] ||
[ "$serieshead" = "$name" ] || flagname
="$name"
155 v_get_tmopt tm_opt
"$head_from"
156 eval run_awk_topgit_msg
-n "-nokind${tm_opt:+ $tm_opt}" "$refslist" '"refs/$topbases"' |
157 join "$seriesf" - |
sort -k2,2n |
awk -v "flag=$flagname" '
161 if (flag != "") mark = (bn == flag) ? "* " : " "
164 sub(/^[^ ]+ [^ ]+ /, "", desc)
165 printf "%-39s\t%s\n", bn, desc
172 v_verify_topgit_branch name
"${name:-HEAD}"
174 if [ -n "$leaves" ]; then
175 v_get_tdopt with_deps_opts
"$head_from"
180 if [ -n "$deps$dependents" ]; then
181 alldeps
="$(get_temp alldeps)"
182 tg
--no-pager summary
$head_from --tgish-only --deps >"$alldeps" || die
"tg summary --deps failed"
183 if [ -n "$deps" ]; then
184 awk -v annb
="$name" 'NF == 2 && $2 != "" && $1 == annb { print $2 }' <"$alldeps"
186 awk -v annb
="$name" 'NF == 2 && $1 != "" && $2 == annb { print $1 }' <"$alldeps"
191 base_rev
="$(git rev-parse --short --verify "refs
/$topbases/$name^
0" -- 2>/dev/null)" ||
192 die
"not a TopGit-controlled branch"
194 measure
="$(measure_branch "refs
/heads
/$name" "$base_rev")"
196 echo "Topic Branch: $name ($measure)"
199 [ -z "$head_from" ] ||
! v_verify_topgit_branch tghead HEAD
-f ||
[ "$tghead" != "$name" ] || noskipiw
=1
200 [ -z "$noskipiw" ] || v_get_tmopt tm_opt
"$head_from"
201 read -r bkind subj
<<EOT
202 $(eval run_awk_topmsg_header "-kind${tm_opt:+ $tm_opt}" '"$name"')
204 [ "$bkind" = "3" ] ||
printf "Subject: %s\n" "$subj"
206 if [ "${verbose:-0}" -ge 1 ]; then
207 scratch
="$(get_temp scratch)"
208 printf '%s\n' "$name" >"$scratch"
209 dependents
="$(get_temp dependents_list)"
210 tg
--no-pager summary
$head_from --tgish-only --deps |
sort -k2,2 |
join -1 2 - "$scratch" | cut
-d ' ' -f 2 |
sort -u >"$dependents"
211 if ! [ -s "$dependents" ]; then
212 echo "Dependents: [none]"
214 if [ "${verbose:-0}" -le 1 ]; then
215 sed '1{ s/^/Dependents: /; n; }; s/^/ /;' <"$dependents"
218 while read -r endent
; do
219 [ ${#endent} -le $minwidth ] || minwidth
=${#endent}
222 while read -r endent
; do
224 contained_by
"refs/heads/$name" "refs/$topbases/$endent^0" || ood
=1
225 if [ -n "$ood" ]; then
226 printf '%s %-*s [needs merge]\n' "$prefix" $minwidth "$endent"
228 printf '%s %s\n' "$prefix" "$endent"
236 if [ "$bkind" = "3" ]; then
241 echo "Base: $base_rev"
242 branch_contains
"refs/heads/$name" "refs/$topbases/$name" ||
243 echo "* Base is newer than head! Please run \`$tgdisplay update\`."
246 if has_remote
"$name"; then
247 echo "Remote Mate: $base_remote/$name"
248 # has_remote only checks the single ref it's passed therefore
249 # check to see if the remote base is present especially since remote
250 # bases in the old location do not automatically fetched by default
251 if ref_exists
"refs/remotes/$base_remote/${topbases#heads/}/$name"; then
252 branch_contains
"refs/$topbases/$name" "refs/remotes/$base_remote/${topbases#heads/}/$name" ||
253 echo "* Local base is out of date wrt. the remote base."
255 echo "* Remote base ($base_remote/${topbases#heads/}/$name) is missing."
257 branch_contains
"refs/heads/$name" "refs/remotes/$base_remote/$name" ||
{
259 echo "* Local head is out of date wrt. the remote head."
261 branch_contains
"refs/remotes/$base_remote/$name" "refs/heads/$name" ||
262 echo "* Local head is ahead of the remote head."
265 # annihilated, empty and bare branches do not logically have any dependencies
266 # but we might be about to commit on an empty branch and with -i or -w it could
268 [ "$bkind" = "0" ] ||
[ "$bkind" = "1" ] ||
{
269 [ -n "$noskipiw" ] && [ -n "$head_from" ]
273 [ "${verbose:-0}" -lt 2 ] || anflag
=1
274 depslist
="$(get_temp topdeps)"
275 cat_file
"refs/heads/$name:.topdeps" ${noskipiw:+$head_from} >"$depslist" 2>/dev
/null
276 eval run_awk_topgit_msg
"$tm_opt" '"refs/$topbases"' "$(awk -v p="refs
/$topbases/" <"$depslist" '
278 gsub(/\047/, "\047\\\047\047", x)
279 return "\047" x "\047"
282 NF == 1 && $0 != "" && $0 !~ /[ \t\r\n*?:[^~\\]/ {printf "%s
", sq(p $0)}
283 ')" |
awk -v an
="$anflag" -v df
="$depslist" '
284 NF >= 2 && $1 != "" && $2 ~ /^[0-4]$/ {bt[$1] = 0 + $2}
287 while ((e = (getline adep <df)) > 0) {
289 if (adep == "" || adep ~ /[ \t\r\n*?:[^~\\]/) continue
290 if (!an && bt[adep] == 2) continue
292 if (bt[adep] == 2) suffix = " (annihilated)"
293 print prefix adep suffix
302 depcheck
="$(get_temp tg-depcheck)"
304 v_get_tdopt with_deps_opts
"$head_from"
305 needs_update
"$name" >"$depcheck" ||
:
306 [ -z "$rhood" ] ||
echo ":refs/remotes/$base_remote/$name $name" >>"$depcheck"
307 if [ -n "$missing_deps" ]; then
308 echo "MISSING: $missing_deps"
310 depcheck2
="$(get_temp tg-depcheck2)"
311 sed '/^!/d' <"$depcheck" >"$depcheck2"
312 if [ -s "$depcheck2" ]; then
313 echo "Needs update from:"
314 # 's/ [^ ]* *$//' -- last is $name
315 # 's/^[:] /::/' -- don't distinguish base updates
316 <"$depcheck2" sed -e 's/ [^ ]* *$//' -e 's/^[:] /:/' |
317 while read dep chain
; do
322 fulldep
="refs/heads/$dep"
323 extradep
="refs/$topbases/$dep"
330 fulldep
="refs/heads/$dep"
334 [ -z "$chain" ] ||
printf '%s' "(<= $(echol "$chain" | sed 's/ / <= /')) "
335 printf '%s' "($(eval measure_branch '"$fulldep"' '"refs
/heads
/$name"' ${extradep:+\"\$extradep\"}))"
339 echo "Up-to-date${missing_deps:+ (except for missing dependencies)}."