-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgit-cb
More file actions
executable file
·239 lines (188 loc) · 5.85 KB
/
git-cb
File metadata and controls
executable file
·239 lines (188 loc) · 5.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#!/usr/bin/tclsh
package require Tcl 8.5
set thisbr ""
set brlist "" ;# others only
set remote_brlist "" ;# remote branches only
set remotes [join [exec git remote] " "]
foreach br [split [exec git branch --no-color --list -a 2>@stderr] \n] {
# Skip pointing branches
if { [string first " -> " $br] != -1 } {
continue
}
# Check if a branch contains multiple components
set parts [file split $br]
if { [llength $parts] > 1 } {
# Remote branch, probably, notify it as remote.
#puts "*D* REMOTE: '$br'"
# Trim required because the branch is preceded by 2 spaces.
if { [string trim [lindex $parts 0]] != "remote" } {
continue ;# XXX report error?
}
lappend remote_brlist [file join {*}[lrange $parts 1 end]]
continue
}
if { [string index $br 0] == "*" } {
set thisbr [string range $br 2 end]
} else {
lappend brlist [string range $br 2 end]
}
}
set breq [lindex $argv 0]
if { $breq == "" } {
puts $thisbr
exit 0
}
if { $breq == "--help" } {
puts stderr "Usage:\n"
puts stderr "[file tail $argv0] <branch name> <repo|=> # Switch to branch, maybe create, = as origin"
puts stderr "[file tail $argv0] -l # List remote and local branches with their connections."
exit 1
}
if { $breq == "-l" } {
# Look through all local branches (brlist)
# and display:
# - if only local, /BRANCH
# - if remote with identical name, REMOTE/BRANCH
# - if remote with different name: /BRANCH = REMOTE/RBRANCH
# thisbr was extracted as current, but in list mode we need
# to include it
lappend brlist $thisbr
foreach br $brlist {
if { [catch {exec git config --get branch.$br.remote} remote] } {
# This branch has no remote-tracking.
puts "/$br (LOCAL)"
continue
}
set brhead [exec git config --get branch.$br.merge]
# brhead = refs/heads/BRANCHNAME
set parts [file split $brhead]
if {[lrange $parts 0 1] != {refs heads}} {
continue; #error?
}
set rbranch [file join [lrange $parts 2 end]]
if { $rbranch == $br } {
puts "$remote/$br"
} else {
puts "/$br = $remote/$rbranch"
}
}
exit 0
}
# Check if this branch name is currently projected,
# no matter any further settings.
if { $breq == $thisbr } {
puts stderr "This branch is currently projected in your view"
exit 1
}
# Purpose of this tool.
#
# 1. Switch the view to the given branch name.
# 2. Branch should be created if doesn't exist.
# 3. If a remote is specified, the branch should be remote-tracking.
# 4. If a remote branch of given name exists, it should be simply bound.
# 5. If a remote branch doesn't exist, an entry should be added for tracking so that it's made remote.
# Possible call syntax:
# FIRST ARGUMENT: branch name. This branch must be set to the view,
# and created if it doesn't exist. Beside this:
# git cb dev-fix-error .
# -- Create local branch.
#
# git cb dev-fix-error =
# -- Create a remote-tracking branch from a default remote (origin)
#
# git cb dev-fix-error remo1
# -- Create a remote-tracking brach on a given remote
#
# git cb dev-fix-error remo1/fix-error
# -- Create a remote-tracking branch on given remote pinned into given remote branch name
#
# git cb dev-fix-error =/fix-error
# -- Default remote, use different branch name
if { $breq in $brlist } {
# Simply switch and do nothing else
puts "Existing branch, switching."
exec >@stdout 2>@stderr git checkout $breq
exit 0
}
set remo [lindex $argv 1]
if { $remo == "" } {
puts stderr "Usage error: Remote required, arg #2 should be:"
puts stderr " <remote> - explicit remote name"
puts stderr " = - the default remote"
puts stderr " =<prefix> - remote out of those in config that start with <prefix>"
puts stderr " . - no remote (local branch)"
exit 1
}
if { $remo == "." } {
# Local
# Check if there isn't a remote branch with this name,
# it might be confusing.
foreach r $remote_brlist {
set rbr [file join {*}[lassign [file split $r] remo]]
if {$breq == $rbr} {
puts stderr "Already exists as '$r', can be confusing. Use another name."
exit 1
}
}
puts "Creating this branch as local."
exec 2>@stderr >@stdout git checkout -b $breq
exit 0
}
set rparts [lassign [file split $remo] remo]
if {$rparts == ""} {
set remobr ""
} else {
set remobr [file join {*}$rparts]
}
if { $remo == "=" } {
set remo origin
} elseif { [string first = $remo] == 0 } {
set pfx [string range $remo 1 end]
set remotes [exec git remote]
set remo [lsearch -inline $remotes $pfx*]
if {$remo == ""} {
puts stderr "ERROR: no remote starting with '$pfx'"
puts stderr "Available: [join $remotes { }]"
exit 1
}
}
set all_remos [exec git remote]
if { $remo ni $all_remos } {
puts stderr "ERROR: No such remote '$remo'. Use = as alias to origin. Available remotes:"
puts stderr $all_remos
exit 1
}
if { $remobr == "" } {
set remobr $breq
}
# We request now the branch to track the local branch.
# First check if the branch was requested as remote tracked.
if {"$remo/$remobr" in $remote_brlist} {
# Easy. Create assignment
puts "Remote branch exists. Creating and assigning."
exec >@stdout git branch --track $breq $remo/$remobr 2>@stderr
} else {
exec >@stdout git branch $breq 2>@stderr
exec >@stdout git config branch.$breq.remote $remo 2>@stderr
exec >@stdout git config branch.$breq.merge refs/heads/$remobr 2>@stderr
puts " --- No remote branch - will be remote-created at first push (please ignore git complaints)"
}
set desc [lrange $argv 2 end]
if {$desc != ""} {
if {[llength $desc] == 1} {
set desc [lindex $desc 0]
}
exec >@stdout git config branch.$breq.description $desc
}
set checkedout [exec git status -s -uno]
if {$checkedout != ""} {
puts "NOTE: You have checkedout files, NOT CHECKING OUT branch."
puts "NOTE: Make sure that the repo state matches your needs, then do:"
puts "\tgit checkout $breq"
exit 1
}
if { [catch {exec >@stdout 2>@stderr git checkout $breq} result] } {
puts "Git complaints: $errorInfo"
puts $result
}
exit 0