tg.sh: avoid modifying a symbolic link pre-commit hook
[topgit/pro.git] / tg-checkout.sh
blob369a0aaf233b50a8d06c5e8a3b236d6f28c61bbf
1 #!/bin/sh
2 # TopGit - A different patch queue manager
3 # Copyright (C) 2013 Per Cederqvist <ceder@lysator.liu.se>
4 # Copyright (C) 2015 Kyle J. McKay <mackyle@gmail.com>
5 # All rights reserved.
6 # GPLv2
8 ## Parse options
10 USAGE="Usage: ${tgname:-tg} [...] checkout [ [ push | pop ] [ -a ] | [goto] [--] <pattern> ]"
12 # Subcommands.
13 push=
14 pop=
15 goto=
17 # Options of "push" and "pop".
18 all=
20 # Arguments of "goto".
21 pattern=
23 checkout() {
24 _head="$(git rev-parse --revs-only --abbrev-ref=loose HEAD --)"
25 ref_exists "refs/$topbases/$_head" && branch_annihilated "$_head" && _checkout_opts="-f"
26 git checkout ${_checkout_opts} "$1"
29 while [ $# -gt 0 ]; do
30 arg="$1"
31 shift
33 case "$arg" in
34 -h|--help)
35 printf '%s\n' "$USAGE"
36 exit 0;;
37 -a|--all)
38 all=1;;
39 child|next|push)
40 push=1;;
41 parent|prev|pop|..)
42 pop=1;;
43 goto|--)
44 goto=1
45 [ "$arg" = "--" -o "$1" != "--" ] || shift
46 if [ $# -gt 0 ]; then
47 pattern="$1"
48 shift
49 fi;;
51 if [ -z "$all$push$pop$goto" -a -n "$arg" ]; then
52 goto=1
53 pattern="$arg"
54 else
55 printf '%s\n' "$USAGE" >&2
56 exit 1
57 fi;;
58 esac
59 done
61 if [ "$goto$all" = 11 ]; then
62 die "goto -a does not make sense."
65 if [ -z "$push$pop$goto" ]; then
66 # Default subcommand is "push". This was the most reasonable
67 # opposite of ".." that I could figure out. "goto" would also
68 # make sense as the default command, I suppose.
69 push=1
72 [ "$push$pop$goto" = "1" ] || { err "incompatible options"; printf '%s\n' "$USAGE" >&2; exit 1; }
74 [ -n "$tg_tmp_dir" ] || die "tg-checkout must be run via '$tg checkout'"
75 _depfile="$(mktemp "$tg_tmp_dir/tg-co-deps.XXXXXX")"
76 _altfile="$(mktemp "$tg_tmp_dir/tg-co-alt.XXXXXX")"
78 if [ -n "$goto" ]; then
79 $tg summary -t | grep -e "$pattern" >"$_altfile" || :
80 no_branch_found="No topic branch matches grep pattern '$pattern'"
81 else
82 branch="$(git symbolic-ref -q HEAD)" || die "Working on a detached head"
83 branch="$(git rev-parse --revs-only --abbrev-ref "$branch" --)"
85 if [ -n "$pop" ]; then
86 no_branch_found="$branch does not depend on any topic"
87 else
88 no_branch_found="No topic depends on $branch"
91 if [ -z "$all" ]; then
92 if [ -n "$pop" ]; then
93 $tg prev -w >"$_altfile"
94 else
95 $tg next >"$_altfile"
97 else
98 $tg summary --deps >$_depfile || die "${tgname:-tg} summary failed"
100 if [ -n "$pop" ]; then
101 dir=pop
102 else
103 dir=push
105 script=@sharedir@/leaves.awk
106 awk -f @sharedir@/leaves.awk dir=$dir start=$branch <$_depfile | sort >"$_altfile"
110 _alts=$(( $(wc -l <"$_altfile") ))
111 if [ $_alts = 0 ]; then
112 die "$no_branch_found"
113 elif [ $_alts = 1 ]; then
114 checkout "$(cat "$_altfile")"
115 exit $?
118 catn() {
119 sed = | paste -d ":" - - | sed 's/^/ /;s/^ *\(......\):/\1 /'
122 echo Please select one of the following topic branches:
123 catn <"$_altfile"
124 printf '%s' "Input the number: "
125 read -r n
127 # Check the input
128 sane="$(sed 's/[^0-9]//g' <<-EOT
132 if [ -z "$n" ] || [ "$sane" != "$n" ]; then
133 die "Bad input"
135 if [ $n -lt 1 ] || [ $n -gt $_alts ]; then
136 die "Input out of range"
139 new_branch="$(sed -n ${n}p "$_altfile")"
140 [ -n "$new_branch" ] || die "Bad input"
142 checkout "$new_branch"