@matheusbsbs / matheus-bagliano / commits / f806f0fba8
Fork 0

gitk: Handle updating with path limiting better

When updating the graph, gitk uses a git log command with commit limiting in order to get just the new commits. When path limiting is also in effect, git log rewrites the parents of the commits it outputs in order to represent just the subgraph that modifies the listed paths, but it doesn't rewrite the parents on the boundary of the graph. The result is that when updating, git log does not give gitk the information about where the new commits join in to the existing graph. This solves the problem by explicitly rewriting boundary parents when updating. If we are updating and are doing path limiting, then when gitk finds an unlisted commit (one where git log puts a "-" in front of the commit ID to indicate that it isn't actually part of the graph), then gitk will execute: git rev-list --first-parent --max-count=1 $id -- paths... which returns the first ancestor that affects the listed paths. (Currently gitk executes this synchronously; it could do it asynchronously, which would be more complex but would avoid the possibility of the UI freezing up if git rev-list takes a long time.) Then, if the result is a commit that we know about, we rewrite the parents of the children of the original commit to point to the new commit. That is mostly a matter of adjusting the parents and children arrays and calling fix_reversal to fix up the graph. Signed-off-by: Paul Mackerras <paulus@samba.org>

Paul Mackerras committed Feb 24, 2008 at 12:16 UTC f806f0fba8ce62f2c74f21419e2bd1e7ce9e565b
1 file changed +55 -4
gitk
+55 -4
@@ -133,7 +133,7 @@ proc start_rev_list {view} {
133 if {$tclencoding != {}} {
134 fconfigure $fd -encoding $tclencoding
135 }
136 - filerun $fd [list getcommitlines $fd $i $view]
136 + filerun $fd [list getcommitlines $fd $i $view 0]
137 nowbusy $view [mc "Reading"]
138 if {$view == $curview} {
139 set progressdirn 1
@@ -227,7 +227,7 @@ proc updatecommits {} {
227 if {$tclencoding != {}} {
228 fconfigure $fd -encoding $tclencoding
229 }
230 - filerun $fd [list getcommitlines $fd $i $view]
230 + filerun $fd [list getcommitlines $fd $i $view 1]
231 incr viewactive($view)
232 set viewcomplete($view) 0
233 set pending_select $mainheadid
@@ -555,6 +555,9 @@ proc renumbervarc {a v} {
555 #puts "renumbervarc did [llength $todo] of $ntot arcs in [expr {$t2-$t1}]ms"
556 }
557
558 +# Fix up the graph after we have found out that in view $v,
559 +# $p (a commit that we have already seen) is actually the parent
560 +# of the last commit in arc $a.
561 proc fix_reversal {p a v} {
562 global varcid varcstart varctok vupptr
563
@@ -964,12 +967,40 @@ proc closevarcs {v} {
967 }
968 }
969
967 -proc getcommitlines {fd inst view} {
970 +# Use $rwid as a substitute for $id, i.e. reparent $id's children to $rwid
971 +# Assumes we already have an arc for $rwid.
972 +proc rewrite_commit {v id rwid} {
973 + global children parents varcid varctok vtokmod varccommits
974 +
975 + foreach ch $children($v,$id) {
976 + # make $rwid be $ch's parent in place of $id
977 + set i [lsearch -exact $parents($v,$ch) $id]
978 + if {$i < 0} {
979 + puts "oops rewrite_commit didn't find $id in parent list for $ch"
980 + }
981 + set parents($v,$ch) [lreplace $parents($v,$ch) $i $i $rwid]
982 + # add $ch to $rwid's children and sort the list if necessary
983 + if {[llength [lappend children($v,$rwid) $ch]] > 1} {
984 + set children($v,$rwid) [lsort -command [list vtokcmp $v] \
985 + $children($v,$rwid)]
986 + }
987 + # fix the graph after joining $id to $rwid
988 + set a $varcid($v,$ch)
989 + fix_reversal $rwid $a $v
990 + if {[string compare [lindex $varctok($v) $a] $vtokmod($v)] < 0} {
991 + # parentlist is wrong for the last element of arc $a
992 + # even if displayorder is right, hence the 3rd arg here
993 + modify_arc $v $a [expr {[llength $varccommits($v,$a)] - 1}]
994 + }
995 + }
996 +}
997 +
998 +proc getcommitlines {fd inst view updating} {
999 global cmitlisted commitinterest leftover
1000 global commitidx commitdata datemode
1001 global parents children curview hlview
1002 global vnextroot idpending ordertok
972 - global varccommits varcid varctok vtokmod
1003 + global varccommits varcid varctok vtokmod viewfiles
1004
1005 set stuff [read $fd 500000]
1006 # git log doesn't terminate the last commit with a null...
@@ -1070,6 +1101,26 @@ proc getcommitlines {fd inst view} {
1101 }
1102 set id [lindex $ids 0]
1103 set vid $view,$id
1104 +
1105 + if {!$listed && $updating && ![info exists varcid($vid)] &&
1106 + $viewfiles($view) ne {}} {
1107 + # git log doesn't rewrite parents for unlisted commits
1108 + # when doing path limiting, so work around that here
1109 + # by working out the rewritten parent with git rev-list
1110 + # and if we already know about it, using the rewritten
1111 + # parent as a substitute parent for $id's children.
1112 + if {![catch {
1113 + set rwid [exec git rev-list --first-parent --max-count=1 \
1114 + $id -- $viewfiles($view)]
1115 + }]} {
1116 + if {$rwid ne {} && [info exists varcid($view,$rwid)]} {
1117 + # use $rwid in place of $id
1118 + rewrite_commit $view $id $rwid
1119 + continue
1120 + }
1121 + }
1122 + }
1123 +
1124 set a 0
1125 if {[info exists varcid($vid)]} {
1126 if {$cmitlisted($vid) || !$listed} continue