Skip to content

Commit f806f0f

Browse files
committed
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>
1 parent 841ea82 commit f806f0f

File tree

1 file changed

+55
-4
lines changed

1 file changed

+55
-4
lines changed

gitk

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ proc start_rev_list {view} {
133133
if {$tclencoding != {}} {
134134
fconfigure $fd -encoding $tclencoding
135135
}
136-
filerun $fd [list getcommitlines $fd $i $view]
136+
filerun $fd [list getcommitlines $fd $i $view 0]
137137
nowbusy $view [mc "Reading"]
138138
if {$view == $curview} {
139139
set progressdirn 1
@@ -227,7 +227,7 @@ proc updatecommits {} {
227227
if {$tclencoding != {}} {
228228
fconfigure $fd -encoding $tclencoding
229229
}
230-
filerun $fd [list getcommitlines $fd $i $view]
230+
filerun $fd [list getcommitlines $fd $i $view 1]
231231
incr viewactive($view)
232232
set viewcomplete($view) 0
233233
set pending_select $mainheadid
@@ -555,6 +555,9 @@ proc renumbervarc {a v} {
555555
#puts "renumbervarc did [llength $todo] of $ntot arcs in [expr {$t2-$t1}]ms"
556556
}
557557

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.
558561
proc fix_reversal {p a v} {
559562
global varcid varcstart varctok vupptr
560563

@@ -964,12 +967,40 @@ proc closevarcs {v} {
964967
}
965968
}
966969

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} {
968999
global cmitlisted commitinterest leftover
9691000
global commitidx commitdata datemode
9701001
global parents children curview hlview
9711002
global vnextroot idpending ordertok
972-
global varccommits varcid varctok vtokmod
1003+
global varccommits varcid varctok vtokmod viewfiles
9731004

9741005
set stuff [read $fd 500000]
9751006
# git log doesn't terminate the last commit with a null...
@@ -1070,6 +1101,26 @@ proc getcommitlines {fd inst view} {
10701101
}
10711102
set id [lindex $ids 0]
10721103
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+
10731124
set a 0
10741125
if {[info exists varcid($vid)]} {
10751126
if {$cmitlisted($vid) || !$listed} continue

0 commit comments

Comments
 (0)