1 # git-gui branch (create/delete) support
2 # Copyright (C) 2006, 2007 Shawn Pearce
4 proc load_all_heads {} {
8 set fd [open "| git for-each-ref --format=%(refname) refs/heads" r]
9 while {[gets $fd line] > 0} {
10 if {[is_tracking_branch $line]} continue
11 if {![regsub ^refs/heads/ $line {} name]} continue
12 lappend all_heads $name
16 set all_heads [lsort $all_heads]
19 proc load_all_tags {} {
21 set fd [open "| git for-each-ref --format=%(refname) refs/tags" r]
22 while {[gets $fd line] > 0} {
23 if {![regsub ^refs/tags/ $line {} name]} continue
24 lappend all_tags $name
28 return [lsort $all_tags]
31 proc populate_branch_menu {} {
32 global all_heads disable_on_lock
35 set last [$m index last]
36 for {set i 0} {$i <= $last} {incr i} {
37 if {[$m type $i] eq {separator}} {
40 foreach a $disable_on_lock {
41 if {[lindex $a 0] ne $m || [lindex $a 2] < $i} {
45 set disable_on_lock $new_dol
50 if {$all_heads ne {}} {
53 foreach b $all_heads {
56 -command [list switch_branch $b] \
57 -variable current_branch \
59 lappend disable_on_lock \
60 [list $m entryconf [$m index last] -state]
64 proc radio_selector {varname value args} {
69 proc switch_branch {new_branch} {
70 global HEAD commit_type current_branch repo_config
72 if {![lock_index switch]} return
74 # -- Our in memory state should match the repository.
76 repository_state curType curHEAD curMERGE_HEAD
77 if {[string match amend* $commit_type]
78 && $curType eq {normal}
79 && $curHEAD eq $HEAD} {
80 } elseif {$commit_type ne $curType || $HEAD ne $curHEAD} {
81 info_popup {Last scanned state does not match repository state.
83 Another Git program has modified this repository since the last scan. A rescan must be performed before the current branch can be changed.
85 The rescan will be automatically started now.
88 rescan {set ui_status_value {Ready.}}
92 # -- Don't do a pointless switch.
94 if {$current_branch eq $new_branch} {
99 if {$repo_config(gui.trustmtime) eq {true}} {
100 switch_branch_stage2 {} $new_branch
102 set ui_status_value {Refreshing file status...}
103 set cmd [list git update-index]
105 lappend cmd --unmerged
106 lappend cmd --ignore-missing
107 lappend cmd --refresh
108 set fd_rf [open "| $cmd" r]
109 fconfigure $fd_rf -blocking 0 -translation binary
110 fileevent $fd_rf readable \
111 [list switch_branch_stage2 $fd_rf $new_branch]
115 proc switch_branch_stage2 {fd_rf new_branch} {
116 global ui_status_value HEAD
120 if {![eof $fd_rf]} return
124 set ui_status_value "Updating working directory to '$new_branch'..."
125 set cmd [list git read-tree]
128 lappend cmd --exclude-per-directory=.gitignore
130 lappend cmd $new_branch
131 set fd_rt [open "| $cmd" r]
132 fconfigure $fd_rt -blocking 0 -translation binary
133 fileevent $fd_rt readable \
134 [list switch_branch_readtree_wait $fd_rt $new_branch]
137 proc switch_branch_readtree_wait {fd_rt new_branch} {
138 global selected_commit_type commit_type HEAD MERGE_HEAD PARENT
139 global current_branch
140 global ui_comm ui_status_value
142 # -- We never get interesting output on stdout; only stderr.
145 fconfigure $fd_rt -blocking 1
147 fconfigure $fd_rt -blocking 0
151 # -- The working directory wasn't in sync with the index and
152 # we'd have to overwrite something to make the switch. A
155 if {[catch {close $fd_rt} err]} {
156 regsub {^fatal: } $err {} err
157 warn_popup "File level merge required.
161 Staying on branch '$current_branch'."
162 set ui_status_value "Aborted checkout of '$new_branch' (file level merging is required)."
167 # -- Update the symbolic ref. Core git doesn't even check for failure
168 # here, it Just Works(tm). If it doesn't we are in some really ugly
169 # state that is difficult to recover from within git-gui.
171 if {[catch {git symbolic-ref HEAD "refs/heads/$new_branch"} err]} {
172 error_popup "Failed to set current branch.
174 This working directory is only partially switched. We successfully updated your files, but failed to update an internal Git file.
176 This should not have occurred. [appname] will now close and give up.
183 # -- Update our repository state. If we were previously in amend mode
184 # we need to toss the current buffer and do a full rescan to update
185 # our file lists. If we weren't in amend mode our file lists are
186 # accurate and we can avoid the rescan.
189 set selected_commit_type new
190 if {[string match amend* $commit_type]} {
191 $ui_comm delete 0.0 end
193 $ui_comm edit modified false
194 rescan {set ui_status_value "Checked out branch '$current_branch'."}
196 repository_state commit_type HEAD MERGE_HEAD
198 set ui_status_value "Checked out branch '$current_branch'."