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 <spearce@spearce.org>
This commit is contained in:
143
git-gui
143
git-gui
@ -231,25 +231,38 @@ proc unlock_index {} {
|
|||||||
##
|
##
|
||||||
## status
|
## status
|
||||||
|
|
||||||
proc repository_state {hdvar ctvar} {
|
proc repository_state {ctvar hdvar mhvar} {
|
||||||
global gitdir
|
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]}]} {
|
if {[catch {set hd [exec git rev-parse --verify HEAD]}]} {
|
||||||
set hd {}
|
set hd {}
|
||||||
set ct initial
|
set ct initial
|
||||||
} elseif {[file exists [file join $gitdir MERGE_HEAD]]} {
|
return
|
||||||
set ct merge
|
|
||||||
} else {
|
|
||||||
set ct normal
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set merge_head [file join $gitdir MERGE_HEAD]
|
||||||
|
if {[file exists $merge_head]} {
|
||||||
|
set ct merge
|
||||||
|
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 {} {
|
proc PARENT {} {
|
||||||
global PARENT empty_tree
|
global PARENT empty_tree
|
||||||
|
|
||||||
if {$PARENT ne {}} {
|
set p [lindex $PARENT 0]
|
||||||
return $PARENT
|
if {$p ne {}} {
|
||||||
|
return $p
|
||||||
}
|
}
|
||||||
if {$empty_tree eq {}} {
|
if {$empty_tree eq {}} {
|
||||||
set empty_tree [exec git mktree << {}]
|
set empty_tree [exec git mktree << {}]
|
||||||
@ -258,21 +271,22 @@ proc PARENT {} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
proc rescan {after} {
|
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 ui_index ui_other ui_status_value ui_comm
|
||||||
global rescan_active file_states
|
global rescan_active file_states
|
||||||
global repo_config
|
global repo_config
|
||||||
|
|
||||||
if {$rescan_active > 0 || ![lock_index read]} return
|
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]
|
if {[string match amend* $commit_type]
|
||||||
&& $new_type eq {normal}
|
&& $newType eq {normal}
|
||||||
&& $new_HEAD eq $HEAD} {
|
&& $newHEAD eq $HEAD} {
|
||||||
} else {
|
} else {
|
||||||
set HEAD $new_HEAD
|
set HEAD $newHEAD
|
||||||
set PARENT $new_HEAD
|
set PARENT $newHEAD
|
||||||
set commit_type $new_type
|
set MERGE_HEAD $newMERGE_HEAD
|
||||||
|
set commit_type $newType
|
||||||
}
|
}
|
||||||
|
|
||||||
array unset file_states
|
array unset file_states
|
||||||
@ -686,23 +700,36 @@ proc read_diff {fd} {
|
|||||||
## commit
|
## commit
|
||||||
|
|
||||||
proc load_last_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 {[llength $PARENT] == 0} {
|
||||||
if {$commit_type ne {normal}} {
|
error_popup {There is nothing to amend.
|
||||||
error_popup "Can't amend a $commit_type commit."
|
|
||||||
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
set msg {}
|
set msg {}
|
||||||
set parent {}
|
set parents [list]
|
||||||
set parent_count 0
|
|
||||||
if {[catch {
|
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} {
|
while {[gets $fd line] > 0} {
|
||||||
if {[string match {parent *} $line]} {
|
if {[string match {parent *} $line]} {
|
||||||
set parent [string range $line 7 end]
|
lappend parents [string range $line 7 end]
|
||||||
incr parent_count
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set msg [string trim [read $fd]]
|
set msg [string trim [read $fd]]
|
||||||
@ -712,17 +739,13 @@ proc load_last_commit {} {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if {$parent_count > 1} {
|
set HEAD $curHEAD
|
||||||
error_popup {Can't amend a merge commit.}
|
set PARENT $parents
|
||||||
return
|
set MERGE_HEAD [list]
|
||||||
}
|
switch -- [llength $parents] {
|
||||||
|
0 {set commit_type amend-initial}
|
||||||
if {$parent_count == 0} {
|
1 {set commit_type amend}
|
||||||
set commit_type amend-initial
|
default {set commit_type amend-merge}
|
||||||
set PARENT {}
|
|
||||||
} elseif {$parent_count == 1} {
|
|
||||||
set commit_type amend
|
|
||||||
set PARENT $parent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$ui_comm delete 0.0 end
|
$ui_comm delete 0.0 end
|
||||||
@ -770,11 +793,11 @@ proc commit_tree {} {
|
|||||||
|
|
||||||
# -- Our in memory state should match the repository.
|
# -- 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]
|
if {[string match amend* $commit_type]
|
||||||
&& $cur_type eq {normal}
|
&& $curType eq {normal}
|
||||||
&& $curHEAD eq $HEAD} {
|
&& $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.
|
info_popup {Last scanned state does not match repository state.
|
||||||
|
|
||||||
Another Git program has modified this repository
|
Another Git program has modified this repository
|
||||||
@ -920,7 +943,8 @@ proc commit_writetree {curHEAD msg} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
proc commit_committree {fd_wt 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 ui_status_value ui_comm selected_commit_type
|
||||||
global file_states selected_paths rescan_active
|
global file_states selected_paths rescan_active
|
||||||
|
|
||||||
@ -935,24 +959,12 @@ proc commit_committree {fd_wt curHEAD msg} {
|
|||||||
# -- Create the commit.
|
# -- Create the commit.
|
||||||
#
|
#
|
||||||
set cmd [list git commit-tree $tree_id]
|
set cmd [list git commit-tree $tree_id]
|
||||||
if {$PARENT ne {}} {
|
set parents [concat $PARENT $MERGE_HEAD]
|
||||||
lappend cmd -p $PARENT
|
if {[llength $parents] > 0} {
|
||||||
}
|
foreach p $parents {
|
||||||
if {$commit_type eq {merge}} {
|
lappend cmd -p $p
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
if {$PARENT eq {}} {
|
|
||||||
# git commit-tree writes to stderr during initial commit.
|
# git commit-tree writes to stderr during initial commit.
|
||||||
lappend cmd 2>/dev/null
|
lappend cmd 2>/dev/null
|
||||||
}
|
}
|
||||||
@ -1020,10 +1032,11 @@ proc commit_committree {fd_wt curHEAD msg} {
|
|||||||
|
|
||||||
# -- Update in memory status
|
# -- Update in memory status
|
||||||
#
|
#
|
||||||
set commit_type normal
|
|
||||||
set selected_commit_type new
|
set selected_commit_type new
|
||||||
|
set commit_type normal
|
||||||
set HEAD $cmt_id
|
set HEAD $cmt_id
|
||||||
set PARENT $cmt_id
|
set PARENT $cmt_id
|
||||||
|
set MERGE_HEAD [list]
|
||||||
|
|
||||||
foreach path [array names file_states] {
|
foreach path [array names file_states] {
|
||||||
set s $file_states($path)
|
set s $file_states($path)
|
||||||
@ -1081,8 +1094,8 @@ proc pull_remote {remote branch} {
|
|||||||
|
|
||||||
# -- Our in memory state should match the repository.
|
# -- Our in memory state should match the repository.
|
||||||
#
|
#
|
||||||
repository_state curHEAD cur_type
|
repository_state curType curHEAD curMERGE_HEAD
|
||||||
if {$commit_type ne $cur_type || $HEAD ne $curHEAD} {
|
if {$commit_type ne $curType || $HEAD ne $curHEAD} {
|
||||||
error_popup {Last scanned state does not match repository state.
|
error_popup {Last scanned state does not match repository state.
|
||||||
|
|
||||||
Its highly likely that another Git program modified the
|
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} {
|
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
|
global ui_status_value
|
||||||
|
|
||||||
unlock_index
|
unlock_index
|
||||||
if {$success} {
|
if {$success} {
|
||||||
repository_state HEAD commit_type
|
repository_state commit_type HEAD MERGE_HEAD
|
||||||
set PARENT $HEAD
|
set PARENT $HEAD
|
||||||
set selected_commit_type new
|
set selected_commit_type new
|
||||||
set $ui_status_value "Pulling $branch from $remote complete."
|
set ui_status_value "Pulling $branch from $remote complete."
|
||||||
} else {
|
} else {
|
||||||
set m "Conflicts detected while pulling $branch from $remote."
|
rescan [list set ui_status_value \
|
||||||
rescan "set ui_status_value {$m}"
|
"Conflicts detected while pulling $branch from $remote."]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2852,6 +2865,7 @@ proc trace_commit_type {varname args} {
|
|||||||
initial {set txt {Initial Commit Message:}}
|
initial {set txt {Initial Commit Message:}}
|
||||||
amend {set txt {Amended Commit Message:}}
|
amend {set txt {Amended Commit Message:}}
|
||||||
amend-initial {set txt {Amended Initial Commit Message:}}
|
amend-initial {set txt {Amended Initial Commit Message:}}
|
||||||
|
amend-merge {set txt {Amended Merge Commit Message:}}
|
||||||
merge {set txt {Merge Commit Message:}}
|
merge {set txt {Merge Commit Message:}}
|
||||||
* {set txt {Commit Message:}}
|
* {set txt {Commit Message:}}
|
||||||
}
|
}
|
||||||
@ -3146,6 +3160,7 @@ set file_lists($ui_other) [list]
|
|||||||
|
|
||||||
set HEAD {}
|
set HEAD {}
|
||||||
set PARENT {}
|
set PARENT {}
|
||||||
|
set MERGE_HEAD [list]
|
||||||
set commit_type {}
|
set commit_type {}
|
||||||
set empty_tree {}
|
set empty_tree {}
|
||||||
set current_diff {}
|
set current_diff {}
|
||||||
|
Reference in New Issue
Block a user