tg-push: pass more options through to git push
[topgit/pro.git] / tg-contains.sh
blob671ea91d4f1576234730a893fa0a6ff896b84e3d
1 #!/bin/sh
2 # TopGit contains command
3 # (C) 2017 Kyle J. McKay <mackyle@gmail.com>
4 # All rights reserved
5 # GPLv2
7 USAGE="\
8 Usage: ${tgname:-tg} [...] contains [-v] [-r] [--ann] [--no-strict] [--] <committish>"
10 usage()
12 if [ "${1:-0}" != 0 ]; then
13 printf '%s\n' "$USAGE" >&2
14 else
15 printf '%s\n' "$USAGE"
17 exit ${1:-0}
20 verbose=
21 remotes=
22 strict=1
23 annok=
25 while [ $# -gt 0 ]; do case "$1" in
26 -h|--help)
27 usage
29 -r|--remotes)
30 remotes=1
32 --ann|--annihilated|--annihilated-ok|--annihilated-okay)
33 annok=1
35 --heads)
36 echo "Did you mean --verbose (-v) instead of --heads?" >&2
37 usage 1
39 -v|--verbose)
40 verbose=$(( ${verbose:-0} + 1 ))
42 -vv|-vvv|-vvvv|-vvvvv)
43 verbose=$(( ${verbose:-0} + ${#1} - 1 ))
45 --strict)
46 strict=1
48 --no-strict)
49 strict=
51 --)
52 shift
53 break
55 -?*)
56 echo "Unknown option: $1" >&2
57 usage 1
60 break
62 esac; shift; done
63 [ $# = 1 ] || usage 1
64 [ "$1" != "@" ] || set -- HEAD
66 set -e
67 findrev="$(git rev-parse --verify "$1"^0 --)" || exit 1
69 # $1 => return correct $topbases value in here on success
70 # $2 => remote name
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"'
78 return 0
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}" --)" || :
85 rbrtree=
86 [ -z "$rmbtree" ] ||
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"'
94 process_dep()
96 if [ -n "$_dep_is_tgish" ] && [ -z "$_dep_missing$_dep_annihilated" ]; then
97 printf '%s\n' "$_dep ${_depchain##* }"
101 depslist=
102 make_deps_list()
104 no_remotes=1
105 base_remote=
106 depslist="$(get_temp depslist)"
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"
114 localcnt=
115 remotecnt=
116 localb="$(get_temp localb)"
117 localwide=0
118 remoteb=
119 remotewide=0
120 [ -z "$remotes" ] || remoteb="$(get_temp remoteb)"
121 while IFS= read -r branch && [ -n "$branch" ]; do
122 branch="${branch#??}"
123 case "$branch" in ""|*[" $tab"]*) continue; esac
124 if v_verify_topgit_branch "" "$branch" -f; then
125 [ -n "$annok" ] || ! branch_annihilated "$branch" || continue
126 if contained_by "$findrev" "refs/$topbases/$branch"; then
127 [ -z "$strict" ] || continue
128 depth="$(git rev-list --count --ancestry-path "refs/$topbases/$branch" --not "$findrev")"
129 depth=$(( ${depth:-0} + 1 ))
130 else
131 depth=0
133 localcnt=$(( ${localcnt:-0} + 1 ))
134 [ ${#branch} -le $localwide ] || localwide=${#branch}
135 printf '%s %s\n' "$depth" "$branch" >>"$localb"
136 remotecnt=
137 else
138 [ -n "$remotes" ] && [ -z "$localcnt" ] && [ "${branch#remotes/}" != "$branch" ] || continue
139 rbranch="${branch#remotes/}"
140 rremote="${rbranch%%/*}"
141 rbranch="${rbranch#*/}"
142 [ "remotes/$rremote/$rbranch" = "$branch" ] || continue
143 v_is_remote_tgbranch rtopbases "$rremote" "$rbranch" || continue
144 if contained_by "$findrev" "refs/remotes/$rremote/${rtopbases#heads/}/$rbranch"; then
145 [ -z "$strict" ] || continue
146 depth="$(git rev-list --count --ancestry-path "refs/remotes/$rremote/${rtopbases#heads/}/$rbranch" --not "$findrev")"
147 depth=$(( ${depth:-0} + 1 ))
148 else
149 depth=0
151 remotecnt=$(( ${remotecnt:-0} + 1 ))
152 [ ${#branch} -le $remotewide ] || remotewide=${#branch}
153 [ -n "$remoteb" ] || remoteb="$(get_temp remoteb)"
154 printf '%s %s\n' "$depth" "remotes/$rremote/$rbranch" >>"$remoteb"
156 done <<EOT
157 $(git branch --no-color ${remotes:+-a} --contains "$findrev")
159 [ -n "$localcnt$remotecnt" ] || exit 1
160 [ -z "$localcnt" ] || [ ${verbose:-0} -le 0 ] || make_deps_list
161 if [ -n "$localcnt" ]; then
162 process="$localb"
163 minwide=$localwide
164 else
165 process="$remoteb"
166 minwide=$remotewide
169 sort -k1,1n "$process" |
170 while read -r depth ref; do
171 [ -n "$mindepth" ] || mindepth="$depth"
172 [ $depth -le $mindepth ] || continue
173 printf '%s\n' "$ref"
174 done | sort -u |
175 while read -r oneresult; do
176 headinfo=
177 isann=
178 [ -z "$annok" ] || [ -z "$depslist" ] || ! branch_annihilated "$oneresult" || isann=1
179 [ -z "$depslist" ] || [ -n "$isann" ] ||
180 headinfo="$(printf '%s\n' "$oneresult" | join -o 2.2 - "$depslist" |
181 sort -u | paste -d , -s - | sed -e 's/,/, /g')"
182 [ -z "$annok" ] || [ -z "$depslist" ] || [ -z "$isann" ] || headinfo=":annihilated:"
183 if [ -z "$headinfo" ]; then
184 printf '%s\n' "$oneresult"
185 else
186 printf '%-*s [%s]\n' $minwide "$oneresult" "$headinfo"
188 done
189 exit 0