From: Shawn O. Pearce Date: Wed, 24 Jan 2007 21:51:59 +0000 (-0500) Subject: git-gui: Implement basic branch switching through read-tree. X-Git-Tag: gitgui-0.6.0~61 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=b5b6b434527e5f0df43f994d690a48dad1fb4555;p=git.git git-gui: Implement basic branch switching through read-tree. If the user selects a different branch from the Branch menu, or asks us to create a new branch and immediately checkout that branch we now perform the update of the working directory by way of a 2 way read-tree invocation. This emulates the behavior of `git checkout branch` or the behavior of `git checkout -b branch initrev`. We don't however support the -m style behavior, where a switch can occur with file level merging performed by merge-recursive. Support for this is planned for a future update. Signed-off-by: Shawn O. Pearce --- diff --git a/git-gui.sh b/git-gui.sh index 5171db6f2..b5c2c7406 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -2155,16 +2155,11 @@ proc do_delete_branch {} { tkwait window $w } -proc switch_branch {b} { - global HEAD commit_type file_states current_branch - global selected_commit_type ui_comm +proc switch_branch {new_branch} { + global HEAD commit_type current_branch repo_config if {![lock_index switch]} return - # -- Backup the selected branch (repository_state resets it) - # - set new_branch $current_branch - # -- Our in memory state should match the repository. # repository_state curType curHEAD curMERGE_HEAD @@ -2185,19 +2180,110 @@ The rescan will be automatically started now. return } - # -- Toss the message buffer if we are in amend mode. + if {$repo_config(gui.trustmtime) eq {true}} { + switch_branch_stage2 {} $new_branch + } else { + set ui_status_value {Refreshing file status...} + set cmd [list git update-index] + lappend cmd -q + lappend cmd --unmerged + lappend cmd --ignore-missing + lappend cmd --refresh + set fd_rf [open "| $cmd" r] + fconfigure $fd_rf -blocking 0 -translation binary + fileevent $fd_rf readable \ + [list switch_branch_stage2 $fd_rf $new_branch] + } +} + +proc switch_branch_stage2 {fd_rf new_branch} { + global ui_status_value HEAD + + if {$fd_rf ne {}} { + read $fd_rf + if {![eof $fd_rf]} return + close $fd_rf + } + + set ui_status_value "Updating working directory to '$new_branch'..." + set cmd [list git read-tree] + lappend cmd -m + lappend cmd -u + lappend cmd --exclude-per-directory=.gitignore + lappend cmd $HEAD + lappend cmd $new_branch + set fd_rt [open "| $cmd" r] + fconfigure $fd_rt -blocking 0 -translation binary + fileevent $fd_rt readable \ + [list switch_branch_readtree_wait $fd_rt $new_branch] +} + +proc switch_branch_readtree_wait {fd_rt new_branch} { + global selected_commit_type commit_type HEAD MERGE_HEAD PARENT + global current_branch + global ui_comm ui_status_value + + # -- We never get interesting output on stdout; only stderr. # - if {[string match amend* $curType]} { - $ui_comm delete 0.0 end - $ui_comm edit reset - $ui_comm edit modified false + read $fd_rt + fconfigure $fd_rt -blocking 1 + if {![eof $fd_rt]} { + fconfigure $fd_rt -blocking 0 + return } - set selected_commit_type new - set current_branch $new_branch + # -- The working directory wasn't in sync with the index and + # we'd have to overwrite something to make the switch. A + # merge is required. + # + if {[catch {close $fd_rt} err]} { + regsub {^fatal: } $err {} err + warn_popup "File level merge required. + +$err + +Staying on branch '$current_branch'." + set ui_status_value "Aborted checkout of '$new_branch' (file level merging is required)." + unlock_index + return + } + + # -- Update the symbolic ref. Core git doesn't even check for failure + # here, it Just Works(tm). If it doesn't we are in some really ugly + # state that is difficult to recover from within git-gui. + # + if {[catch {exec git symbolic-ref HEAD "refs/heads/$new_branch"} err]} { + error_popup "Failed to set current branch. + +This working directory is only partially switched. +We successfully updated your files, but failed to +update an internal Git file. + +This should not have occurred. [appname] will now +close and give up. +$err" + do_quit + return + } + + # -- Update our repository state. If we were previously in amend mode + # we need to toss the current buffer and do a full rescan to update + # our file lists. If we weren't in amend mode our file lists are + # accurate and we can avoid the rescan. + # unlock_index - error "NOT FINISHED" + set selected_commit_type new + if {[string match amend* $commit_type]} { + $ui_comm delete 0.0 end + $ui_comm edit reset + $ui_comm edit modified false + rescan {set ui_status_value "Checked out branch '$current_branch'."} + } else { + repository_state commit_type HEAD MERGE_HEAD + set PARENT $HEAD + set ui_status_value "Checked out branch '$current_branch'." + } } ######################################################################