t/.gitattributes: add some binary attributes
[topgit/pro.git] / tg-checkout.sh
blob36fe8e445702a239a88fafda89376efb69324cf8
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 Kyle J. McKay <mackyle@gmail.com>
5 # All rights reserved.
6 # GPLv2
8 ## Parse options
10 USAGE="\
11 Usage: ${tgname:-tg} [...] checkout [--iow] [-f] [-b <branch>] (next | prev) [<steps>]
12 Or: ${tgname:-tg} [...] checkout [--iow] [-f] (next | prev) -a
13 Or: ${tgname:-tg} [...] checkout [--iow] [-f] [goto] [--] <pattern> | --series[=<head>]"
15 usage()
17 [ -z "$2" ] || printf '%s\n' "$2" >&2
18 if [ "${1:-0}" != 0 ]; then
19 printf '%s\n' "$USAGE" >&2
20 else
21 printf '%s\n' "$USAGE"
23 exit ${1:-0}
26 # Parse options
28 branch= # -b value
29 iowoptval= # "" or "$iowopt"
30 forceval= # "" or "-f"
31 mergeval= # "" or "-m"
32 quietval= # "" or "-q"
33 dashdash= # "" or "1" if [goto] "--" [--series[=<head>]] seen
35 while [ $# -gt 0 ]; do case "$1" in
36 -h|--help)
37 usage
39 -f|--force)
40 forceval="-f"
42 -m|--merge)
43 mergeval="-m"
45 -q|--quiet)
46 quietval="-q"
48 --ignore-other-worktrees|--iow)
49 iowoptval="$iowopt"
51 --branch=*)
52 branch="${1#--branch=}"
53 [ -n "$branch" ] || usage 1 "--branch= requires a branch name"
55 --branch|-b)
56 [ $# -ge 2 ] || usage 1 "$1 requires an argument"
57 branch="$2"
58 [ -n "$branch" ] || usage 1 "$1 requires a branch name"
59 shift
61 --series|--series=*)
62 dashdash=1
63 break
65 --|goto)
66 [ "$1" != "goto" ] || [ "$2" != "--" ] || shift
67 shift
68 dashdash=1
69 break
71 -[0-9]*)
72 break
74 -?*)
75 usage 1 "Unknown option: $1"
78 break
80 esac; shift; done
81 [ $# -ne 0 ] || [ -n "$dashdash" ] || {
82 # deprecated "next" alias
83 warn "support for \"tg checkout\" with no argument will soon be removed"
84 warn "please switch to equivalent \"tg checkout +\" to avoid breakage"
85 set -- "+"
87 [ $# -gt 0 ] || usage 1
88 pinstep=
89 [ -n "$dashdash" ] || {
90 case "$1" in +[0-9]*|-[0-9]*)
91 arg="$1"
92 shift
93 set -- "${arg%%[0-9]*}" "${arg#?}" "$@"
94 pinstep=1
95 esac
96 case "$1" in
97 +|n|next|push|child) shift;;
98 -|p|prev|previous|pop|parent|..) reverse=1; shift;;
99 -*) usage 1;;
100 *) dashdash=1;;
101 esac
104 choices="$(get_temp choices)"
105 desc=
107 if [ -n "$dashdash" ]; then
108 [ $# -eq 1 ] || usage 1 "goto mode requires exactly one pattern"
109 pattern="$1"
110 [ -n "$pattern" ] || usage 1 "goto mode requires a non-empty pattern"
111 case "$pattern" in
112 --series|--series=*)
113 tg --no-pager info "$pattern" "${branch:-HEAD}" >"$choices" || exit
114 desc=1
117 [ -z "$branch" ] || usage 1 "--branch not allowed in goto <pattern> mode"
118 tg --no-pager summary --list | grep -e "$pattern" >"$choices" || :
119 no_branch_found="No topic branch matches grep pattern '$pattern'"
121 esac
122 else
123 [ $# -gt 0 ] || set -- "1"
124 [ $# -eq 1 ] || usage 1 "next/previous permits no more than one argument"
125 case "$1" in
126 -a|--all)
127 [ -z "$branch" ] || usage 1 "--branch not allowed in --all mode"
128 navigate_deps -t -s=-1 ${reverse:+-r} >"$choices"
129 no_branch_found="No TopGit branches found at all!"
131 [1-9]*)
132 [ "$1" = "${1%%[!0-9]*}" ] || usage 1 "invalid next/previous step count"
133 v_verify_topgit_branch branch "${branch:-HEAD}"
134 navigate_deps -t -s="$1" ${reverse:+-r} ${pinstep:+-k} "$branch" >"$choices" || exit
135 pl="s" dir="next"
136 [ "$1" != 1 ] || pl=
137 [ -z "$reverse" ] || dir="previous"
138 no_branch_found="No $dir TopGit branch(es) found $1 step$pl away"
141 usage 1 "invalid next/previous movement; must be --all or positive number"
143 esac
146 cnt=$(( $(wc -l <"$choices") ))
147 [ $cnt -gt 0 ] || die "$no_branch_found"
149 if [ $cnt -eq 1 ]; then
150 read -r choice <"$choices" || :
151 choice="${choice%%[ $tab]*}"
152 [ -n "$choice" ] || die "$no_branch_found"
153 else
154 echo "Please select one of the following topic branches:"
155 awk -v "desc=$desc" <"$choices" '
156 BEGIN { colcount = 0 }
157 function cols() {
158 if (colcount) return colcount
159 sizer = "exec stty size 0>&2 2>/dev/null"
160 info = ""
161 sizer | getline info
162 close(sizer)
163 colcount = 0
164 if (split(info, nums, " ") >= 2 && nums[2] ~ /^[1-9][0-9]*$/)
165 colcount = 0 + nums[2]
166 if (!colcount) colcount = 80
167 return colcount
170 if ($0 ~ /^[* ] /) {
171 mark = substr($0, 1, 2)
172 names = substr($0, 3)
173 } else {
174 mark = ""
175 names = $0
177 cnt = split(names, name, " ")
178 if (!cnt) next
179 annotation = ""
180 if (cnt > 1) {
181 if (desc) {
182 annotation = names
183 sub(/^[ \t]+/, "", annotation)
184 sub(/^[^ \t]+[ \t]+/, "", annotation)
185 sub(/[ \t]+$/, "", annotation)
186 if (annotation != "") annotation = " " annotation
187 } else {
188 for (i = 2; i <= cnt; ++i) {
189 annotation = annotation ", " name[i]
191 annotation = " [" substr(annotation, 3) "]"
194 if (desc)
195 line = sprintf("%-39s%s", sprintf("%6d %s%s", NR, mark, name[1]), annotation)
196 else
197 line = sprintf("%6d %s%s%s", NR, mark, name[1], annotation)
198 printf "%.*s\n", cols() - 1, line
200 printf '%s' "Input the number: "
201 read -r n
202 [ -n "$n" ] && [ "$n" = "${n%%[!0-9]*}" ] || die "Bad input"
203 [ $n -ge 1 ] && [ $n -le $cnt ] || die "Input out of range"
204 choice="$(sed -n ${n}p <"$choices")" || :
205 case "$choice" in "* "*|" "*) choice="${choice#??}"; esac
206 choice="${choice%%[ $tab]*}"
207 [ -n "$choice" ] || die "Bad input"
209 git checkout $quietval $iowoptval $mergeval $forceval "$choice" --