Display the diffs for a merge in a unified fashion.

Stuff that ended up in the result is shown in bold with a "+" at the
beginning of the line; stuff that didn't is in the normal font with
a "-" at the beginning of the line.  The color shows which parent
the stuff was in; red for the first parent, blue for the second, then
green, purple, brown, and the rest are grey.  If the result is different
from all of the parents it is shown in black (and bold).
This commit is contained in:
Paul Mackerras 2005-07-27 22:15:47 -05:00 committed by Paul Mackerras
parent 7eab29339b
commit 9d2a52eca1

367
gitk
View File

@ -273,7 +273,7 @@ proc makewindow {} {
global findtype findtypemenu findloc findstring fstring geometry
global entries sha1entry sha1string sha1but
global maincursor textcursor
global rowctxmenu gaudydiff
global rowctxmenu gaudydiff mergemax
menu .bar
.bar add cascade -label "File" -menu .bar.file
@ -373,6 +373,15 @@ proc makewindow {} {
$ctext tag conf hunksep -fore blue
$ctext tag conf d0 -fore red
$ctext tag conf d1 -fore "#00a000"
$ctext tag conf m0 -fore red
$ctext tag conf m1 -fore blue
$ctext tag conf m2 -fore green
$ctext tag conf m3 -fore purple
$ctext tag conf m4 -fore brown
$ctext tag conf mmax -fore darkgrey
set mergemax 5
$ctext tag conf mresult -font [concat $textfont bold]
$ctext tag conf msep -font [concat $textfont bold]
$ctext tag conf found -back yellow
}
@ -1752,7 +1761,9 @@ proc contmergediff {ids} {
}
if {![info exists treediffs($ids)]} {
set diffids $ids
gettreediffs $ids
if {![info exists treepending]} {
gettreediffs $ids
}
return
}
}
@ -1790,16 +1801,364 @@ proc contmergediff {ids} {
}
set mergefilelist($diffmergeid) $files
showmergediff
if {$files ne {}} {
showmergediff
}
}
proc showmergediff {} {
global cflist diffmergeid mergefilelist
global cflist diffmergeid mergefilelist parents
global diffopts diffinhunk currentfile diffblocked
global groupfilelast mergefds
set files $mergefilelist($diffmergeid)
foreach f $files {
$cflist insert end $f
}
set env(GIT_DIFF_OPTS) $diffopts
set flist {}
catch {unset currentfile}
catch {unset currenthunk}
catch {unset filelines}
set groupfilelast -1
foreach p $parents($diffmergeid) {
set cmd [list | git-diff-tree -p $p $diffmergeid]
set cmd [concat $cmd $mergefilelist($diffmergeid)]
if {[catch {set f [open $cmd r]} err]} {
error_popup "Error getting diffs: $err"
foreach f $flist {
catch {close $f}
}
return
}
lappend flist $f
set ids [list $diffmergeid $p]
set mergefds($ids) $f
set diffinhunk($ids) 0
set diffblocked($ids) 0
fconfigure $f -blocking 0
fileevent $f readable [list getmergediffline $f $ids $diffmergeid]
}
}
proc getmergediffline {f ids id} {
global diffmergeid diffinhunk diffoldlines diffnewlines
global currentfile currenthunk
global diffoldstart diffnewstart diffoldlno diffnewlno
global diffblocked mergefilelist
global noldlines nnewlines difflcounts filelines
set n [gets $f line]
if {$n < 0} {
if {![eof $f]} return
}
if {!([info exists diffmergeid] && $diffmergeid == $id)} {
if {$n < 0} {
close $f
}
return
}
if {$diffinhunk($ids) != 0} {
set fi $currentfile($ids)
if {$n > 0 && [regexp {^[-+ \\]} $line match]} {
# continuing an existing hunk
set line [string range $line 1 end]
set p [lindex $ids 1]
if {$match eq "-" || $match eq " "} {
set filelines($p,$fi,$diffoldlno($ids)) $line
incr diffoldlno($ids)
}
if {$match eq "+" || $match eq " "} {
set filelines($id,$fi,$diffnewlno($ids)) $line
incr diffnewlno($ids)
}
if {$match eq " "} {
if {$diffinhunk($ids) == 2} {
lappend difflcounts($ids) \
[list $noldlines($ids) $nnewlines($ids)]
set noldlines($ids) 0
set diffinhunk($ids) 1
}
incr noldlines($ids)
} elseif {$match eq "-" || $match eq "+"} {
if {$diffinhunk($ids) == 1} {
lappend difflcounts($ids) [list $noldlines($ids)]
set noldlines($ids) 0
set nnewlines($ids) 0
set diffinhunk($ids) 2
}
if {$match eq "-"} {
incr noldlines($ids)
} else {
incr nnewlines($ids)
}
}
# and if it's \ No newline at end of line, then what?
return
}
# end of a hunk
if {$diffinhunk($ids) == 1 && $noldlines($ids) != 0} {
lappend difflcounts($ids) [list $noldlines($ids)]
} elseif {$diffinhunk($ids) == 2
&& ($noldlines($ids) != 0 || $nnewlines($ids) != 0)} {
lappend difflcounts($ids) [list $noldlines($ids) $nnewlines($ids)]
}
set currenthunk($ids) [list $currentfile($ids) \
$diffoldstart($ids) $diffnewstart($ids) \
$diffoldlno($ids) $diffnewlno($ids) \
$difflcounts($ids)]
set diffinhunk($ids) 0
# -1 = need to block, 0 = unblocked, 1 = is blocked
set diffblocked($ids) -1
processhunks
if {$diffblocked($ids) == -1} {
fileevent $f readable {}
set diffblocked($ids) 1
}
}
if {$n < 0} {
# eof
if {!$diffblocked($ids)} {
close $f
set currentfile($ids) [llength $mergefilelist($diffmergeid)]
set currenthunk($ids) [list $currentfile($ids) 0 0 0 0 {}]
processhunks
}
} elseif {[regexp {^diff --git a/(.*) b/} $line match fname]} {
# start of a new file
set currentfile($ids) \
[lsearch -exact $mergefilelist($diffmergeid) $fname]
} elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
$line match f1l f1c f2l f2c rest]} {
if {[info exists currentfile($ids)] && $currentfile($ids) >= 0} {
# start of a new hunk
if {$f1l == 0 && $f1c == 0} {
set f1l 1
}
if {$f2l == 0 && $f2c == 0} {
set f2l 1
}
set diffinhunk($ids) 1
set diffoldstart($ids) $f1l
set diffnewstart($ids) $f2l
set diffoldlno($ids) $f1l
set diffnewlno($ids) $f2l
set difflcounts($ids) {}
set noldlines($ids) 0
set nnewlines($ids) 0
}
}
}
proc processhunks {} {
global diffmergeid parents nparents currenthunk
global mergefilelist diffblocked mergefds
global grouphunks grouplinestart grouplineend groupfilenum
set nfiles [llength $mergefilelist($diffmergeid)]
while 1 {
set fi $nfiles
set lno 0
# look for the earliest hunk
foreach p $parents($diffmergeid) {
set ids [list $diffmergeid $p]
if {![info exists currenthunk($ids)]} return
set i [lindex $currenthunk($ids) 0]
set l [lindex $currenthunk($ids) 2]
if {$i < $fi || ($i == $fi && $l < $lno)} {
set fi $i
set lno $l
set pi $p
}
}
if {$fi < $nfiles} {
set ids [list $diffmergeid $pi]
set hunk $currenthunk($ids)
unset currenthunk($ids)
if {$diffblocked($ids) > 0} {
fileevent $mergefds($ids) readable \
[list getmergediffline $mergefds($ids) $ids $diffmergeid]
}
set diffblocked($ids) 0
if {[info exists groupfilenum] && $groupfilenum == $fi
&& $lno <= $grouplineend} {
# add this hunk to the pending group
lappend grouphunks($pi) $hunk
set endln [lindex $hunk 4]
if {$endln > $grouplineend} {
set grouplineend $endln
}
continue
}
}
# succeeding stuff doesn't belong in this group, so
# process the group now
if {[info exists groupfilenum]} {
processgroup
unset groupfilenum
unset grouphunks
}
if {$fi >= $nfiles} break
# start a new group
set groupfilenum $fi
set grouphunks($pi) [list $hunk]
set grouplinestart $lno
set grouplineend [lindex $hunk 4]
}
}
proc processgroup {} {
global groupfilelast groupfilenum difffilestart
global mergefilelist diffmergeid ctext filelines
global parents diffmergeid diffoffset
global grouphunks grouplinestart grouplineend nparents
global mergemax
$ctext conf -state normal
set id $diffmergeid
set f $groupfilenum
if {$groupfilelast != $f} {
$ctext insert end "\n"
set here [$ctext index "end - 1c"]
set difffilestart($f) $here
set mark fmark.[expr {$f + 1}]
$ctext mark set $mark $here
$ctext mark gravity $mark left
set header [lindex $mergefilelist($id) $f]
set l [expr {(78 - [string length $header]) / 2}]
set pad [string range "----------------------------------------" 1 $l]
$ctext insert end "$pad $header $pad\n" filesep
set groupfilelast $f
foreach p $parents($id) {
set diffoffset($p) 0
}
}
$ctext insert end "@@" msep
set nlines [expr {$grouplineend - $grouplinestart}]
set events {}
set pnum 0
foreach p $parents($id) {
set startline [expr {$grouplinestart + $diffoffset($p)}]
set offset($p) $diffoffset($p)
set ol $startline
set nl $grouplinestart
if {[info exists grouphunks($p)]} {
foreach h $grouphunks($p) {
set l [lindex $h 2]
if {$nl < $l} {
for {} {$nl < $l} {incr nl} {
set filelines($p,$f,$ol) $filelines($id,$f,$nl)
incr ol
}
}
foreach chunk [lindex $h 5] {
if {[llength $chunk] == 2} {
set olc [lindex $chunk 0]
set nlc [lindex $chunk 1]
set nnl [expr {$nl + $nlc}]
lappend events [list $nl $nnl $pnum $olc $nlc]
incr ol $olc
set nl $nnl
} else {
incr ol [lindex $chunk 0]
incr nl [lindex $chunk 0]
}
}
}
}
if {$nl < $grouplineend} {
for {} {$nl < $grouplineend} {incr nl} {
set filelines($p,$f,$ol) $filelines($id,$f,$nl)
incr ol
}
}
set nlines [expr {$ol - $startline}]
$ctext insert end " -$startline,$nlines" msep
incr pnum
}
set nlines [expr {$grouplineend - $grouplinestart}]
$ctext insert end " +$grouplinestart,$nlines @@\n" msep
set events [lsort -integer -index 0 $events]
set nevents [llength $events]
set nmerge $nparents($diffmergeid)
set i 0
set l $grouplinestart
while {$i < $nevents} {
set nl [lindex $events $i 0]
while {$l < $nl} {
$ctext insert end " $filelines($id,$f,$l)\n"
incr l
}
set e [lindex $events $i]
set enl [lindex $e 1]
set j $i
set active {}
while 1 {
set pnum [lindex $e 2]
set olc [lindex $e 3]
set nlc [lindex $e 4]
if {![info exists delta($pnum)]} {
set delta($pnum) [expr {$olc - $nlc}]
lappend active $pnum
} else {
incr delta($pnum) [expr {$olc - $nlc}]
}
if {[incr j] >= $nevents} break
set e [lindex $events $j]
if {[lindex $e 0] >= $enl} break
if {[lindex $e 1] > $enl} {
set enl [lindex $e 1]
}
}
set nlc [expr {$enl - $l}]
set ncol mresult
if {[llength $active] == $nmerge - 1} {
for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
if {![info exists delta($pnum)]} {
if {$pnum < $mergemax} {
lappend ncol m$pnum
} else {
lappend ncol mmax
}
break
}
}
}
set pnum -1
foreach p $parents($id) {
incr pnum
if {![info exists delta($pnum)]} continue
set olc [expr {$nlc + $delta($pnum)}]
set ol [expr {$l + $diffoffset($p)}]
incr diffoffset($p) $delta($pnum)
unset delta($pnum)
for {} {$olc > 0} {incr olc -1} {
$ctext insert end "-$filelines($p,$f,$ol)\n" m$pnum
incr ol
}
}
for {} {$nlc > 0} {incr nlc -1} {
$ctext insert end "+$filelines($id,$f,$l)\n" $ncol
incr l
}
set i $j
}
while {$l < $grouplineend} {
$ctext insert end " $filelines($id,$f,$l)\n"
incr l
}
$ctext conf -state disabled
}
proc startdiff {ids} {