tg: add missing '[...]' to a few usage lines
[topgit/pro.git] / tg-update.sh
blob273694635d744f895aff1797a0c1c0a91283f04d
1 #!/bin/sh
2 # TopGit - A different patch queue manager
3 # (c) Petr Baudis <pasky@suse.cz> 2008
4 # GPLv2
6 name= # Branch to update
7 all= # Update all branches
8 pattern= # Branch selection filter for -a
9 current= # Branch we are currently on
10 skip= # skip missing dependencies
12 ## Parse options
14 while [ -n "$1" ]; do
15 arg="$1"; shift
16 case "$arg" in
17 -a)
18 all=1;;
19 --skip)
20 skip=1;;
21 -*)
22 echo "Usage: ${tgname:-tg} [...] update [--skip] ([<name>] | -a [<pattern>...])" >&2
23 exit 1;;
25 if [ -z "$all" ]; then
26 [ -z "$name" ] || die "name already specified ($name)"
27 name="$arg"
28 else
29 pattern="$pattern refs/top-bases/${arg#refs/top-bases/}"
32 esac
33 done
34 [ -z "$pattern" ] && pattern=refs/top-bases
36 current="$(strip_ref "$(git symbolic-ref HEAD 2>/dev/null)")"
37 if [ -z "$all" ]; then
38 name="$(verify_topgit_branch "${name:-HEAD}")"
39 else
40 [ -n "$current" ] || die "cannot return to detached tree; switch to another branch"
43 ensure_clean_tree
45 recursive_update() {
46 $tg update ${skip:+--skip}
47 _ret=$?
48 [ $_ret -eq 3 ] && exit 3
49 return $_ret
52 update_branch() {
53 _update_name="$1"
54 ## First, take care of our base
56 _depcheck="$(get_temp tg-depcheck)"
57 missing_deps=
58 needs_update "$_update_name" >"$_depcheck" || :
59 if [ -n "$missing_deps" ]; then
60 msg="Some dependencies are missing: $missing_deps"
61 if [ -n "$skip" ]; then
62 info "$msg; skipping"
63 elif [ -z "$all" ]; then
64 die "$msg"
65 else
66 info "$msg; skipping branch $_update_name"
67 return
70 if [ -s "$_depcheck" ]; then
71 # We need to switch to the base branch
72 # ...but only if we aren't there yet (from failed previous merge)
73 _HEAD="$(git symbolic-ref HEAD)"
74 if [ "$_HEAD" = "${_HEAD#refs/top-bases/}" ]; then
75 switch_to_base "$_update_name"
78 cat "$_depcheck" |
79 sed 's/ [^ ]* *$//' | # last is $_update_name
80 sed 's/.* \([^ ]*\)$/+\1/' | # only immediate dependencies
81 sed 's/^\([^+]\)/-\1/' | # now each line is +branch or -branch (+ == recurse)
82 uniq -s 1 | # fold branch lines; + always comes before - and thus wins within uniq
83 while read depline; do
84 action="$(echo "$depline" | cut -c 1)"
85 dep="$(echo "$depline" | cut -c 2-)"
87 # We do not distinguish between dependencies out-of-date
88 # and base/remote out-of-date cases for $dep here,
89 # but thanks to needs_update returning : or %
90 # for the latter, we do correctly recurse here
91 # in both cases.
93 if [ x"$action" = x+ ]; then
94 case " $missing_deps " in *" $dep "*)
95 info "Skipping recursing to missing dependency: $dep"
96 continue
97 esac
98 info "Recursing to $dep..."
99 git checkout -q "$dep"
101 export TG_RECURSIVE="[$dep] $TG_RECURSIVE"
102 export PS1="[$dep] $PS1"
103 while ! recursive_update; do
104 # The merge got stuck! Let the user fix it up.
105 info "You are in a subshell. If you abort the merge,"
106 info "use \`exit 1\` to abort the recursive update altogether."
107 info "Use \`exit 2\` to skip updating this branch and continue."
108 if "${SHELL:-/bin/sh}" -i </dev/tty; then
109 # assume user fixed it
110 continue
111 else
112 ret=$?
113 if [ $ret -eq 2 ]; then
114 info "Ok, I will try to continue without updating this branch."
115 break
116 else
117 info "Ok, you aborted the merge. Now, you just need to"
118 info "switch back to some sane branch using \`git$gitcdopt checkout\`."
119 exit 3
122 done
124 switch_to_base "$_update_name"
127 # This will be either a proper topic branch
128 # or a remote base. (branch_needs_update() is called
129 # only on the _dependencies_, not our branch itself!)
131 info "Updating base with $dep changes..."
132 if ! git merge "$dep"; then
133 if [ -z "$TG_RECURSIVE" ]; then
134 resume="\`$tgdisplay update${skip:+ --skip} $_update_name\` again"
135 else # subshell
136 resume='exit'
138 info "Please commit merge resolution and call $resume."
139 info "It is also safe to abort this operation using \`git$gitcdopt reset --hard\`,"
140 info "but please remember that you are on the base branch now;"
141 info "you will want to switch to some normal branch afterwards."
142 rm "$_depcheck"
143 exit 2
145 done
146 else
147 info "The base is up-to-date."
150 # Home, sweet home...
151 # (We want to always switch back, in case we were on the base from failed
152 # previous merge.)
153 git checkout -q "$_update_name"
155 merge_with="refs/top-bases/$_update_name"
158 ## Second, update our head with the remote branch
160 if has_remote "$_update_name"; then
161 _rname="refs/remotes/$base_remote/$_update_name"
162 if branch_contains "$_update_name" "$_rname"; then
163 info "The $_update_name head is up-to-date wrt. its remote branch."
164 else
165 info "Reconciling remote branch updates with $_update_name base..."
166 # *DETACH* our HEAD now!
167 git checkout -q "refs/top-bases/$_update_name"
168 if ! git merge "$_rname"; then
169 info "Oops, you will need to help me out here a bit."
170 info "Please commit merge resolution and call:"
171 info "git$gitcdopt checkout $_update_name && git$gitcdopt merge <commitid>"
172 info "It is also safe to abort this operation using: git$gitcdopt reset --hard $_update_name"
173 exit 4
175 # Go back but remember we want to merge with this, not base
176 merge_with="$(git rev-parse HEAD)"
177 git checkout -q "$_update_name"
182 ## Third, update our head with the base
184 if branch_contains "$_update_name" "$merge_with"; then
185 info "The $_update_name head is up-to-date wrt. the base."
186 return 0
188 info "Updating $_update_name against new base..."
189 if ! git merge "$merge_with"; then
190 if [ -z "$TG_RECURSIVE" ]; then
191 info "Please commit merge resolution. No need to do anything else"
192 info "You can abort this operation using \`git$gitcdopt reset --hard\` now"
193 info "and retry this merge later using \`$tgdisplay update${skip:+ --skip}\`."
194 else # subshell
195 info "Please commit merge resolution and call exit."
196 info "You can abort this operation using \`git$gitcdopt reset --hard\`."
198 exit 4
202 [ -z "$all" ] && { update_branch $name; exit; }
204 non_annihilated_branches $pattern |
205 while read name; do
206 info "Proccessing $name..."
207 update_branch "$name" || exit
208 done
210 info "Returning to $current..."
211 git checkout -q "$current"
212 # vim:noet