topgit: version 0.19.14
[topgit/pro.git] / tg-checkout.sh
blob60d77ade885a8a8e289beaf25c2fbf114205a73d
1 #!/bin/sh
2 # TopGit - A different patch queue manager
3 # Copyright (C) 2013 Per Cederqvist <ceder@lysator.liu.se>
4 # Copyright (C) 2015,2017,2018,2021 Kyle J. McKay <mackyle@gmail.com>
5 # All rights reserved
6 # GPLv2
8 ## Parse options
10 USAGE="\
11 Usage: ${tgname:-tg} [...] checkout [<opt>...] [-b <branch>] (next | prev) [<steps>]
12 Or: ${tgname:-tg} [...] checkout [<opt>...] (next | prev) -a
13 Or: ${tgname:-tg} [...] checkout [<opt>...] [goto] [--] <pattern> | --series[=<head>]
14 Options:
15 --iow pass '--ignore-other-worktrees' to git >= v2.5.0
16 --force / -f pass '--force' option to git
17 --merge / -m pass '--merge' option to git
18 --quiet / -q pass '--quiet' option to git
19 --branch <branch> start at branch <branch> instead of HEAD
20 -b <branch> alias for --branch <branch>
21 --all / -a step as many times as possible"
23 usage()
25 [ -z "$2" ] || printf '%s\n' "$2" >&2
26 if [ "${1:-0}" != 0 ]; then
27 printf '%s\n' "$USAGE" >&2
28 else
29 printf '%s\n' "$USAGE"
31 exit ${1:-0}
34 # Parse options
36 branch= # -b value
37 iowoptval= # "" or "$iowopt"
38 forceval= # "" or "-f"
39 mergeval= # "" or "-m"
40 quietval= # "" or "-q"
41 dashdash= # "" or "1" if [goto] "--" [--series[=<head>]] seen
43 while [ $# -gt 0 ]; do case "$1" in
44 -h|--help)
45 usage
47 -f|--force)
48 forceval="-f"
50 -m|--merge)
51 mergeval="-m"
53 -q|--quiet)
54 quietval="-q"
56 --ignore-other-worktrees|--iow)
57 iowoptval="$iowopt"
59 --branch=*)
60 branch="${1#--branch=}"
61 [ -n "$branch" ] || usage 1 "--branch= requires a branch name"
63 --branch|-b)
64 [ $# -ge 2 ] || usage 1 "$1 requires an argument"
65 branch="$2"
66 [ -n "$branch" ] || usage 1 "$1 requires a branch name"
67 shift
69 --series|--series=*)
70 dashdash=1
71 break
73 --|goto)
74 [ "$1" != "goto" ] || [ "$2" != "--" ] || shift
75 shift
76 dashdash=1
77 break
79 -[0-9]*)
80 break
82 -?*)
83 usage 1 "Unknown option: $1"
86 break
88 esac; shift; done
89 [ $# -ne 0 ] || [ -n "$dashdash" ] || {
90 # deprecated "next" alias
91 warn "support for \"tg checkout\" with no argument will soon be removed"
92 warn "please switch to equivalent \"tg checkout +\" to avoid breakage"
93 set -- "+"
95 [ $# -gt 0 ] || usage 1
96 pinstep=
97 [ -n "$dashdash" ] || {
98 case "$1" in +[0-9]*|-[0-9]*)
99 arg="$1"
100 shift
101 set -- "${arg%%[0-9]*}" "${arg#?}" "$@"
102 pinstep=1
103 esac
104 case "$1" in
105 +|n|next|push|child) shift;;
106 -|p|prev|previous|pop|parent|..) reverse=1; shift;;
107 -*) usage 1;;
108 *) dashdash=1;;
109 esac
112 choices="$(get_temp choices)"
113 desc=
115 if [ -n "$dashdash" ]; then
116 [ $# -eq 1 ] || usage 1 "goto mode requires exactly one pattern"
117 pattern="$1"
118 [ -n "$pattern" ] || usage 1 "goto mode requires a non-empty pattern"
119 case "$pattern" in
120 --series|--series=*)
121 tg --no-pager info "$pattern" "${branch:-HEAD}" >"$choices" || exit
122 desc=1
125 [ -z "$branch" ] || usage 1 "--branch not allowed in goto <pattern> mode"
126 tg --no-pager summary --list | grep -e "$pattern" >"$choices" || :
127 no_branch_found="No topic branch matches grep pattern '$pattern'"
129 esac
130 else
131 [ $# -gt 0 ] || set -- "1"
132 [ $# -eq 1 ] || usage 1 "next/previous permits no more than one argument"
133 case "$1" in
134 -a|--all)
135 [ -z "$branch" ] || usage 1 "--branch not allowed in --all mode"
136 navigate_deps -t -s=-1 ${reverse:+-r} >"$choices"
137 no_branch_found="No TopGit branches found at all!"
139 [1-9]*)
140 [ "$1" = "${1%%[!0-9]*}" ] || usage 1 "invalid next/previous step count"
141 v_verify_topgit_branch branch "${branch:-HEAD}"
142 navigate_deps -t -s="$1" ${reverse:+-r} ${pinstep:+-k} "$branch" >"$choices" || exit
143 pl="s" dir="next"
144 [ "$1" != 1 ] || pl=
145 [ -z "$reverse" ] || dir="previous"
146 no_branch_found="No $dir TopGit branch(es) found $1 step$pl away"
149 usage 1 "invalid next/previous movement; must be --all or positive number"
151 esac
154 cnt=$(( $(wc -l <"$choices") ))
155 [ $cnt -gt 0 ] || die "$no_branch_found"
157 if [ $cnt -eq 1 ]; then
158 read -r choice <"$choices" || :
159 choice="${choice%%[ $tab]*}"
160 [ -n "$choice" ] || die "$no_branch_found"
161 else
162 echo "Please select one of the following topic branches:"
163 awk -v "desc=$desc" <"$choices" '
164 BEGIN { colcount = 0 }
165 function cols() {
166 if (colcount) return colcount
167 sizer = "exec stty size 0>&2 2>/dev/null"
168 info = ""
169 sizer | getline info
170 close(sizer)
171 colcount = 0
172 if (split(info, nums, " ") >= 2 && nums[2] ~ /^[1-9][0-9]*$/)
173 colcount = 0 + nums[2]
174 if (!colcount) colcount = 80
175 return colcount
178 if ($0 ~ /^[* ] /) {
179 mark = substr($0, 1, 2)
180 names = substr($0, 3)
181 } else {
182 mark = ""
183 names = $0
185 cnt = split(names, name, " ")
186 if (!cnt) next
187 annotation = ""
188 if (cnt > 1) {
189 if (desc) {
190 annotation = names
191 sub(/^[ \t]+/, "", annotation)
192 sub(/^[^ \t]+[ \t]+/, "", annotation)
193 sub(/[ \t]+$/, "", annotation)
194 if (annotation != "") annotation = " " annotation
195 } else {
196 for (i = 2; i <= cnt; ++i) {
197 annotation = annotation ", " name[i]
199 annotation = " [" substr(annotation, 3) "]"
202 if (desc)
203 line = sprintf("%-39s%s", sprintf("%6d %s%s", NR, mark, name[1]), annotation)
204 else
205 line = sprintf("%6d %s%s%s", NR, mark, name[1], annotation)
206 printf "%.*s\n", cols() - 1, line
208 printf '%s' "Input the number: "
209 read -r n
210 [ -n "$n" ] && [ "$n" = "${n%%[!0-9]*}" ] || die "Bad input"
211 [ $n -ge 1 ] && [ $n -le $cnt ] || die "Input out of range"
212 choice="$(sed -n ${n}p <"$choices")" || :
213 case "$choice" in "* "*|" "*) choice="${choice#??}"; esac
214 choice="${choice%%[ $tab]*}"
215 [ -n "$choice" ] || die "Bad input"
217 git checkout $quietval $iowoptval $mergeval $forceval "$choice" --