From 3c461ffe88a7e2653663d60d9ba9f145621c9b7c Mon Sep 17 00:00:00 2001
From: Paul Mackerras <paulus@dorrigo.(none)>
Date: Wed, 20 Jul 2005 09:13:46 -0400
Subject: [PATCH] Calculate the list of interesting files for a merge.

If there is a GCA for the parents of the merge, then a file is
interesting if some parent has a version that is different from both
the child and the GCA.  If there is no GCA (e.g. for a merge that
pulls in an external project) then a file is interesting if the child's
version is different from all of the parents.

Next step is to actually show the differences for the interesting
files...
---
 gitk | 190 +++++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 138 insertions(+), 52 deletions(-)

diff --git a/gitk b/gitk
index 1de5ad93165..4cc59becd37 100755
--- a/gitk
+++ b/gitk
@@ -1504,7 +1504,7 @@ proc donefilediff {} {
 }
 
 proc findcont {ids} {
-    global findids treediffs parents nparents treepending
+    global findids treediffs parents nparents
     global ffileline findstartline finddidsel
     global lineid numcommits matchinglines findinprogress
     global findmergefiles
@@ -1692,33 +1692,10 @@ proc selectline {l} {
 
     $cflist delete 0 end
     $cflist insert end "Comments"
-    startdiff $id $parents($id)
-}
-
-proc startdiff {id vs} {
-    global diffpending diffpindex
-    global diffindex difffilestart
-    global curdifftag curtagstart
-
-    set diffpending $vs
-    set diffpindex 0
-    set diffindex 0
-    catch {unset difffilestart}
-    set curdifftag Comments
-    set curtagstart 0.0
-    contdiff [list $id [lindex $vs 0]]
-}
-
-proc contdiff {ids} {
-    global treediffs diffids treepending
-
-    set diffids $ids
-    if {![info exists treediffs($ids)]} {
-	if {![info exists treepending]} {
-	    gettreediffs $ids
-	}
-    } else {
-	addtocflist $ids
+    if {$nparents($id) == 1} {
+	startdiff [concat $id $parents($id)]
+    } elseif {$nparents($id) > 1} {
+	mergediff $id
     }
 }
 
@@ -1730,39 +1707,148 @@ proc selnextline {dir} {
     selectline $l
 }
 
-proc addtocflist {ids} {
-    global treediffs cflist diffpindex
+proc mergediff {id} {
+    global parents diffmergeid diffmergegca mergefilelist diffpindex
 
-    set colors {black blue green red cyan magenta}
-    set color [lindex $colors [expr {$diffpindex % [llength $colors]}]]
+    set diffmergeid $id
+    set diffpindex -1
+    set diffmergegca [findgca $parents($id)]
+    if {[info exists mergefilelist($id)]} {
+	showmergediff
+    } else {
+	contmergediff {}
+    }
+}
+
+proc findgca {ids} {
+    set gca {}
+    foreach id $ids {
+	if {$gca eq {}} {
+	    set gca $id
+	} else {
+	    if {[catch {
+		set gca [exec git-merge-base $gca $id]
+	    } err]} {
+		return {}
+	    }
+	}
+    }
+    return $gca
+}
+
+proc contmergediff {ids} {
+    global diffmergeid diffpindex parents nparents diffmergegca
+    global treediffs mergefilelist diffids
+
+    # diff the child against each of the parents, and diff
+    # each of the parents against the GCA.
+    while 1 {
+	if {[lindex $ids 0] == $diffmergeid && $diffmergegca ne {}} {
+	    set ids [list [lindex $ids 1] $diffmergegca]
+	} else {
+	    if {[incr diffpindex] >= $nparents($diffmergeid)} break
+	    set p [lindex $parents($diffmergeid) $diffpindex]
+	    set ids [list $diffmergeid $p]
+	}
+	if {![info exists treediffs($ids)]} {
+	    set diffids $ids
+	    gettreediffs $ids
+	    return
+	}
+    }
+
+    # If a file in some parent is different from the child and also
+    # different from the GCA, then it's interesting.
+    # If we don't have a GCA, then a file is interesting if it is
+    # different from the child in all the parents.
+    if {$diffmergegca ne {}} {
+	set files {}
+	foreach p $parents($diffmergeid) {
+	    set gcadiffs $treediffs([list $p $diffmergegca])
+	    foreach f $treediffs([list $diffmergeid $p]) {
+		if {[lsearch -exact $files $f] < 0
+		    && [lsearch -exact $gcadiffs $f] >= 0} {
+		    lappend files $f
+		}
+	    }
+	}
+	set files [lsort $files]
+    } else {
+	set p [lindex $parents($diffmergeid) 0]
+	set files $treediffs([list $diffmergeid $p])
+	for {set i 1} {$i < $nparents($diffmergeid) && $files ne {}} {incr i} {
+	    set p [lindex $parents($diffmergeid) $i]
+	    set df $treediffs([list $diffmergeid $p])
+	    set nf {}
+	    foreach f $files {
+		if {[lsearch -exact $df $f] >= 0} {
+		    lappend nf $f
+		}
+	    }
+	    set files $nf
+	}
+    }
+
+    set mergefilelist($diffmergeid) $files
+    showmergediff
+}
+
+proc showmergediff {} {
+    global cflist diffmergeid mergefilelist
+
+    set files $mergefilelist($diffmergeid)
+    foreach f $files {
+	$cflist insert end $f
+    }
+}
+
+proc startdiff {ids} {
+    global treediffs diffids treepending diffmergeid
+
+    set diffids $ids
+    catch {unset diffmergeid}
+    if {![info exists treediffs($ids)]} {
+	if {![info exists treepending]} {
+	    gettreediffs $ids
+	}
+    } else {
+	addtocflist $ids
+    }
+}
+
+proc addtocflist {ids} {
+    global treediffs cflist
     foreach f $treediffs($ids) {
 	$cflist insert end $f
-	$cflist itemconf end -foreground $color
     }
     getblobdiffs $ids
 }
 
 proc gettreediffs {ids} {
-    global treediffs parents treepending
+    global treediff parents treepending
     set treepending $ids
-    set treediffs($ids) {}
+    set treediff {}
     set id [lindex $ids 0]
     set p [lindex $ids 1]
     if [catch {set gdtf [open "|git-diff-tree -r $p $id" r]}] return
     fconfigure $gdtf -blocking 0
-    fileevent $gdtf readable "gettreediffline $gdtf {$ids}"
+    fileevent $gdtf readable [list gettreediffline $gdtf $ids]
 }
 
 proc gettreediffline {gdtf ids} {
-    global treediffs treepending diffids
+    global treediff treediffs treepending diffids diffmergeid
+
     set n [gets $gdtf line]
     if {$n < 0} {
 	if {![eof $gdtf]} return
 	close $gdtf
+	set treediffs($ids) $treediff
 	unset treepending
-	if {[info exists diffids]} {
-	    if {$ids != $diffids} {
-		gettreediffs $diffids
+	if {$ids != $diffids} {
+	    gettreediffs $diffids
+	} else {
+	    if {[info exists diffmergeid]} {
+		contmergediff $ids
 	    } else {
 		addtocflist $ids
 	    }
@@ -1770,31 +1856,36 @@ proc gettreediffline {gdtf ids} {
 	return
     }
     set file [lindex $line 5]
-    lappend treediffs($ids) $file
+    lappend treediff $file
 }
 
 proc getblobdiffs {ids} {
-    global diffopts blobdifffd diffids env
-    global nextupdate diffinhdr
+    global diffopts blobdifffd diffids env curdifftag curtagstart
+    global diffindex difffilestart nextupdate diffinhdr
 
     set id [lindex $ids 0]
     set p [lindex $ids 1]
     set env(GIT_DIFF_OPTS) $diffopts
-    if [catch {set bdf [open "|git-diff-tree -r -p $p $id" r]} err] {
+    set cmd [list | git-diff-tree -r -p -C $p $id]
+    if {[catch {set bdf [open $cmd r]} err]} {
 	puts "error getting diffs: $err"
 	return
     }
     set diffinhdr 0
     fconfigure $bdf -blocking 0
     set blobdifffd($ids) $bdf
-    fileevent $bdf readable [list getblobdiffline $bdf $ids]
+    set curdifftag Comments
+    set curtagstart 0.0
+    set diffindex 0
+    catch {unset difffilestart}
+    fileevent $bdf readable [list getblobdiffline $bdf $diffids]
     set nextupdate [expr {[clock clicks -milliseconds] + 100}]
 }
 
 proc getblobdiffline {bdf ids} {
     global diffids blobdifffd ctext curdifftag curtagstart
     global diffnexthead diffnextnote diffindex difffilestart
-    global nextupdate diffpending diffpindex diffinhdr
+    global nextupdate diffinhdr
     global gaudydiff
 
     set n [gets $bdf line]
@@ -1803,11 +1894,6 @@ proc getblobdiffline {bdf ids} {
 	    close $bdf
 	    if {$ids == $diffids && $bdf == $blobdifffd($ids)} {
 		$ctext tag add $curdifftag $curtagstart end
-		if {[incr diffpindex] < [llength $diffpending]} {
-		    set id [lindex $ids 0]
-		    set p [lindex $diffpending $diffpindex]
-		    contdiff [list $id $p]
-		}
 	    }
 	}
 	return
@@ -2157,7 +2243,7 @@ proc diffvssel {dirn} {
     $ctext conf -state disabled
     $ctext tag delete Comments
     $ctext tag remove found 1.0 end
-    startdiff [list $newid $oldid]
+    startdiff $newid [list $oldid]
 }
 
 proc mkpatch {} {