From: Shawn O. Pearce Date: Tue, 21 Nov 2006 02:27:22 +0000 (-0500) Subject: git-gui: Improve handling of merge commits. X-Git-Tag: gitgui-0.6.0~177 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=f18e40a1a60d506065b6cc0e45704ce29ea0a035;p=git.git git-gui: Improve handling of merge commits. Its useful to be able to amend the last commit even if it was a merge commit, so we really should support that in the gui. We now do so by making PARENT a list. We always diff against the first parent but we create a commit consisting of the parent(s) listed in this list, in order. We also should recheck the repository state during an amend. Earlier I was bitten by this exact bug when I switched branches through a command prompt and then did not do a rescan in git-gui. When I hit "Amend Last Commit" I was surprised to see information from the prior branch appear. This was due to git-gui caching the data from the last rescan and using that data form the amend data load request, rather than the data of the current branch. Improved error text in the dialogs used to tell the user why an amend is being refused by git-gui. In general this is only during an initial commit (nothing prior to amend) and during a merge commit (it is simply too confusing to amend the last commit while also trying to complete a merge). Fixed a couple of minor bugs in the pull logic. Since this code isn't really useful nobody has recently tested it and noticed the breakage. It really needs to be rewritten anyway. Signed-off-by: Shawn O. Pearce --- diff --git a/git-gui b/git-gui index dcbb100fe..d5738baf1 100755 --- a/git-gui +++ b/git-gui @@ -231,25 +231,38 @@ proc unlock_index {} { ## ## status -proc repository_state {hdvar ctvar} { +proc repository_state {ctvar hdvar mhvar} { global gitdir - upvar $hdvar hd $ctvar ct + upvar $ctvar ct $hdvar hd $mhvar mh + + set mh [list] if {[catch {set hd [exec git rev-parse --verify HEAD]}]} { set hd {} set ct initial - } elseif {[file exists [file join $gitdir MERGE_HEAD]]} { + return + } + + set merge_head [file join $gitdir MERGE_HEAD] + if {[file exists $merge_head]} { set ct merge - } else { - set ct normal + set fd_mh [open $merge_head r] + while {[gets $fd_mh line] >= 0} { + lappend mh $line + } + close $fd_mh + return } + + set ct normal } proc PARENT {} { global PARENT empty_tree - if {$PARENT ne {}} { - return $PARENT + set p [lindex $PARENT 0] + if {$p ne {}} { + return $p } if {$empty_tree eq {}} { set empty_tree [exec git mktree << {}] @@ -258,21 +271,22 @@ proc PARENT {} { } proc rescan {after} { - global HEAD PARENT commit_type + global HEAD PARENT MERGE_HEAD commit_type global ui_index ui_other ui_status_value ui_comm global rescan_active file_states global repo_config if {$rescan_active > 0 || ![lock_index read]} return - repository_state new_HEAD new_type + repository_state newType newHEAD newMERGE_HEAD if {[string match amend* $commit_type] - && $new_type eq {normal} - && $new_HEAD eq $HEAD} { + && $newType eq {normal} + && $newHEAD eq $HEAD} { } else { - set HEAD $new_HEAD - set PARENT $new_HEAD - set commit_type $new_type + set HEAD $newHEAD + set PARENT $newHEAD + set MERGE_HEAD $newMERGE_HEAD + set commit_type $newType } array unset file_states @@ -686,23 +700,36 @@ proc read_diff {fd} { ## commit proc load_last_commit {} { - global HEAD PARENT commit_type ui_comm + global HEAD PARENT MERGE_HEAD commit_type ui_comm - if {[string match amend* $commit_type]} return - if {$commit_type ne {normal}} { - error_popup "Can't amend a $commit_type commit." + if {[llength $PARENT] == 0} { + error_popup {There is nothing to amend. + +You are about to create the initial commit. +There is no commit before this to amend. +} + return + } + + repository_state curType curHEAD curMERGE_HEAD + if {$curType eq {merge}} { + error_popup {Cannot amend while merging. + +You are currently in the middle of a merge that +has not been fully completed. You cannot amend +the prior commit unless you first abort the +current merge activity. +} return } set msg {} - set parent {} - set parent_count 0 + set parents [list] if {[catch { - set fd [open "| git cat-file commit $HEAD" r] + set fd [open "| git cat-file commit $curHEAD" r] while {[gets $fd line] > 0} { if {[string match {parent *} $line]} { - set parent [string range $line 7 end] - incr parent_count + lappend parents [string range $line 7 end] } } set msg [string trim [read $fd]] @@ -712,17 +739,13 @@ proc load_last_commit {} { return } - if {$parent_count > 1} { - error_popup {Can't amend a merge commit.} - return - } - - if {$parent_count == 0} { - set commit_type amend-initial - set PARENT {} - } elseif {$parent_count == 1} { - set commit_type amend - set PARENT $parent + set HEAD $curHEAD + set PARENT $parents + set MERGE_HEAD [list] + switch -- [llength $parents] { + 0 {set commit_type amend-initial} + 1 {set commit_type amend} + default {set commit_type amend-merge} } $ui_comm delete 0.0 end @@ -770,11 +793,11 @@ proc commit_tree {} { # -- Our in memory state should match the repository. # - repository_state curHEAD cur_type + repository_state curType curHEAD curMERGE_HEAD if {[string match amend* $commit_type] - && $cur_type eq {normal} + && $curType eq {normal} && $curHEAD eq $HEAD} { - } elseif {$commit_type ne $cur_type || $HEAD ne $curHEAD} { + } elseif {$commit_type ne $curType || $HEAD ne $curHEAD} { info_popup {Last scanned state does not match repository state. Another Git program has modified this repository @@ -920,7 +943,8 @@ proc commit_writetree {curHEAD msg} { } proc commit_committree {fd_wt curHEAD msg} { - global single_commit gitdir HEAD PARENT commit_type tcl_platform + global HEAD PARENT MERGE_HEAD commit_type + global single_commit gitdir tcl_platform global ui_status_value ui_comm selected_commit_type global file_states selected_paths rescan_active @@ -935,24 +959,12 @@ proc commit_committree {fd_wt curHEAD msg} { # -- Create the commit. # set cmd [list git commit-tree $tree_id] - if {$PARENT ne {}} { - lappend cmd -p $PARENT - } - if {$commit_type eq {merge}} { - if {[catch { - set fd_mh [open [file join $gitdir MERGE_HEAD] r] - while {[gets $fd_mh merge_head] >= 0} { - lappend cmd -p $merge_head - } - close $fd_mh - } err]} { - error_popup "Loading MERGE_HEAD failed:\n\n$err" - set ui_status_value {Commit failed.} - unlock_index - return + set parents [concat $PARENT $MERGE_HEAD] + if {[llength $parents] > 0} { + foreach p $parents { + lappend cmd -p $p } - } - if {$PARENT eq {}} { + } else { # git commit-tree writes to stderr during initial commit. lappend cmd 2>/dev/null } @@ -1020,10 +1032,11 @@ proc commit_committree {fd_wt curHEAD msg} { # -- Update in memory status # - set commit_type normal set selected_commit_type new + set commit_type normal set HEAD $cmt_id set PARENT $cmt_id + set MERGE_HEAD [list] foreach path [array names file_states] { set s $file_states($path) @@ -1081,8 +1094,8 @@ proc pull_remote {remote branch} { # -- Our in memory state should match the repository. # - repository_state curHEAD cur_type - if {$commit_type ne $cur_type || $HEAD ne $curHEAD} { + repository_state curType curHEAD curMERGE_HEAD + if {$commit_type ne $curType || $HEAD ne $curHEAD} { error_popup {Last scanned state does not match repository state. Its highly likely that another Git program modified the @@ -1120,18 +1133,18 @@ Commit or throw away all changes before starting a pull operation. } proc post_pull_remote {remote branch success} { - global HEAD PARENT commit_type selected_commit_type + global HEAD PARENT MERGE_HEAD commit_type selected_commit_type global ui_status_value unlock_index if {$success} { - repository_state HEAD commit_type + repository_state commit_type HEAD MERGE_HEAD set PARENT $HEAD set selected_commit_type new - set $ui_status_value "Pulling $branch from $remote complete." + set ui_status_value "Pulling $branch from $remote complete." } else { - set m "Conflicts detected while pulling $branch from $remote." - rescan "set ui_status_value {$m}" + rescan [list set ui_status_value \ + "Conflicts detected while pulling $branch from $remote."] } } @@ -2852,6 +2865,7 @@ proc trace_commit_type {varname args} { initial {set txt {Initial Commit Message:}} amend {set txt {Amended Commit Message:}} amend-initial {set txt {Amended Initial Commit Message:}} + amend-merge {set txt {Amended Merge Commit Message:}} merge {set txt {Merge Commit Message:}} * {set txt {Commit Message:}} } @@ -3146,6 +3160,7 @@ set file_lists($ui_other) [list] set HEAD {} set PARENT {} +set MERGE_HEAD [list] set commit_type {} set empty_tree {} set current_diff {}