2 # TopGit contains command
3 # (C) 2017 Kyle J. McKay <mackyle@gmail.com>
8 Usage: ${tgname:-tg} [...] contains [-v] [-r] [--ann] [--no-strict] [--] <committish>"
12 if [ "${1:-0}" != 0 ]; then
13 printf '%s\n' "$USAGE" >&2
15 printf '%s\n' "$USAGE"
25 while [ $# -gt 0 ]; do case "$1" in
32 --ann|
--annihilated|
--annihilated-ok|
--annihilated-okay)
36 echo "Did you mean --verbose (-v) instead of --heads?" >&2
40 verbose
=$
(( ${verbose:-0} + 1 ))
42 -vv|
-vvv|
-vvvv|
-vvvvv)
43 verbose
=$
(( ${verbose:-0} + ${#1} - 1 ))
56 echo "Unknown option: $1" >&2
64 [ "$1" != "@" ] ||
set -- HEAD
67 findrev
="$(git rev-parse --verify "$1"^0 --)" ||
exit 1
69 # $1 => return correct $topbases value in here on success
71 # $3 => remote branch name
72 # succeeds if both refs/remotes/$2/$3 and refs/remotes/$2/${$1#heads/}/$3 exist
73 v_is_remote_tgbranch
()
75 git rev-parse
--quiet --verify "refs/remotes/$2/$3^0" -- >/dev
/null ||
return 1
76 if git rev-parse
--quiet --verify "refs/remotes/$2/${topbases#heads/}/$3^0" -- >/dev
/null
; then
77 [ -z "$1" ] ||
eval "$1="'"$topbases"'
80 git rev-parse
--quiet --verify "refs/remotes/$2/${oldbases#heads/}/$3^0" -- >/dev
/null ||
return 1
81 if [ -z "$annok" ]; then
82 rmb
="$(git merge-base "refs
/remotes
/$2/${oldbases#heads/}/$3^
0" "refs
/remotes
/$2/$3^
0" 2>/dev/null)" ||
:
83 if [ -n "$rmb" ]; then
84 rmbtree
="$(git rev-parse --quiet --verify "$rmb^
{tree
}" --)" ||
:
87 rbrtree
="$(git rev-parse --quiet --verify "refs
/remotes
/$2/$3^
{tree
}" --)" ||
:
88 [ -z "$rmbtree" ] ||
[ -z "$rbrtree" ] ||
[ "$rmbtree" != "$rbrtree" ] ||
return 1
91 [ -z "$1" ] ||
eval "$1="'"$oldbases"'
96 if [ -n "$_dep_is_tgish" ] && [ -z "$_dep_missing$_dep_annihilated" ]; then
97 printf '%s\n' "$_dep ${_depchain##* }"
106 depslist
="$(get_temp depslist)" ||
exit 1
107 tg summary
--topgit-heads |
108 while read -r onetghead
; do
109 printf '%s %s\n' "$onetghead" "$onetghead"
110 recurse_deps process_dep
"$onetghead"
111 done |
sort -u >"$depslist"
116 localb
="$(get_temp localb)" ||
exit 1
120 [ -z "$remotes" ] || remoteb
="$(get_temp remoteb)" ||
exit 1
122 while read -r branch bremote
&& [ -n "$branch" ]; do case "$branch" in
127 [ -z "$bremote" ] && v_verify_topgit_branch
"" "$branch" -f ||
continue
128 branch
="${branch#refs/heads/}"
129 [ -n "$annok" ] ||
! branch_annihilated
"$branch" ||
continue
130 if contained_by
"$findrev" "refs/$topbases/$branch"; then
131 [ -z "$strict" ] ||
continue
132 depth
="$(git rev-list --count --ancestry-path \
133 "refs
/$topbases/$branch" --not "$findrev")"
134 depth
=$
(( ${depth:-0} + 1 ))
138 localcnt
=$
(( ${localcnt:-0} + 1 ))
139 [ ${#branch} -le $localwide ] || localwide
=${#branch}
140 printf '%s %s\n' "$depth" "$branch" >>"$localb"
144 [ -n "$bremote" ] && [ -n "$remotes" ] && [ -z "$localcnt" ] &&
145 [ "${branch#refs/remotes/}" != "$branch" ] ||
continue
146 rbranch
="${branch#refs/remotes/$bremote/}"
147 [ "refs/remotes/$bremote/$rbranch" = "$branch" ] ||
continue
148 v_is_remote_tgbranch rtopbases
"$bremote" "$rbranch" ||
continue
149 if contained_by
"$findrev" "refs/remotes/$bremote/${rtopbases#heads/}/$rbranch"; then
150 [ -z "$strict" ] ||
continue
151 depth
="$(git rev-list --count --ancestry-path \
152 "refs
/remotes
/$bremote/${rtopbases#heads/}/$rbranch" --not "$findrev")"
153 depth
=$
(( ${depth:-0} + 1 ))
157 remotecnt
=$
(( ${remotecnt:-0} + 1 ))
158 branch
="${branch#refs/}"
159 [ ${#branch} -le $remotewide ] || remotewide
=${#branch}
160 [ -n "$remoteb" ] || remoteb
="$(get_temp remoteb)" ||
exit 1
161 printf '%s %s\n' "$depth" "remotes/$bremote/$rbranch" >>"$remoteb"
165 if [ -z "$remotes" ]; then
166 process_branches
<<EOT || exit 1
167 $(fer_branch_contains "$findrev")
170 ferlist
="$(get_temp ferlist)" ||
exit 1
171 fer_branch_contains
-a "$findrev" >"$ferlist" ||
exit 1
172 process_branches
<<EOT
173 $( awk -v tb="${topbases#heads/}" -v ob="${oldbases#heads/}" <"$ferlist" '
174 function join(a,b,e,_j,_r) {_r=""
175 for (_j=b;_j<=e;++_j)_r=_r"/"a[_j];return substr(_r,2)}
176 !/^refs\/remotes\/./ {next}
178 n=split(substr($0,14),c,/\//)
181 r=join(c,1,i); t=join(c,i+1,n)
182 print "refs/remotes/"r"/"tb"/"t" "r
183 print "refs/remotes/"r"/"ob"/"t" "r
186 ' | git cat-file $gcfbopt --batch-check='%(objectname) %(objecttype) %(rest)' |
187 awk -v f="$ferlist" '
188 function join(a,b,e,_j,_r) {_r=""
189 for (_j=b;_j<=e;++_j)_r=_r"/"a[_j];return substr(_r,2)}
190 !($2=="commit"&&$3!=""&&$1~/^[0-9a-f][0-9a-f][0-9a-f][0-9a-f]+$/){next}
193 while((e=(getline b<f))>0) {
194 if(b!~/^refs\/remotes\/./){print b;continue}
195 n=split(substr(b,14),c,/\//)
198 for (i=1;!d&&i<n;++i) {
200 if(r in p) {d=1;t=join(c,i+1,n)
201 print "refs/remotes/"r"/"t" "r}
211 [ -n "$localcnt$remotecnt" ] ||
exit 1
212 [ -z "$localcnt" ] ||
[ ${verbose:-0} -le 0 ] || make_deps_list
213 if [ -n "$localcnt" ]; then
221 sort -k1,1n
"$process" |
222 while read -r depth ref
; do
223 [ -n "$mindepth" ] || mindepth
="$depth"
224 [ $depth -le $mindepth ] ||
continue
227 while read -r oneresult
; do
230 [ -z "$annok" ] ||
[ -z "$depslist" ] ||
! branch_annihilated
"$oneresult" || isann
=1
231 [ -z "$depslist" ] ||
[ -n "$isann" ] ||
232 headinfo
="$(printf '%s\n' "$oneresult" | join -o 2.2 - "$depslist" |
233 sort -u | paste -d , -s - | sed -e 's/,/, /g')"
234 [ -z "$annok" ] ||
[ -z "$depslist" ] ||
[ -z "$isann" ] || headinfo
=":annihilated:"
235 if [ -z "$headinfo" ]; then
236 printf '%s\n' "$oneresult"
238 printf '%-*s [%s]\n' $minwide "$oneresult" "$headinfo"