1 # git-gui branch create support
2 # Copyright (C) 2006, 2007 Shawn Pearce
6 field w
; # widget path
7 field w_rev
; # mega-widget to pick the initial revision
8 field w_name
; # new branch name widget
10 field name
{}; # name of the branch the user has chosen
11 field name_type user
; # type of branch name to use
13 field opt_merge ff
; # type of merge to apply to existing branch
14 field opt_checkout
1; # automatically checkout the new branch?
15 field opt_fetch
1; # refetch tracking branch if used?
16 field reset_ok
0; # did the user agree to reset?
18 constructor dialog
{} {
22 wm title
$top "[appname] ([reponame]): Create Branch"
24 wm geometry
$top "+[winfo rootx .]+[winfo rooty .]"
27 label $w.header
-text {Create New Branch
} -font font_uibold
28 pack $w.header
-side top
-fill x
31 button $w.buttons.create
-text Create
\
34 pack $w.buttons.create
-side right
35 button $w.buttons.cancel
-text {Cancel
} \
36 -command [list destroy $w]
37 pack $w.buttons.cancel
-side right
-padx 5
38 pack $w.buttons
-side bottom
-fill x
-pady 10 -padx 10
40 labelframe $w.desc
-text {Branch Name
}
41 radiobutton $w.desc.name_r
\
46 set w_name
$w.desc.name_t
53 -validatecommand [cb _validate
%d
%S
]
54 grid $w.desc.name_r
$w_name -sticky we
-padx {0 5}
56 radiobutton $w.desc.match_r
\
58 -text {Match Tracking Branch Name
} \
61 grid $w.desc.match_r
-sticky we
-padx {0 5} -columnspan 2
63 grid columnconfigure
$w.desc
1 -weight 1
64 pack $w.desc
-anchor nw
-fill x
-pady 5 -padx 5
66 set w_rev
[::choose_rev::new $w.rev
{Starting Revision
}]
67 pack $w.rev
-anchor nw
-fill both
-expand 1 -pady 5 -padx 5
69 labelframe $w.
options -text {Options
}
71 frame $w.
options.merge
72 label $w.
options.merge.l
-text {Update Existing Branch
:}
73 pack $w.
options.merge.l
-side left
74 radiobutton $w.
options.merge.no
\
78 pack $w.
options.merge.no
-side left
79 radiobutton $w.
options.merge.ff
\
80 -text {Fast Forward Only
} \
83 pack $w.
options.merge.ff
-side left
84 radiobutton $w.
options.merge.reset
\
88 pack $w.
options.merge.reset
-side left
89 pack $w.
options.merge
-anchor nw
91 checkbutton $w.
options.fetch
\
92 -text {Fetch Tracking Branch
} \
94 pack $w.
options.fetch
-anchor nw
96 checkbutton $w.
options.checkout
\
97 -text {Checkout After Creation
} \
98 -variable @opt_checkout
99 pack $w.
options.checkout
-anchor nw
100 pack $w.
options -anchor nw
-fill x
-pady 5 -padx 5
102 trace add
variable @name_type write
[cb _select
]
104 set name
$repo_config(gui.newbranchtemplate
)
105 if {[is_config_true gui.matchtrackingbranch
]} {
109 bind $w <Visibility
> [cb _visible
]
110 bind $w <Key-Escape
> [list destroy $w]
111 bind $w <Key-Return
> [cb _create
]\;break
116 global repo_config current_branch
119 set spec
[$w_rev get_tracking_branch
]
120 switch -- $name_type {
129 -title [wm title
$w] \
131 -message "Please select a tracking branch."
134 if {![regsub ^refs
/heads
/ [lindex $spec 2] {} newbranch
]} {
138 -title [wm title
$w] \
140 -message "Tracking branch [$w get] is not a branch in the remote repository."
147 ||
$newbranch eq
$repo_config(gui.newbranchtemplate
)} {
151 -title [wm title
$w] \
153 -message "Please supply a branch name."
158 if {$newbranch eq
$current_branch} {
162 -title [wm title
$w] \
164 -message "'$newbranch' already exists and is the current branch."
169 if {[catch {git check-ref-format
"heads/$newbranch"}]} {
173 -title [wm title
$w] \
175 -message "'$newbranch' is not an acceptable branch name."
180 if {$spec ne
{} && $opt_fetch} {
181 set l_trck
[lindex $spec 0]
182 set remote
[lindex $spec 1]
183 set r_head
[lindex $spec 2]
184 regsub ^refs
/heads
/ $r_head {} r_head
188 wm title
$c "Refreshing Tracking Branch"
189 wm geometry
$c "+[winfo rootx $w]+[winfo rooty $w]"
191 set e
[::console::embed \
193 "Fetching $r_head from $remote"]
194 pack $c.
console -fill both
-expand 1
196 [list git fetch
$remote +$r_head:$l_trck] \
197 [cb _finish_fetch
$newbranch $c $e]
199 bind $c <Visibility
> [list grab $c]
200 bind $c <$M1B-Key
-w
> break
201 bind $c <$M1B-Key
-W
> break
202 wm protocol
$c WM_DELETE_WINDOW
[cb _noop
]
204 _finish_create
$this $newbranch
210 method _finish_fetch
{newbranch c e ok
} {
211 wm protocol
$c WM_DELETE_WINDOW
{}
215 _finish_create
$this $newbranch
218 button $c.
close -text Close
-command [list destroy $c]
219 pack $c.
close -side bottom
-anchor e
-padx 10 -pady 10
223 method _finish_create
{newbranch
} {
224 global null_sha1 all_heads
226 if {[catch {set new
[$w_rev commit_or_die
]}]} {
230 set ref refs
/heads
/$newbranch
231 if {[catch {set cur
[git rev-parse
--verify "$ref^0"]}]} {
232 # Assume it does not exist, and that is what the error was.
234 set reflog_msg
"branch: Created from [$w_rev get]"
236 } elseif
{$opt_merge eq
{no
}} {
240 -title [wm title
$w] \
242 -message "Branch '$newbranch' already exists."
247 catch {set mrb
[git merge-base
$new $cur]}
248 switch -- $opt_merge {
251 # The current branch is actually newer.
254 } elseif
{$mrb eq
$cur} {
255 # The current branch is older.
257 set reflog_msg
"merge [$w_rev get]: Fast-forward"
262 -title [wm title
$w] \
264 -message "Branch '$newbranch' already exists.\n\nIt cannot fast-forward to [$w_rev get].\nA merge is required."
271 # The current branch is older.
273 set reflog_msg
"merge [$w_rev get]: Fast-forward"
275 # The current branch will lose things.
277 if {[_confirm_reset
$this $newbranch $cur $new]} {
278 set reflog_msg
"reset [$w_rev get]"
288 -title [wm title
$w] \
290 -message "Branch '$newbranch' already exists."
299 git update-ref
-m $reflog_msg $ref $new $cur
304 -title [wm title
$w] \
306 -message "Failed to create '$newbranch'.\n\n$err"
311 if {$cur eq
$null_sha1} {
312 lappend all_heads
$newbranch
313 set all_heads
[lsort -uniq $all_heads]
319 switch_branch
$newbranch
323 method _confirm_reset
{newbranch cur new
} {
325 set gitk
[list do_gitk
[list $cur ^
$new]]
327 set c
$w.confirm_reset
329 wm title
$c "Confirm Branch Reset"
330 wm geometry
$c "+[winfo rootx $w]+[winfo rooty $w]"
332 pack [label $c.msg1
\
335 -text "Resetting '$newbranch' to [$w_rev get] will lose the following commits:" \
345 -xscrollcommand [list $c.
list.sbx
set] \
346 -yscrollcommand [list $c.
list.sby
set]
347 scrollbar $c.
list.sbx
-orient h
-command [list $list xview
]
348 scrollbar $c.
list.sby
-orient v
-command [list $list yview
]
349 pack $c.
list.sbx
-fill x
-side bottom
350 pack $c.
list.sby
-fill y
-side right
351 pack $list -fill both
-expand 1
352 pack $c.
list -fill both
-expand 1 -padx 5 -pady 5
354 pack [label $c.msg2
\
357 -text "Recovering lost commits may not be easy." \
359 pack [label $c.msg3
\
362 -text "Reset '$newbranch'?" \
366 button $c.buttons.visualize
\
369 pack $c.buttons.visualize
-side left
370 button $c.buttons.reset
\
376 pack $c.buttons.reset
-side right
377 button $c.buttons.cancel
\
380 -command [list destroy $c]
381 pack $c.buttons.cancel
-side right
-padx 5
382 pack $c.buttons
-side bottom
-fill x
-pady 10 -padx 10
384 set fd
[open "| git rev-list --pretty=oneline $cur ^$new" r
]
385 while {[gets $fd line
] > 0} {
386 set abbr
[string range
$line 0 7]
387 set subj
[string range
$line 41 end
]
388 $list insert end
"$abbr $subj\n"
391 $list configure
-state disabled
393 bind $c <Key-v
> $gitk
395 bind $c <Visibility
> "
397 focus $c.buttons.cancel
399 bind $c <Key-Return
> [list destroy $c]
400 bind $c <Key-Escape
> [list destroy $c]
405 method _validate
{d S
} {
407 if {[regexp {[~^
:?
*\[\0- ]} $S]} {
410 if {[string length
$S] > 0} {
417 method _select
{args
} {
418 if {$name_type eq
{match
}} {
419 $w_rev pick_tracking_branch
425 if {$name_type eq
{user
}} {