Merge branch 'master' into dev
[gitweb.git] / gitk
diff --git a/gitk b/gitk
index e0eb3d0f8ece7d8253eab5550367558f8cffc6de..86dd575ca71655606c1be4293d0bcd6e0cdb34ef 100755 (executable)
--- a/gitk
+++ b/gitk
@@ -106,7 +106,7 @@ proc start_rev_list {view} {
     set vnextroot($view) 0
     varcinit $view
 
-    set commits [exec git rev-parse --default HEAD --revs-only \
+    set commits [eval exec git rev-parse --default HEAD --revs-only \
                     $viewargs($view)]
     set viewincl($view) {}
     foreach c $commits {
@@ -118,7 +118,7 @@ proc start_rev_list {view} {
        set fd [open [concat | git log --no-color -z --pretty=raw --parents \
                         --boundary $commits "--" $viewfiles($view)] r]
     } err]} {
-       error_popup "Error executing git log: $err"
+       error_popup "[mc "Error executing git log:"] $err"
        exit 1
     }
     set i [incr loginstance]
@@ -133,7 +133,7 @@ proc start_rev_list {view} {
        fconfigure $fd -encoding $tclencoding
     }
     filerun $fd [list getcommitlines $fd $i $view]
-    nowbusy $view "Reading"
+    nowbusy $view [mc "Reading"]
     if {$view == $curview} {
        set progressdirn 1
        set progresscoords {0 0}
@@ -163,15 +163,17 @@ proc getcommits {} {
 
     initlayout
     start_rev_list $curview
-    show_status "Reading commits..."
+    show_status [mc "Reading commits..."]
 }
 
 proc updatecommits {} {
     global curview viewargs viewfiles viewincl viewinstances
-    global viewactive viewcomplete loginstance tclencoding
-    global varcid startmsecs commfd getdbg showneartags leftover
+    global viewactive viewcomplete loginstance tclencoding mainheadid
+    global varcid startmsecs commfd showneartags showlocalchanges leftover
 
-    set getdbg 1
+    if {$showlocalchanges && [commitinview $mainheadid $curview]} {
+       dodiffindex
+    }
     set view $curview
     set commits [exec git rev-parse --default HEAD --revs-only \
                     $viewargs($view)]
@@ -267,20 +269,21 @@ proc strrep {n} {
 # --topo-order) into the order for display.
 
 proc varcinit {view} {
-    global vseeds varcstart vupptr vdownptr vleftptr varctok varcrow
-    global vtokmod varcmod varcix uat
+    global varcstart vupptr vdownptr vleftptr vbackptr varctok varcrow
+    global vtokmod varcmod vrowmod varcix vlastins
 
-    set vseeds($view) {}
     set varcstart($view) {{}}
     set vupptr($view) {0}
     set vdownptr($view) {0}
     set vleftptr($view) {0}
+    set vbackptr($view) {0}
     set varctok($view) {{}}
     set varcrow($view) {{}}
     set vtokmod($view) {}
     set varcmod($view) 0
+    set vrowmod($view) 0
     set varcix($view) {{}}
-    set uat 0
+    set vlastins($view) {0}
 }
 
 proc resetvarcs {view} {
@@ -301,19 +304,17 @@ proc resetvarcs {view} {
     foreach vd [array names vseedcount $view,*] {
        unset vseedcount($vd)
     }
-    foreach vid [array names ordertok $view,*] {
-       unset ordertok($vid)
-    }
+    catch {unset ordertok}
 }
 
 proc newvarc {view id} {
-    global varcid varctok parents children vseeds
-    global vupptr vdownptr vleftptr varcrow varcix varcstart
-    global commitdata commitinfo vseedcount
+    global varcid varctok parents children datemode
+    global vupptr vdownptr vleftptr vbackptr varcrow varcix varcstart
+    global commitdata commitinfo vseedcount varccommits vlastins
 
     set a [llength $varctok($view)]
     set vid $view,$id
-    if {[llength $children($vid)] == 0} {
+    if {[llength $children($vid)] == 0 || $datemode} {
        if {![info exists commitinfo($id)]} {
            parsecommit $id $commitdata($id) 1
        }
@@ -327,64 +328,61 @@ proc newvarc {view id} {
        set c [incr vseedcount($view,$cdate)]
        set cdate [expr {$cdate ^ 0xffffffff}]
        set tok "s[strrep $cdate][strrep $c]"
-       lappend vseeds($view) $id
-       lappend vupptr($view) 0
-       set ka [lindex $vdownptr($view) 0]
-       if {$ka == 0 ||
-           [string compare $tok [lindex $varctok($view) $ka]] < 0} {
-           lset vdownptr($view) 0 $a
-           lappend vleftptr($view) $ka
-       } else {
-           while {[set b [lindex $vleftptr($view) $ka]] != 0 &&
-                  [string compare $tok [lindex $varctok($view) $b]] >= 0} {
-               set ka $b
-           }
-           lset vleftptr($view) $ka $a
-           lappend vleftptr($view) $b
-       }
     } else {
        set tok {}
-       foreach k $children($vid) {
-           set ka $varcid($view,$k)
-           if {[string compare [lindex $varctok($view) $ka] $tok] > 0} {
-               set ki $k
-               set tok [lindex $varctok($view) $ka]
-           }
+    }
+    set ka 0
+    if {[llength $children($vid)] > 0} {
+       set kid [lindex $children($vid) end]
+       set k $varcid($view,$kid)
+       if {[string compare [lindex $varctok($view) $k] $tok] > 0} {
+           set ki $kid
+           set ka $k
+           set tok [lindex $varctok($view) $k]
        }
-       set ka $varcid($view,$ki)
-       lappend vupptr($view) $ka
+    }
+    if {$ka != 0} {
        set i [lsearch -exact $parents($view,$ki) $id]
        set j [expr {[llength $parents($view,$ki)] - 1 - $i}]
-       set rsib 0
-       while {[incr i] < [llength $parents($view,$ki)]} {
-           set bi [lindex $parents($view,$ki) $i]
-           if {[info exists varcid($view,$bi)]} {
-               set b $varcid($view,$bi)
-               if {[lindex $vupptr($view) $b] == $ka} {
-                   set rsib $b
-                   lappend vleftptr($view) [lindex $vleftptr($view) $b]
-                   lset vleftptr($view) $b $a
-                   break
-               }
-           }
-       }
-       if {$rsib == 0} {
-           lappend vleftptr($view) [lindex $vdownptr($view) $ka]
-           lset vdownptr($view) $ka $a
-       }
        append tok [strrep $j]
     }
+    set c [lindex $vlastins($view) $ka]
+    if {$c == 0 || [string compare $tok [lindex $varctok($view) $c]] < 0} {
+       set c $ka
+       set b [lindex $vdownptr($view) $ka]
+    } else {
+       set b [lindex $vleftptr($view) $c]
+    }
+    while {$b != 0 && [string compare $tok [lindex $varctok($view) $b]] >= 0} {
+       set c $b
+       set b [lindex $vleftptr($view) $c]
+    }
+    if {$c == $ka} {
+       lset vdownptr($view) $ka $a
+       lappend vbackptr($view) 0
+    } else {
+       lset vleftptr($view) $c $a
+       lappend vbackptr($view) $c
+    }
+    lset vlastins($view) $ka $a
+    lappend vupptr($view) $ka
+    lappend vleftptr($view) $b
+    if {$b != 0} {
+       lset vbackptr($view) $b $a
+    }
     lappend varctok($view) $tok
     lappend varcstart($view) $id
     lappend vdownptr($view) 0
     lappend varcrow($view) {}
     lappend varcix($view) {}
+    set varccommits($view,$a) {}
+    lappend vlastins($view) 0
     return $a
 }
 
 proc splitvarc {p v} {
     global varcid varcstart varccommits varctok
-    global vupptr vdownptr vleftptr varcix varcrow
+    global vupptr vdownptr vleftptr vbackptr varcix varcrow vlastins
 
     set oa $varcid($v,$p)
     set ac $varccommits($v,$oa)
@@ -406,6 +404,8 @@ proc splitvarc {p v} {
     lset vdownptr($v) $oa $na
     lappend vupptr($v) $oa
     lappend vleftptr($v) 0
+    lappend vbackptr($v) 0
+    lappend vlastins($v) 0
     for {set b [lindex $vdownptr($v) $na]} {$b != 0} {set b [lindex $vleftptr($v) $b]} {
        lset vupptr($v) $b $na
     }
@@ -413,11 +413,12 @@ proc splitvarc {p v} {
 
 proc renumbervarc {a v} {
     global parents children varctok varcstart varccommits
-    global vupptr vdownptr vleftptr varcid vtokmod varcmod
+    global vupptr vdownptr vleftptr vbackptr vlastins varcid vtokmod datemode
 
     set t1 [clock clicks -milliseconds]
     set todo {}
     set isrelated($a) 1
+    set kidchanged($a) 1
     set ntot 0
     while {$a != 0} {
        if {[info exists isrelated($a)]} {
@@ -441,70 +442,95 @@ proc renumbervarc {a v} {
        set a $b
     }
     foreach a $todo {
+       if {![info exists kidchanged($a)]} continue
        set id [lindex $varcstart($v) $a]
-       set tok {}
-       foreach k $children($v,$id) {
-           set ka $varcid($v,$k)
-           if {[string compare [lindex $varctok($v) $ka] $tok] > 0} {
-               set ki $k
-               set tok [lindex $varctok($v) $ka]
+       if {[llength $children($v,$id)] > 1} {
+           set children($v,$id) [lsort -command [list vtokcmp $v] \
+                                     $children($v,$id)]
+       }
+       set oldtok [lindex $varctok($v) $a]
+       if {!$datemode} {
+           set tok {}
+       } else {
+           set tok $oldtok
+       }
+       set ka 0
+       if {[llength $children($v,$id)] > 0} {
+           set kid [lindex $children($v,$id) end]
+           set k $varcid($v,$kid)
+           if {[string compare [lindex $varctok($v) $k] $tok] > 0} {
+               set ki $kid
+               set ka $k
+               set tok [lindex $varctok($v) $k]
            }
        }
-       if {$tok ne {}} {
-           set ka $varcid($v,$ki)
+       if {$ka != 0} {
            set i [lsearch -exact $parents($v,$ki) $id]
            set j [expr {[llength $parents($v,$ki)] - 1 - $i}]
            append tok [strrep $j]
-           set oldtok [lindex $varctok($v) $a]
-           if {$tok eq $oldtok} continue
-           lset varctok($v) $a $tok
-       } else {
-           set ka 0
        }
+       if {$tok eq $oldtok} {
+           continue
+       }
+       set id [lindex $varccommits($v,$a) end]
+       foreach p $parents($v,$id) {
+           if {[info exists varcid($v,$p)]} {
+               set kidchanged($varcid($v,$p)) 1
+           } else {
+               set sortkids($p) 1
+           }
+       }
+       lset varctok($v) $a $tok
        set b [lindex $vupptr($v) $a]
        if {$b != $ka} {
-           set tok [lindex $varctok($v) $ka]
-           if {[string compare $tok $vtokmod($v)] < 0} {
-               set vtokmod($v) $tok
-               set varcmod($v) $ka
-           }
-           set tok [lindex $varctok($v) $b]
-           if {[string compare $tok $vtokmod($v)] < 0} {
-               set vtokmod($v) $tok
-               set varcmod($v) $b
-           }
-           set c [lindex $vdownptr($v) $b]
-           if {$c == $a} {
-               lset vdownptr($v) $b [lindex $vleftptr($v) $a]
+           if {[string compare [lindex $varctok($v) $ka] $vtokmod($v)] < 0} {
+               modify_arc $v $ka
+           }
+           if {[string compare [lindex $varctok($v) $b] $vtokmod($v)] < 0} {
+               modify_arc $v $b
+           }
+           set c [lindex $vbackptr($v) $a]
+           set d [lindex $vleftptr($v) $a]
+           if {$c == 0} {
+               lset vdownptr($v) $b $d
            } else {
-               set b $c
-               while {$b != 0 && [lindex $vleftptr($v) $b] != $a} {
-                   set b [lindex $vleftptr($v) $b]
-               }
-               if {$b != 0} {
-                   lset vleftptr($v) $b [lindex $vleftptr($v) $a]
-               } else {
-                   puts "oops couldn't find $a in chain for [lindex $vupptr($v) $a]"
-               }
+               lset vleftptr($v) $c $d
+           }
+           if {$d != 0} {
+               lset vbackptr($v) $d $c
            }
            lset vupptr($v) $a $ka
-           set rsib 0
-           while {[incr i] < [llength $parents($v,$ki)]} {
-               set bi [lindex $parents($v,$ki) $i]
-               if {[info exists varcid($v,$bi)]} {
-                   set b $varcid($v,$bi)
-                   if {[lindex $vupptr($v) $b] == $ka} {
-                       set rsib $b
-                       lset vleftptr($v) $a [lindex $vleftptr($v) $b]
-                       lset vleftptr($v) $b $a
-                       break
-                   }
-               }
+           set c [lindex $vlastins($v) $ka]
+           if {$c == 0 || \
+                   [string compare $tok [lindex $varctok($v) $c]] < 0} {
+               set c $ka
+               set b [lindex $vdownptr($v) $ka]
+           } else {
+               set b [lindex $vleftptr($v) $c]
+           }
+           while {$b != 0 && \
+                     [string compare $tok [lindex $varctok($v) $b]] >= 0} {
+               set c $b
+               set b [lindex $vleftptr($v) $c]
+           }
+           if {$c == $ka} {
+               lset vdownptr($v) $ka $a
+               lset vbackptr($v) $a 0
+           } else {
+               lset vleftptr($v) $c $a
+               lset vbackptr($v) $a $c
            }
-           if {$rsib == 0} {
-               lset vleftptr($v) $a [lindex $vdownptr($v) $ka]
-               lset vdownptr($v) $ka $a
+           lset vleftptr($v) $a $b
+           if {$b != 0} {
+               lset vbackptr($v) $b $a
            }
+           lset vlastins($v) $ka $a
+       }
+    }
+    foreach id [array names sortkids] {
+       if {[llength $children($v,$id)] > 1} {
+           set children($v,$id) [lsort -command [list vtokcmp $v] \
+                                     $children($v,$id)]
        }
     }
     set t2 [clock clicks -milliseconds]
@@ -512,31 +538,24 @@ proc renumbervarc {a v} {
 }
 
 proc fix_reversal {p a v} {
-    global varcid varcstart varctok vupptr vseeds
+    global varcid varcstart varctok vupptr
 
     set pa $varcid($v,$p)
     if {$p ne [lindex $varcstart($v) $pa]} {
        splitvarc $p $v
        set pa $varcid($v,$p)
     }
-    # seeds always need to be renumbered (and taken out of the seeds list)
-    if {[lindex $vupptr($v) $pa] == 0} {
-       set i [lsearch -exact $vseeds($v) $p]
-       if {$i >= 0} {
-           set vseeds($v) [lreplace $vseeds($v) $i $i]
-       } else {
-           puts "oops couldn't find [shortids $p] in seeds"
-       }
-       renumbervarc $pa $v
-    } elseif {[string compare [lindex $varctok($v) $a] \
-                  [lindex $varctok($v) $pa]] > 0} {
+    # seeds always need to be renumbered
+    if {[lindex $vupptr($v) $pa] == 0 ||
+       [string compare [lindex $varctok($v) $a] \
+            [lindex $varctok($v) $pa]] > 0} {
        renumbervarc $pa $v
     }
 }
 
 proc insertrow {id p v} {
-    global varcid varccommits parents children cmitlisted ordertok
-    global commitidx varctok vtokmod varcmod
+    global varcid varccommits parents children cmitlisted
+    global commitidx varctok vtokmod
 
     set a $varcid($v,$p)
     set i [lsearch -exact $varccommits($v,$a) $p]
@@ -547,26 +566,20 @@ proc insertrow {id p v} {
     set children($v,$id) {}
     set parents($v,$id) [list $p]
     set varcid($v,$id) $a
-    if {[llength [lappend children($v,$p) $id]] > 1 &&
-       [vtokcmp $v [lindex $children($v,$p) end-1] $id] > 0} {
-       set children($v,$p) [lsort -command [list vtokcmp $v] $children($v,$p)]
-    }
+    lappend children($v,$p) $id
     set cmitlisted($v,$id) 1
     incr commitidx($v)
-    set ordertok($v,$id) $ordertok($v,$p)
     # note we deliberately don't update varcstart($v) even if $i == 0
     set varccommits($v,$a) [linsert $varccommits($v,$a) $i $id]
-    set tok [lindex $varctok($v) $a]
-    if {[string compare $tok $vtokmod($v)] < 0} {
-       set vtokmod($v) $tok
-       set varcmod($v) $a
+    if {[string compare [lindex $varctok($v) $a] $vtokmod($v)] < 0} {
+       modify_arc $v $a $i
     }
-    update_arcrows $v
+    drawvisible
 }
 
 proc removerow {id v} {
-    global varcid varccommits parents children commitidx ordertok
-    global varctok vtokmod varcmod
+    global varcid varccommits parents children commitidx
+    global varctok vtokmod cmitlisted
 
     if {[llength $parents($v,$id)] != 1} {
        puts "oops: removerow [shortids $id] has [llength $parents($v,$id)] parents"
@@ -584,18 +597,15 @@ proc removerow {id v} {
     unset parents($v,$id)
     unset children($v,$id)
     unset cmitlisted($v,$id)
-    unset ordertok($v,$id)
     incr commitidx($v) -1
     set j [lsearch -exact $children($v,$p) $id]
     if {$j >= 0} {
        set children($v,$p) [lreplace $children($v,$p) $j $j]
     }
-    set tok [lindex $varctok($v) $a]
-    if {[string compare $tok $vtokmod($v)] < 0} {
-       set vtokmod($v) $tok
-       set varcmod($v) $a
+    if {[string compare [lindex $varctok($v) $a] $vtokmod($v)] < 0} {
+       modify_arc $v $a $i
     }
-    update_arcrows $v
+    drawvisible
 }
 
 proc vtokcmp {v a b} {
@@ -605,13 +615,39 @@ proc vtokcmp {v a b} {
                [lindex $varctok($v) $varcid($v,$b)]]
 }
 
+proc modify_arc {v a {lim {}}} {
+    global varctok vtokmod varcmod varcrow vupptr curview vrowmod varccommits
+    global vhighlights nhighlights fhighlights rhighlights
+
+    set vtokmod($v) [lindex $varctok($v) $a]
+    set varcmod($v) $a
+    if {$v == $curview} {
+       while {$a != 0 && [lindex $varcrow($v) $a] eq {}} {
+           set a [lindex $vupptr($v) $a]
+           set lim {}
+       }
+       set r 0
+       if {$a != 0} {
+           if {$lim eq {}} {
+               set lim [llength $varccommits($v,$a)]
+           }
+           set r [expr {[lindex $varcrow($v) $a] + $lim}]
+       }
+       set vrowmod($v) $r
+       undolayout $r
+    }
+    catch {unset nhighlights}
+    catch {unset fhighlights}
+    catch {unset vhighlights}
+    catch {unset rhighlights}
+}
+
 proc update_arcrows {v} {
-    global vtokmod varcmod varcrow commitidx currentid selectedline
-    global varcid vseeds vrownum varcorder varcix varccommits
+    global vtokmod varcmod vrowmod varcrow commitidx currentid selectedline
+    global varcid vrownum varcorder varcix varccommits
     global vupptr vdownptr vleftptr varctok
-    global uat displayorder parentlist curview cached_commitrow
+    global displayorder parentlist curview cached_commitrow
 
-    set t1 [clock clicks -milliseconds]
     set narctot [expr {[llength $varctok($v)] - 1}]
     set a $varcmod($v)
     while {$a != 0 && [lindex $varcix($v) $a] eq {}} {
@@ -640,14 +676,13 @@ proc update_arcrows {v} {
        }
        set row [lindex $varcrow($v) $a]
     }
-    if {[llength $displayorder] > $row} {
-       set displayorder [lrange $displayorder 0 [expr {$row - 1}]]
-       set parentlist [lrange $parentlist 0 [expr {$row - 1}]]
-    }
     if {$v == $curview} {
+       if {[llength $displayorder] > $vrowmod($v)} {
+           set displayorder [lrange $displayorder 0 [expr {$vrowmod($v) - 1}]]
+           set parentlist [lrange $parentlist 0 [expr {$vrowmod($v) - 1}]]
+       }
        catch {unset cached_commitrow}
     }
-    set startrow $row
     while {1} {
        set p $a
        incr row [llength $varccommits($v,$a)]
@@ -669,20 +704,12 @@ proc update_arcrows {v} {
        lset varcix($v) $a $arcn
        lset varcrow($v) $a $row
     }
+    set vtokmod($v) [lindex $varctok($v) $p]
+    set varcmod($v) $p
+    set vrowmod($v) $row
     if {[info exists currentid]} {
        set selectedline [rowofcommit $currentid]
     }
-    undolayout $startrow
-    if {$row != $commitidx($v)} {
-       puts "oops update_arcrows got to row $row out of $commitidx($v)"
-       set vtokmod($v) {}
-       set varcmod($v) 0
-    } else {
-       set vtokmod($v) [lindex $varctok($v) $p]
-       set varcmod($v) $p
-    }
-    set t2 [clock clicks -milliseconds]
-    incr uat [expr {$t2-$t1}]
 }
 
 # Test whether view $v contains commit $id
@@ -695,6 +722,7 @@ proc commitinview {id v} {
 # Return the row number for commit $id in the current view
 proc rowofcommit {id} {
     global varcid varccommits varcrow curview cached_commitrow
+    global varctok vtokmod
 
     if {[info exists cached_commitrow($id)]} {
        return $cached_commitrow($id)
@@ -705,6 +733,9 @@ proc rowofcommit {id} {
        return {}
     }
     set a $varcid($v,$id)
+    if {[string compare [lindex $varctok($v) $a] $vtokmod($v)] > 0} {
+       update_arcrows $v
+    }
     set i [lsearch -exact $varccommits($v,$a) $id]
     if {$i < 0} {
        puts "oops didn't find commit [shortids $id] in arc $a"
@@ -738,9 +769,12 @@ proc bsearch {l elt} {
 # Make sure rows $start..$end-1 are valid in displayorder and parentlist
 proc make_disporder {start end} {
     global vrownum curview commitidx displayorder parentlist
-    global varccommits varcorder parents
+    global varccommits varcorder parents vrowmod varcrow
     global d_valid_start d_valid_end
 
+    if {$end > $vrowmod($curview)} {
+       update_arcrows $curview
+    }
     set ai [bsearch $vrownum($curview) $start]
     set start [lindex $vrownum($curview) $ai]
     set narc [llength $vrownum($curview)]
@@ -786,7 +820,7 @@ proc commitonrow {row} {
 
 proc closevarcs {v} {
     global varctok varccommits varcid parents children
-    global cmitlisted commitidx commitinterest vtokmod varcmod
+    global cmitlisted commitidx commitinterest vtokmod
 
     set missing_parents 0
     set scripts {}
@@ -806,12 +840,10 @@ proc closevarcs {v} {
                set b [newvarc $v $p]
            }
            set varcid($v,$p) $b
-           lappend varccommits($v,$b) $p
-           set tok [lindex $varctok($v) $b]
-           if {[string compare $tok $vtokmod($v)] < 0} {
-               set vtokmod($v) $tok
-               set varcmod($v) $b
+           if {[string compare [lindex $varctok($v) $b] $vtokmod($v)] < 0} {
+               modify_arc $v $b
            }
+           lappend varccommits($v,$b) $p
            incr commitidx($v)
            if {[info exists commitinterest($p)]} {
                foreach script $commitinterest($p) {
@@ -822,7 +854,6 @@ proc closevarcs {v} {
        }
     }
     if {$missing_parents > 0} {
-       update_arcrows $v
        foreach s $scripts {
            eval $s
        }
@@ -830,11 +861,11 @@ proc closevarcs {v} {
 }
 
 proc getcommitlines {fd inst view}  {
-    global cmitlisted commitinterest leftover getdbg
-    global commitidx commitdata
+    global cmitlisted commitinterest leftover
+    global commitidx commitdata datemode
     global parents children curview hlview
-    global ordertok vnextroot idpending
-    global varccommits varcid varctok vtokmod varcmod
+    global vnextroot idpending ordertok
+    global varccommits varcid varctok vtokmod
 
     set stuff [read $fd 500000]
     # git log doesn't terminate the last commit with a null...
@@ -929,35 +960,14 @@ proc getcommitlines {fd inst view}  {
            if {[string length $shortcmit] > 80} {
                set shortcmit "[string range $shortcmit 0 80]..."
            }
-           error_popup "Can't parse git log output: {$shortcmit}"
+           error_popup "[mc "Can't parse git log output:"] {$shortcmit}"
            exit 1
        }
        set id [lindex $ids 0]
        set vid $view,$id
        if {!$listed && [info exists parents($vid)]} continue
-       if {![info exists ordertok($vid)]} {
-           set otok "o[strrep $vnextroot($view)]"
-           incr vnextroot($view)
-           set ordertok($vid) $otok
-       } else {
-           set otok $ordertok($vid)
-       }
        if {$listed} {
            set olds [lrange $ids 1 end]
-           if {[llength $olds] == 1} {
-               set p [lindex $olds 0]
-               if {![info exists ordertok($view,$p)]} {
-                   set ordertok($view,$p) $ordertok($vid)
-               }
-           } else {
-               set i 0
-               foreach p $olds {
-                   if {![info exists ordertok($view,$p)]} {
-                       set ordertok($view,$p) "$otok[strrep $i]]"
-                   }
-                   incr i
-               }
-           }
        } else {
            set olds {}
        }
@@ -967,12 +977,12 @@ proc getcommitlines {fd inst view}  {
        set a 0
        if {![info exists children($vid)]} {
            set children($vid) {}
-       } else {
-           if {[llength $children($vid)] == 1} {
-               set k [lindex $children($vid) 0]
-               if {[llength $parents($view,$k)] == 1} {
-                   set a $varcid($view,$k)
-               }
+       } elseif {[llength $children($vid)] == 1} {
+           set k [lindex $children($vid) 0]
+           if {[llength $parents($view,$k)] == 1 &&
+               (!$datemode ||
+                $varcid($view,$k) == [llength $varctok($view)] - 1)} {
+               set a $varcid($view,$k)
            }
        }
        if {$a == 0} {
@@ -980,8 +990,11 @@ proc getcommitlines {fd inst view}  {
            set a [newvarc $view $id]
        }
        set varcid($vid) $a
+       if {[string compare [lindex $varctok($view) $a] $vtokmod($view)] < 0} {
+           modify_arc $view $a
+       }
        lappend varccommits($view,$a) $id
-       set tok [lindex $varctok($view) $a]
+
        set i 0
        foreach p $olds {
            if {$i == 0 || [lsearch -exact $olds $p] >= $i} {
@@ -990,17 +1003,14 @@ proc getcommitlines {fd inst view}  {
                    [vtokcmp $view [lindex $children($vp) end-1] $id] > 0} {
                    set children($vp) [lsort -command [list vtokcmp $view] \
                                           $children($vp)]
+                   catch {unset ordertok}
+               }
+               if {[info exists varcid($view,$p)]} {
+                   fix_reversal $p $a $view
                }
-           }
-           if {[info exists varcid($view,$p)]} {
-               fix_reversal $p $a $view
            }
            incr i
        }
-       if {[string compare $tok $vtokmod($view)] < 0} {
-           set vtokmod($view) $tok
-           set varcmod($view) $a
-       }
 
        incr commitidx($view)
        if {[info exists commitinterest($id)]} {
@@ -1012,7 +1022,6 @@ proc getcommitlines {fd inst view}  {
        set gotsome 1
     }
     if {$gotsome} {
-       update_arcrows $view
        run chewcommits $view
        foreach s $scripts {
            eval $s
@@ -1055,7 +1064,7 @@ proc chewcommits {view} {
     if {$view == $curview} {
        layoutmore
        if {$viewcomplete($view)} {
-           global commitidx
+           global commitidx varctok
            global numcommits startmsecs
            global mainheadid commitinfo nullid
 
@@ -1066,10 +1075,9 @@ proc chewcommits {view} {
            if {$commitidx($curview) > 0} {
                #set ms [expr {[clock clicks -milliseconds] - $startmsecs}]
                #puts "overall $ms ms for $numcommits commits"
-               #global uat
-               #puts "${uat}ms in update_arcrows"
+               #puts "[llength $varctok($view)] arcs, $commitidx($view) commits"
            } else {
-               show_status "No commits selected"
+               show_status [mc "No commits selected"]
            }
            notbusy layout
        }
@@ -1150,7 +1158,7 @@ proc getcommit {id} {
     } else {
        readcommit $id
        if {![info exists commitinfo($id)]} {
-           set commitinfo($id) {"No commit information available"}
+           set commitinfo($id) [list [mc "No commit information available"]]
        }
     }
     return 1
@@ -1249,7 +1257,7 @@ proc removehead {id name} {
 proc show_error {w top msg} {
     message $w.m -text $msg -justify center -aspect 400
     pack $w.m -side top -fill x -padx 20 -pady 20
-    button $w.ok -text OK -command "destroy $top"
+    button $w.ok -text [mc OK] -command "destroy $top"
     pack $w.ok -side bottom -fill x
     bind $top <Visibility> "grab $top; focus $top"
     bind $top <Key-Return> "destroy $top"
@@ -1271,9 +1279,9 @@ proc confirm_popup msg {
     wm transient $w .
     message $w.m -text $msg -justify center -aspect 400
     pack $w.m -side top -fill x -padx 20 -pady 20
-    button $w.ok -text OK -command "set confirm_ok 1; destroy $w"
+    button $w.ok -text [mc OK] -command "set confirm_ok 1; destroy $w"
     pack $w.ok -side left -fill x
-    button $w.cancel -text Cancel -command "destroy $w"
+    button $w.cancel -text [mc Cancel] -command "destroy $w"
     pack $w.cancel -side right -fill x
     bind $w <Visibility> "grab $w; focus $w"
     tkwait window $w
@@ -1297,34 +1305,34 @@ proc makewindow {} {
     global have_tk85
 
     menu .bar
-    .bar add cascade -label "File" -menu .bar.file
+    .bar add cascade -label [mc "File"] -menu .bar.file
     .bar configure -font uifont
     menu .bar.file
-    .bar.file add command -label "Update" -command updatecommits
-    .bar.file add command -label "Reload" -command reloadcommits
-    .bar.file add command -label "Reread references" -command rereadrefs
-    .bar.file add command -label "List references" -command showrefs
-    .bar.file add command -label "Quit" -command doquit
+    .bar.file add command -label [mc "Update"] -command updatecommits
+    .bar.file add command -label [mc "Reload"] -command reloadcommits
+    .bar.file add command -label [mc "Reread references"] -command rereadrefs
+    .bar.file add command -label [mc "List references"] -command showrefs
+    .bar.file add command -label [mc "Quit"] -command doquit
     .bar.file configure -font uifont
     menu .bar.edit
-    .bar add cascade -label "Edit" -menu .bar.edit
-    .bar.edit add command -label "Preferences" -command doprefs
+    .bar add cascade -label [mc "Edit"] -menu .bar.edit
+    .bar.edit add command -label [mc "Preferences"] -command doprefs
     .bar.edit configure -font uifont
 
     menu .bar.view -font uifont
-    .bar add cascade -label "View" -menu .bar.view
-    .bar.view add command -label "New view..." -command {newview 0}
-    .bar.view add command -label "Edit view..." -command editview \
+    .bar add cascade -label [mc "View"] -menu .bar.view
+    .bar.view add command -label [mc "New view..."] -command {newview 0}
+    .bar.view add command -label [mc "Edit view..."] -command editview \
        -state disabled
-    .bar.view add command -label "Delete view" -command delview -state disabled
+    .bar.view add command -label [mc "Delete view"] -command delview -state disabled
     .bar.view add separator
-    .bar.view add radiobutton -label "All files" -command {showview 0} \
+    .bar.view add radiobutton -label [mc "All files"] -command {showview 0} \
        -variable selectedview -value 0
 
     menu .bar.help
-    .bar add cascade -label "Help" -menu .bar.help
-    .bar.help add command -label "About gitk" -command about
-    .bar.help add command -label "Key bindings" -command keys
+    .bar add cascade -label [mc "Help"] -menu .bar.help
+    .bar.help add command -label [mc "About gitk"] -command about
+    .bar.help add command -label [mc "Key bindings"] -command keys
     .bar.help configure -font uifont
     . configure -menu .bar
 
@@ -1381,7 +1389,7 @@ proc makewindow {} {
     set sha1entry .tf.bar.sha1
     set entries $sha1entry
     set sha1but .tf.bar.sha1label
-    button $sha1but -text "SHA1 ID: " -state disabled -relief flat \
+    button $sha1but -text [mc "SHA1 ID: "] -state disabled -relief flat \
        -command gotocommit -width 8 -font uifont
     $sha1but conf -disabledforeground [$sha1but cget -foreground]
     pack .tf.bar.sha1label -side left
@@ -1431,17 +1439,17 @@ proc makewindow {} {
     set progupdatepending 0
 
     # build up the bottom bar of upper window
-    label .tf.lbar.flabel -text "Find " -font uifont
-    button .tf.lbar.fnext -text "next" -command {dofind 1 1} -font uifont
-    button .tf.lbar.fprev -text "prev" -command {dofind -1 1} -font uifont
-    label .tf.lbar.flab2 -text " commit " -font uifont
+    label .tf.lbar.flabel -text "[mc "Find"] " -font uifont
+    button .tf.lbar.fnext -text [mc "next"] -command {dofind 1 1} -font uifont
+    button .tf.lbar.fprev -text [mc "prev"] -command {dofind -1 1} -font uifont
+    label .tf.lbar.flab2 -text " [mc "commit"] " -font uifont
     pack .tf.lbar.flabel .tf.lbar.fnext .tf.lbar.fprev .tf.lbar.flab2 \
        -side left -fill y
-    set gdttype "containing:"
+    set gdttype [mc "containing:"]
     set gm [tk_optionMenu .tf.lbar.gdttype gdttype \
-               "containing:" \
-               "touching paths:" \
-               "adding/removing string:"]
+               [mc "containing:"] \
+               [mc "touching paths:"] \
+               [mc "adding/removing string:"]]
     trace add variable gdttype write gdttype_change
     $gm conf -font uifont
     .tf.lbar.gdttype conf -font uifont
@@ -1452,15 +1460,15 @@ proc makewindow {} {
     lappend entries $fstring
     entry $fstring -width 30 -font textfont -textvariable findstring
     trace add variable findstring write find_change
-    set findtype Exact
+    set findtype [mc "Exact"]
     set findtypemenu [tk_optionMenu .tf.lbar.findtype \
-                     findtype Exact IgnCase Regexp]
+                     findtype [mc "Exact"] [mc "IgnCase"] [mc "Regexp"]]
     trace add variable findtype write findcom_change
     .tf.lbar.findtype configure -font uifont
     .tf.lbar.findtype.menu configure -font uifont
-    set findloc "All fields"
-    tk_optionMenu .tf.lbar.findloc findloc "All fields" Headline \
-       Comments Author Committer
+    set findloc [mc "All fields"]
+    tk_optionMenu .tf.lbar.findloc findloc [mc "All fields"] [mc "Headline"] \
+       [mc "Comments"] [mc "Author"] [mc "Committer"]
     trace add variable findloc write find_change
     .tf.lbar.findloc configure -font uifont
     .tf.lbar.findloc.menu configure -font uifont
@@ -1490,7 +1498,7 @@ proc makewindow {} {
     frame .bleft.top
     frame .bleft.mid
 
-    button .bleft.top.search -text "Search" -command dosearch \
+    button .bleft.top.search -text [mc "Search"] -command dosearch \
        -font uifont
     pack .bleft.top.search -side left -padx 5
     set sstring .bleft.top.sstring
@@ -1498,13 +1506,13 @@ proc makewindow {} {
     lappend entries $sstring
     trace add variable searchstring write incrsearch
     pack $sstring -side left -expand 1 -fill x
-    radiobutton .bleft.mid.diff -text "Diff" -font uifont \
+    radiobutton .bleft.mid.diff -text [mc "Diff"] -font uifont \
        -command changediffdisp -variable diffelide -value {0 0}
-    radiobutton .bleft.mid.old -text "Old version" -font uifont \
+    radiobutton .bleft.mid.old -text [mc "Old version"] -font uifont \
        -command changediffdisp -variable diffelide -value {0 1}
-    radiobutton .bleft.mid.new -text "New version" -font uifont \
+    radiobutton .bleft.mid.new -text [mc "New version"] -font uifont \
        -command changediffdisp -variable diffelide -value {1 0}
-    label .bleft.mid.labeldiffcontext -text "      Lines of context: " \
+    label .bleft.mid.labeldiffcontext -text "      [mc "Lines of context"]: " \
        -font uifont
     pack .bleft.mid.diff .bleft.mid.old .bleft.mid.new -side left
     spinbox .bleft.mid.diffcontext -width 5 -font textfont \
@@ -1563,10 +1571,10 @@ proc makewindow {} {
     # lower right
     frame .bright
     frame .bright.mode
-    radiobutton .bright.mode.patch -text "Patch" \
+    radiobutton .bright.mode.patch -text [mc "Patch"] \
        -command reselectline -variable cmitmode -value "patch"
     .bright.mode.patch configure -font uifont
-    radiobutton .bright.mode.tree -text "Tree" \
+    radiobutton .bright.mode.tree -text [mc "Tree"] \
        -command reselectline -variable cmitmode -value "tree"
     .bright.mode.tree configure -font uifont
     grid .bright.mode.patch .bright.mode.tree -sticky ew
@@ -1683,43 +1691,43 @@ proc makewindow {} {
 
     set rowctxmenu .rowctxmenu
     menu $rowctxmenu -tearoff 0
-    $rowctxmenu add command -label "Diff this -> selected" \
+    $rowctxmenu add command -label [mc "Diff this -> selected"] \
        -command {diffvssel 0}
-    $rowctxmenu add command -label "Diff selected -> this" \
+    $rowctxmenu add command -label [mc "Diff selected -> this"] \
        -command {diffvssel 1}
-    $rowctxmenu add command -label "Make patch" -command mkpatch
-    $rowctxmenu add command -label "Create tag" -command mktag
-    $rowctxmenu add command -label "Write commit to file" -command writecommit
-    $rowctxmenu add command -label "Create new branch" -command mkbranch
-    $rowctxmenu add command -label "Cherry-pick this commit" \
+    $rowctxmenu add command -label [mc "Make patch"] -command mkpatch
+    $rowctxmenu add command -label [mc "Create tag"] -command mktag
+    $rowctxmenu add command -label [mc "Write commit to file"] -command writecommit
+    $rowctxmenu add command -label [mc "Create new branch"] -command mkbranch
+    $rowctxmenu add command -label [mc "Cherry-pick this commit"] \
        -command cherrypick
-    $rowctxmenu add command -label "Reset HEAD branch to here" \
+    $rowctxmenu add command -label [mc "Reset HEAD branch to here"] \
        -command resethead
 
     set fakerowmenu .fakerowmenu
     menu $fakerowmenu -tearoff 0
-    $fakerowmenu add command -label "Diff this -> selected" \
+    $fakerowmenu add command -label [mc "Diff this -> selected"] \
        -command {diffvssel 0}
-    $fakerowmenu add command -label "Diff selected -> this" \
+    $fakerowmenu add command -label [mc "Diff selected -> this"] \
        -command {diffvssel 1}
-    $fakerowmenu add command -label "Make patch" -command mkpatch
-#    $fakerowmenu add command -label "Commit" -command {mkcommit 0}
-#    $fakerowmenu add command -label "Commit all" -command {mkcommit 1}
-#    $fakerowmenu add command -label "Revert local changes" -command revertlocal
+    $fakerowmenu add command -label [mc "Make patch"] -command mkpatch
+#    $fakerowmenu add command -label [mc "Commit"] -command {mkcommit 0}
+#    $fakerowmenu add command -label [mc "Commit all"] -command {mkcommit 1}
+#    $fakerowmenu add command -label [mc "Revert local changes"] -command revertlocal
 
     set headctxmenu .headctxmenu
     menu $headctxmenu -tearoff 0
-    $headctxmenu add command -label "Check out this branch" \
+    $headctxmenu add command -label [mc "Check out this branch"] \
        -command cobranch
-    $headctxmenu add command -label "Remove this branch" \
+    $headctxmenu add command -label [mc "Remove this branch"] \
        -command rmbranch
 
     global flist_menu
     set flist_menu .flistctxmenu
     menu $flist_menu -tearoff 0
-    $flist_menu add command -label "Highlight this too" \
+    $flist_menu add command -label [mc "Highlight this too"] \
        -command {flist_hl 0}
-    $flist_menu add command -label "Highlight this only" \
+    $flist_menu add command -label [mc "Highlight this only"] \
        -command {flist_hl 1}
 }
 
@@ -1945,17 +1953,17 @@ proc about {} {
        return
     }
     toplevel $w
-    wm title $w "About gitk"
-    message $w.m -text {
+    wm title $w [mc "About gitk"]
+    message $w.m -text [mc "
 Gitk - a commit viewer for git
 
-Copyright Â© 2005-2007 Paul Mackerras
+Copyright Â© 2005-2006 Paul Mackerras
 
-Use and redistribute under the terms of the GNU General Public License} \
+Use and redistribute under the terms of the GNU General Public License"] \
            -justify center -aspect 400 -border 2 -bg white -relief groove
     pack $w.m -side top -fill x -padx 2 -pady 2
     $w.m configure -font uifont
-    button $w.ok -text Close -command "destroy $w" -default active
+    button $w.ok -text [mc "Close"] -command "destroy $w" -default active
     pack $w.ok -side bottom
     $w.ok configure -font uifont
     bind $w <Visibility> "focus $w.ok"
@@ -1976,8 +1984,8 @@ proc keys {} {
        set M1T Ctrl
     }
     toplevel $w
-    wm title $w "Gitk key bindings"
-    message $w.m -text "
+    wm title $w [mc "Gitk key bindings"]
+    message $w.m -text [mc "
 Gitk key bindings:
 
 <$M1T-Q>               Quit
@@ -2015,11 +2023,11 @@ f               Scroll diff view to next file
 <$M1T-KP->     Decrease font size
 <$M1T-minus>   Decrease font size
 <F5>           Update
-" \
+"] \
            -justify left -bg white -border 2 -relief groove
     pack $w.m -side top -fill both -padx 2 -pady 2
     $w.m configure -font uifont
-    button $w.ok -text Close -command "destroy $w" -default active
+    button $w.ok -text [mc "Close"] -command "destroy $w" -default active
     pack $w.ok -side bottom
     $w.ok configure -font uifont
     bind $w <Visibility> "focus $w.ok"
@@ -2411,12 +2419,12 @@ proc flist_hl {only} {
     global flist_menu_file findstring gdttype
 
     set x [shellquote $flist_menu_file]
-    if {$only || $findstring eq {} || $gdttype ne "touching paths:"} {
+    if {$only || $findstring eq {} || $gdttype ne [mc "touching paths:"]} {
        set findstring $x
     } else {
        append findstring " " $x
     }
-    set gdttype "touching paths:"
+    set gdttype [mc "touching paths:"]
 }
 
 # Functions for adding and removing shell-type quoting
@@ -2528,7 +2536,7 @@ proc newview {ishighlight} {
     set newviewname($nextviewnum) "View $nextviewnum"
     set newviewperm($nextviewnum) 0
     set newviewargs($nextviewnum) [shellarglist $revtreeargs]
-    vieweditor $top $nextviewnum "Gitk view definition"
+    vieweditor $top $nextviewnum [mc "Gitk view definition"]
 }
 
 proc editview {} {
@@ -2553,20 +2561,20 @@ proc vieweditor {top n title} {
 
     toplevel $top
     wm title $top $title
-    label $top.nl -text "Name" -font uifont
+    label $top.nl -text [mc "Name"] -font uifont
     entry $top.name -width 20 -textvariable newviewname($n) -font uifont
     grid $top.nl $top.name -sticky w -pady 5
-    checkbutton $top.perm -text "Remember this view" -variable newviewperm($n) \
+    checkbutton $top.perm -text [mc "Remember this view"] -variable newviewperm($n) \
        -font uifont
     grid $top.perm - -pady 5 -sticky w
     message $top.al -aspect 1000 -font uifont \
-       -text "Commits to include (arguments to git rev-list):"
+       -text [mc "Commits to include (arguments to git rev-list):"]
     grid $top.al - -sticky w -pady 5
     entry $top.args -width 50 -textvariable newviewargs($n) \
        -background white -font uifont
     grid $top.args - -sticky ew -padx 5
     message $top.l -aspect 1000 -font uifont \
-       -text "Enter files and directories to include, one per line:"
+       -text [mc "Enter files and directories to include, one per line:"]
     grid $top.l - -sticky w
     text $top.t -width 40 -height 10 -background white -font uifont
     if {[info exists viewfiles($n)]} {
@@ -2579,9 +2587,9 @@ proc vieweditor {top n title} {
     }
     grid $top.t - -sticky ew -padx 5
     frame $top.buts
-    button $top.buts.ok -text "OK" -command [list newviewok $top $n] \
+    button $top.buts.ok -text [mc "OK"] -command [list newviewok $top $n] \
        -font uifont
-    button $top.buts.can -text "Cancel" -command [list destroy $top] \
+    button $top.buts.can -text [mc "Cancel"] -command [list destroy $top] \
        -font uifont
     grid $top.buts.ok $top.buts.can
     grid columnconfigure $top.buts 0 -weight 1 -uniform a
@@ -2615,7 +2623,7 @@ proc newviewok {top n} {
     if {[catch {
        set newargs [shellsplit $newviewargs($n)]
     } err]} {
-       error_popup "Error in commit selection arguments: $err"
+       error_popup "[mc "Error in commit selection arguments:"] $err"
        wm raise $top
        focus $top
        return
@@ -2666,7 +2674,7 @@ proc delview {} {
 
     if {$curview == 0} return
     if {[info exists hlview] && $hlview == $curview} {
-       set selectedhlview None
+       set selectedhlview [mc "None"]
        unset hlview
     }
     allviewmenus $curview delete
@@ -2684,7 +2692,7 @@ proc addviewmenu {n} {
 }
 
 proc showview {n} {
-    global curview viewfiles cached_commitrow
+    global curview viewfiles cached_commitrow ordertok
     global displayorder parentlist rowidlist rowisopt rowfinal
     global colormap rowtextx nextcolor canvxmax
     global numcommits viewcomplete
@@ -2718,15 +2726,16 @@ proc showview {n} {
     clear_display
     if {[info exists hlview] && $hlview == $n} {
        unset hlview
-       set selectedhlview None
+       set selectedhlview [mc "None"]
     }
     catch {unset commitinterest}
     catch {unset cached_commitrow}
+    catch {unset ordertok}
 
     set curview $n
     set selectedview $n
-    .bar.view entryconf Edit* -state [expr {$n == 0? "disabled": "normal"}]
-    .bar.view entryconf Delete* -state [expr {$n == 0? "disabled": "normal"}]
+    .bar.view entryconf [mc "Edit view..."] -state [expr {$n == 0? "disabled": "normal"}]
+    .bar.view entryconf [mc "Delete view"] -state [expr {$n == 0? "disabled": "normal"}]
 
     run refill_reflist
     if {![info exists viewcomplete($n)]} {
@@ -2780,12 +2789,10 @@ proc showview {n} {
     }
     if {!$viewcomplete($n)} {
        if {$numcommits == 0} {
-           show_status "Reading commits..."
-       } else {
-           run chewcommits $n
+           show_status [mc "Reading commits..."]
        }
     } elseif {$numcommits == 0} {
-       show_status "No commits selected"
+       show_status [mc "No commits selected"]
     }
 }
 
@@ -2936,7 +2943,7 @@ proc gdttype_change {name ix op} {
 
     stopfinding
     if {$findstring ne {}} {
-       if {$gdttype eq "containing:"} {
+       if {$gdttype eq [mc "containing:"]} {
            if {$highlight_files ne {}} {
                set highlight_files {}
                hfiles_change
@@ -2959,7 +2966,7 @@ proc find_change {name ix op} {
     global gdttype findstring highlight_files
 
     stopfinding
-    if {$gdttype eq "containing:"} {
+    if {$gdttype eq [mc "containing:"]} {
        findcom_change
     } else {
        if {$highlight_files ne $findstring} {
@@ -2983,9 +2990,9 @@ proc findcom_change args {
     catch {unset nhighlights}
     unbolden
     unmarkmatches
-    if {$gdttype ne "containing:" || $findstring eq {}} {
+    if {$gdttype ne [mc "containing:"] || $findstring eq {}} {
        set findpattern {}
-    } elseif {$findtype eq "Regexp"} {
+    } elseif {$findtype eq [mc "Regexp"]} {
        set findpattern $findstring
     } else {
        set e [string map {"*" "\\*" "?" "\\?" "\[" "\\\[" "\\" "\\\\"} \
@@ -3011,12 +3018,12 @@ proc makepatterns {l} {
 proc do_file_hl {serial} {
     global highlight_files filehighlight highlight_paths gdttype fhl_list
 
-    if {$gdttype eq "touching paths:"} {
+    if {$gdttype eq [mc "touching paths:"]} {
        if {[catch {set paths [shellsplit $highlight_files]}]} return
        set highlight_paths [makepatterns $paths]
        highlight_filelist
        set gdtargs [concat -- $paths]
-    } elseif {$gdttype eq "adding/removing string:"} {
+    } elseif {$gdttype eq [mc "adding/removing string:"]} {
        set gdtargs [list "-S$highlight_files"]
     } else {
        # must be "containing:", i.e. we're searching commit info
@@ -3092,9 +3099,9 @@ proc readfhighlight {} {
 proc doesmatch {f} {
     global findtype findpattern
 
-    if {$findtype eq "Regexp"} {
+    if {$findtype eq [mc "Regexp"]} {
        return [regexp $findpattern $f]
-    } elseif {$findtype eq "IgnCase"} {
+    } elseif {$findtype eq [mc "IgnCase"]} {
        return [string match -nocase $findpattern $f]
     } else {
        return [string match $findpattern $f]
@@ -3111,11 +3118,11 @@ proc askfindhighlight {row id} {
     }
     set info $commitinfo($id)
     set isbold 0
-    set fldtypes {Headline Author Date Committer CDate Comments}
+    set fldtypes [list [mc Headline] [mc Author] [mc Date] [mc Committer] [mc CDate] [mc Comments]]
     foreach f $info ty $fldtypes {
-       if {($findloc eq "All fields" || $findloc eq $ty) &&
+       if {($findloc eq [mc "All fields"] || $findloc eq $ty) &&
            [doesmatch $f]} {
-           if {$ty eq "Author"} {
+           if {$ty eq [mc "Author"]} {
                set isbold 2
                break
            }
@@ -3143,14 +3150,14 @@ proc markrowmatches {row id} {
     set author [lindex $commitinfo($id) 1]
     $canv delete match$row
     $canv2 delete match$row
-    if {$findloc eq "All fields" || $findloc eq "Headline"} {
+    if {$findloc eq [mc "All fields"] || $findloc eq [mc "Headline"]} {
        set m [findmatches $headline]
        if {$m ne {}} {
            markmatches $canv $row $headline $linehtag($row) $m \
                [$canv itemcget $linehtag($row) -font] $row
        }
     }
-    if {$findloc eq "All fields" || $findloc eq "Author"} {
+    if {$findloc eq [mc "All fields"] || $findloc eq [mc "Author"]} {
        set m [findmatches $author]
        if {$m ne {}} {
            markmatches $canv2 $row $author $linentag($row) $m \
@@ -3163,7 +3170,7 @@ proc vrel_change {name ix op} {
     global highlight_related
 
     rhighlight_none
-    if {$highlight_related ne "None"} {
+    if {$highlight_related ne [mc "None"]} {
        run drawvisible
     }
 }
@@ -3177,7 +3184,7 @@ proc rhighlight_sel {a} {
     set desc_todo [list $a]
     catch {unset ancestor}
     set anc_todo [list $a]
-    if {$highlight_related ne "None"} {
+    if {$highlight_related ne [mc "None"]} {
        rhighlight_none
        run drawvisible
     }
@@ -3260,20 +3267,20 @@ proc askrelhighlight {row id} {
 
     if {![info exists selectedline]} return
     set isbold 0
-    if {$highlight_related eq "Descendent" ||
-       $highlight_related eq "Not descendent"} {
+    if {$highlight_related eq [mc "Descendent"] ||
+       $highlight_related eq [mc "Not descendent"]} {
        if {![info exists descendent($id)]} {
            is_descendent $id
        }
-       if {$descendent($id) == ($highlight_related eq "Descendent")} {
+       if {$descendent($id) == ($highlight_related eq [mc "Descendent"])} {
            set isbold 1
        }
-    } elseif {$highlight_related eq "Ancestor" ||
-             $highlight_related eq "Not ancestor"} {
+    } elseif {$highlight_related eq [mc "Ancestor"] ||
+             $highlight_related eq [mc "Not ancestor"]} {
        if {![info exists ancestor($id)]} {
            is_ancestor $id
        }
-       if {$ancestor($id) == ($highlight_related eq "Ancestor")} {
+       if {$ancestor($id) == ($highlight_related eq [mc "Ancestor"])} {
            set isbold 1
        }
     }
@@ -3313,24 +3320,73 @@ proc ntimes {n o} {
     return $ret
 }
 
+proc ordertoken {id} {
+    global ordertok curview varcid varcstart varctok curview parents children
+    global nullid nullid2
+
+    if {[info exists ordertok($id)]} {
+       return $ordertok($id)
+    }
+    set origid $id
+    set todo {}
+    while {1} {
+       if {[info exists varcid($curview,$id)]} {
+           set a $varcid($curview,$id)
+           set p [lindex $varcstart($curview) $a]
+       } else {
+           set p [lindex $children($curview,$id) 0]
+       }
+       if {[info exists ordertok($p)]} {
+           set tok $ordertok($p)
+           break
+       }
+       if {[llength $children($curview,$p)] == 0} {
+           # it's a root
+           set tok [lindex $varctok($curview) $a]
+           break
+       }
+       set id [lindex $children($curview,$p) 0]
+       if {$id eq $nullid || $id eq $nullid2} {
+           # XXX treat it as a root
+           set tok [lindex $varctok($curview) $a]
+           break
+       }
+       if {[llength $parents($curview,$id)] == 1} {
+           lappend todo [list $p {}]
+       } else {
+           set j [lsearch -exact $parents($curview,$id) $p]
+           if {$j < 0} {
+               puts "oops didn't find [shortids $p] in parents of [shortids $id]"
+           }
+           lappend todo [list $p [strrep $j]]
+       }
+    }
+    for {set i [llength $todo]} {[incr i -1] >= 0} {} {
+       set p [lindex $todo $i 0]
+       append tok [lindex $todo $i 1]
+       set ordertok($p) $tok
+    }
+    set ordertok($origid) $tok
+    return $tok
+}
+
 # Work out where id should go in idlist so that order-token
 # values increase from left to right
 proc idcol {idlist id {i 0}} {
-    global ordertok curview
-
-    set t $ordertok($curview,$id)
-    if {$i >= [llength $idlist] ||
-       $t < $ordertok($curview,[lindex $idlist $i])} {
+    set t [ordertoken $id]
+    if {$i < 0} {
+       set i 0
+    }
+    if {$i >= [llength $idlist] || $t < [ordertoken [lindex $idlist $i]]} {
        if {$i > [llength $idlist]} {
            set i [llength $idlist]
        }
-       while {[incr i -1] >= 0 &&
-              $t < $ordertok($curview,[lindex $idlist $i])} {}
+       while {[incr i -1] >= 0 && $t < [ordertoken [lindex $idlist $i]]} {}
        incr i
     } else {
-       if {$t > $ordertok($curview,[lindex $idlist $i])} {
+       if {$t > [ordertoken [lindex $idlist $i]]} {
            while {[incr i] < [llength $idlist] &&
-                  $t >= $ordertok($curview,[lindex $idlist $i])} {}
+                  $t >= [ordertoken [lindex $idlist $i]]} {}
        }
     }
     return $i
@@ -3471,19 +3527,23 @@ proc readdiffindex {fd serial} {
     # we only need to see one line and we don't really care what it says...
     close $fd
 
-    # now see if there are any local changes not checked in to the index
-    if {$serial == $lserial} {
-       set fd [open "|git diff-files" r]
-       fconfigure $fd -blocking 0
-       filerun $fd [list readdifffiles $fd $serial]
+    if {$serial != $lserial} {
+       return 0
     }
 
-    if {$isdiff && $serial == $lserial && ![commitinview $nullid2 $curview]} {
+    # now see if there are any local changes not checked in to the index
+    set fd [open "|git diff-files" r]
+    fconfigure $fd -blocking 0
+    filerun $fd [list readdifffiles $fd $serial]
+
+    if {$isdiff && ![commitinview $nullid2 $curview]} {
        # add the line for the changes in the index to the graph
-       set hl "Local changes checked in to index but not committed"
+       set hl [mc "Local changes checked in to index but not committed"]
        set commitinfo($nullid2) [list  $hl {} {} {} {} "    $hl\n"]
        set commitdata($nullid2) "\n    $hl\n"
        insertrow $nullid2 $mainheadid $curview
+    } elseif {!$isdiff && [commitinview $nullid2 $curview]} {
+       removerow $nullid2 $curview
     }
     return 0
 }
@@ -3502,9 +3562,13 @@ proc readdifffiles {fd serial} {
     # we only need to see one line and we don't really care what it says...
     close $fd
 
-    if {$isdiff && $serial == $lserial && ![commitinview $nullid $curview]} {
+    if {$serial != $lserial} {
+       return 0
+    }
+
+    if {$isdiff && ![commitinview $nullid $curview]} {
        # add the line for the local diff to the graph
-       set hl "Local uncommitted changes, not checked in to index"
+       set hl [mc "Local uncommitted changes, not checked in to index"]
        set commitinfo($nullid) [list  $hl {} {} {} {} "    $hl\n"]
        set commitdata($nullid) "\n    $hl\n"
        if {[commitinview $nullid2 $curview]} {
@@ -3513,6 +3577,8 @@ proc readdifffiles {fd serial} {
            set p $mainheadid
        }
        insertrow $nullid $p $curview
+    } elseif {!$isdiff && [commitinview $nullid $curview]} {
+       removerow $nullid $curview
     }
     return 0
 }
@@ -3553,7 +3619,7 @@ proc prevuse {id row} {
 
 proc make_idlist {row} {
     global displayorder parentlist uparrowlen downarrowlen mingaplen
-    global commitidx curview ordertok children
+    global commitidx curview children
 
     set r [expr {$row - $mingaplen - $downarrowlen - 1}]
     if {$r < 0} {
@@ -3576,7 +3642,7 @@ proc make_idlist {row} {
            set rn [nextuse $p $r]
            if {$rn >= $row &&
                $rn <= $r + $downarrowlen + $mingaplen + $uparrowlen} {
-               lappend ids [list $ordertok($curview,$p) $p]
+               lappend ids [list [ordertoken $p] $p]
            }
        }
     }
@@ -3586,17 +3652,17 @@ proc make_idlist {row} {
            if {$p eq $nextid} continue
            set rn [nextuse $p $r]
            if {$rn < 0 || $rn >= $row} {
-               lappend ids [list $ordertok($curview,$p) $p]
+               lappend ids [list [ordertoken $p] $p]
            }
        }
     }
     set id [lindex $displayorder $row]
-    lappend ids [list $ordertok($curview,$id) $id]
+    lappend ids [list [ordertoken $id] $id]
     while {$r < $rb} {
        foreach p [lindex $parentlist $r] {
            set firstkid [lindex $children($curview,$p) 0]
            if {[rowofcommit $firstkid] < $row} {
-               lappend ids [list $ordertok($curview,$p) $p]
+               lappend ids [list [ordertoken $p] $p]
            }
        }
        incr r
@@ -3604,7 +3670,7 @@ proc make_idlist {row} {
        if {$id ne {}} {
            set firstkid [lindex $children($curview,$id) 0]
            if {$firstkid ne {} && [rowofcommit $firstkid] < $row} {
-               lappend ids [list $ordertok($curview,$id) $id]
+               lappend ids [list [ordertoken $id] $id]
            }
        }
     }
@@ -4338,7 +4404,7 @@ proc drawcmitrow {row} {
     if {$findpattern ne {} && ![info exists nhighlights($row)]} {
        askfindhighlight $row $id
     }
-    if {$highlight_related ne "None" && ![info exists rhighlights($row)]} {
+    if {$highlight_related ne [mc "None"] && ![info exists rhighlights($row)]} {
        askrelhighlight $row $id
     }
     if {![info exists iddrawn($id)]} {
@@ -4748,11 +4814,11 @@ proc notbusy {what} {
 
 proc findmatches {f} {
     global findtype findstring
-    if {$findtype == "Regexp"} {
+    if {$findtype == [mc "Regexp"]} {
        set matches [regexp -indices -all -inline $findstring $f]
     } else {
        set fs $findstring
-       if {$findtype == "IgnCase"} {
+       if {$findtype == [mc "IgnCase"]} {
            set f [string tolower $f]
            set fs [string tolower $fs]
        }
@@ -4783,8 +4849,8 @@ proc dofind {{dirn 1} {wrap 1}} {
        set findstartline $selectedline
     }
     set findcurline $findstartline
-    nowbusy finding "Searching"
-    if {$gdttype ne "containing:" && ![info exists filehighlight]} {
+    nowbusy finding [mc "Searching"]
+    if {$gdttype ne [mc "containing:"] && ![info exists filehighlight]} {
        after cancel do_file_hl $fh_serial
        do_file_hl $fh_serial
     }
@@ -4814,7 +4880,7 @@ proc findmore {} {
     if {![info exists find_dirn]} {
        return 0
     }
-    set fldtypes {Headline Author Date Committer CDate Comments}
+    set fldtypes [list [mc "Headline"] [mc "Author"] [mc "Date"] [mc "Committer"] [mc "CDate"] [mc "Comments"]]
     set l $findcurline
     set moretodo 0
     if {$find_dirn > 0} {
@@ -4852,7 +4918,7 @@ proc findmore {} {
     set arow [lindex $vrownum($curview) $ai]
     set ids [lindex $varccommits($curview,$a)]
     set arowend [expr {$arow + [llength $ids]}]
-    if {$gdttype eq "containing:"} {
+    if {$gdttype eq [mc "containing:"]} {
        for {} {$n > 0} {incr n -1; incr l $find_dirn} {
            if {$l < $arow || $l >= $arowend} {
                incr ai $find_dirn
@@ -4872,7 +4938,7 @@ proc findmore {} {
            }
            set info $commitinfo($id)
            foreach f $info ty $fldtypes {
-               if {($findloc eq "All fields" || $findloc eq $ty) &&
+               if {($findloc eq [mc "All fields"] || $findloc eq $ty) &&
                    [doesmatch $f]} {
                    set found 1
                    break
@@ -4935,7 +5001,7 @@ proc findselectline {l} {
     set markingmatches 1
     set findcurline $l
     selectline $l 1
-    if {$findloc == "All fields" || $findloc == "Comments"} {
+    if {$findloc == [mc "All fields"] || $findloc == [mc "Comments"]} {
        # highlight the matches in the comments
        set f [$ctext get 1.0 $commentend]
        set matches [findmatches $f]
@@ -5258,11 +5324,11 @@ proc selectline {l isnew} {
     set linknum 0
     set info $commitinfo($id)
     set date [formatdate [lindex $info 2]]
-    $ctext insert end "Author: [lindex $info 1]  $date\n"
+    $ctext insert end "[mc "Author"]: [lindex $info 1]  $date\n"
     set date [formatdate [lindex $info 4]]
-    $ctext insert end "Committer: [lindex $info 3]  $date\n"
+    $ctext insert end "[mc "Committer"]: [lindex $info 3]  $date\n"
     if {[info exists idtags($id)]} {
-       $ctext insert end "Tags:"
+       $ctext insert end [mc "Tags:"]
        foreach tag $idtags($id) {
            $ctext insert end " $tag"
        }
@@ -5279,18 +5345,18 @@ proc selectline {l isnew} {
            } else {
                set tag m$np
            }
-           $ctext insert end "Parent: " $tag
+           $ctext insert end "[mc "Parent"]: " $tag
            appendwithlinks [commit_descriptor $p] {}
            incr np
        }
     } else {
        foreach p $olds {
-           append headers "Parent: [commit_descriptor $p]"
+           append headers "[mc "Parent"]: [commit_descriptor $p]"
        }
     }
 
     foreach c $children($curview,$id) {
-       append headers "Child:  [commit_descriptor $c]"
+       append headers "[mc "Child"]:  [commit_descriptor $c]"
     }
 
     # make anything that looks like a SHA1 ID be a clickable link
@@ -5299,13 +5365,13 @@ proc selectline {l isnew} {
        if {![info exists allcommits]} {
            getallcommits
        }
-       $ctext insert end "Branch: "
+       $ctext insert end "[mc "Branch"]: "
        $ctext mark set branch "end -1c"
        $ctext mark gravity branch left
-       $ctext insert end "\nFollows: "
+       $ctext insert end "\n[mc "Follows"]: "
        $ctext mark set follows "end -1c"
        $ctext mark gravity follows left
-       $ctext insert end "\nPrecedes: "
+       $ctext insert end "\n[mc "Precedes"]: "
        $ctext mark set precedes "end -1c"
        $ctext mark gravity precedes left
        $ctext insert end "\n"
@@ -5322,7 +5388,7 @@ proc selectline {l isnew} {
     $ctext conf -state disabled
     set commentend [$ctext index "end - 1c"]
 
-    init_flist "Comments"
+    init_flist [mc "Comments"]
     if {$cmitmode eq "tree"} {
        gettree $id
     } elseif {[llength $olds] <= 1} {
@@ -5587,7 +5653,7 @@ proc mergediff {id} {
        set cmd [concat $cmd -- $viewfiles($curview)]
     }
     if {[catch {set mdf [open $cmd r]} err]} {
-       error_popup "Error getting merge diffs: $err"
+       error_popup "[mc "Error getting merge diffs:"] $err"
        return
     }
     fconfigure $mdf -blocking 0
@@ -6264,9 +6330,9 @@ proc sha1change {n1 n2 op} {
     }
     if {[$sha1but cget -state] == $state} return
     if {$state == "normal"} {
-       $sha1but conf -state normal -relief raised -text "Goto: "
+       $sha1but conf -state normal -relief raised -text "[mc "Goto:"] "
     } else {
-       $sha1but conf -state disabled -relief flat -text "SHA1 ID: "
+       $sha1but conf -state disabled -relief flat -text "[mc "SHA1 ID:"] "
     }
 }
 
@@ -6285,7 +6351,7 @@ proc gotocommit {} {
            set matches [array names varcid "$curview,$id*"]
            if {$matches ne {}} {
                if {[llength $matches] > 1} {
-                   error_popup "Short SHA1 id $id is ambiguous"
+                   error_popup [mc "Short SHA1 id %s is ambiguous" $id]
                    return
                }
                set id [lindex [split [lindex $matches 0] ","] 1]
@@ -6297,11 +6363,11 @@ proc gotocommit {} {
        return
     }
     if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
-       set type "SHA1 id"
+       set msg [mc "SHA1 id %s is not known" $sha1string]
     } else {
-       set type "Tag/Head"
+       set msg [mc "Tag/Head %s is not known" $sha1string]
     }
-    error_popup "$type $sha1string is not known"
+    error_popup $msg
 }
 
 proc lineenter {x y id} {
@@ -6431,17 +6497,17 @@ proc lineclick {x y id isnew} {
     $ctext conf -state normal
     clear_ctext
     settabs 0
-    $ctext insert end "Parent:\t"
+    $ctext insert end "[mc "Parent"]:\t"
     $ctext insert end $id link0
     setlink $id link0
     set info $commitinfo($id)
     $ctext insert end "\n\t[lindex $info 0]\n"
-    $ctext insert end "\tAuthor:\t[lindex $info 1]\n"
+    $ctext insert end "\t[mc "Author"]:\t[lindex $info 1]\n"
     set date [formatdate [lindex $info 2]]
-    $ctext insert end "\tDate:\t$date\n"
+    $ctext insert end "\t[mc "Date"]:\t$date\n"
     set kids $children($curview,$id)
     if {$kids ne {}} {
-       $ctext insert end "\nChildren:"
+       $ctext insert end "\n[mc "Children"]:"
        set i 0
        foreach child $kids {
            incr i
@@ -6451,9 +6517,9 @@ proc lineclick {x y id isnew} {
            $ctext insert end $child link$i
            setlink $child link$i
            $ctext insert end "\n\t[lindex $info 0]"
-           $ctext insert end "\n\tAuthor:\t[lindex $info 1]"
+           $ctext insert end "\n\t[mc "Author"]:\t[lindex $info 1]"
            set date [formatdate [lindex $info 2]]
-           $ctext insert end "\n\tDate:\t$date\n"
+           $ctext insert end "\n\t[mc "Date"]:\t$date\n"
        }
     }
     $ctext conf -state disabled
@@ -6498,13 +6564,13 @@ proc rowmenu {x y id} {
     }
     if {$id ne $nullid && $id ne $nullid2} {
        set menu $rowctxmenu
-       $menu entryconfigure 7 -label "Reset $mainhead branch to here"
+       $menu entryconfigure 7 -label [mc "Reset %s branch to here" $mainhead]
     } else {
        set menu $fakerowmenu
     }
-    $menu entryconfigure "Diff this*" -state $state
-    $menu entryconfigure "Diff selected*" -state $state
-    $menu entryconfigure "Make patch" -state $state
+    $menu entryconfigure [mc "Diff this -> selected"] -state $state
+    $menu entryconfigure [mc "Diff selected -> this"] -state $state
+    $menu entryconfigure [mc "Make patch"] -state $state
     tk_popup $menu $x $y
 }
 
@@ -6529,13 +6595,13 @@ proc doseldiff {oldid newid} {
 
     $ctext conf -state normal
     clear_ctext
-    init_flist "Top"
-    $ctext insert end "From "
+    init_flist [mc "Top"]
+    $ctext insert end "[mc "From"] "
     $ctext insert end $oldid link0
     setlink $oldid link0
     $ctext insert end "\n     "
     $ctext insert end [lindex $commitinfo($oldid) 0]
-    $ctext insert end "\n\nTo   "
+    $ctext insert end "\n\n[mc "To"]   "
     $ctext insert end $newid link1
     setlink $newid link1
     $ctext insert end "\n     "
@@ -6558,9 +6624,9 @@ proc mkpatch {} {
     set patchtop $top
     catch {destroy $top}
     toplevel $top
-    label $top.title -text "Generate patch"
+    label $top.title -text [mc "Generate patch"]
     grid $top.title - -pady 10
-    label $top.from -text "From:"
+    label $top.from -text [mc "From:"]
     entry $top.fromsha1 -width 40 -relief flat
     $top.fromsha1 insert 0 $oldid
     $top.fromsha1 conf -state readonly
@@ -6569,7 +6635,7 @@ proc mkpatch {} {
     $top.fromhead insert 0 $oldhead
     $top.fromhead conf -state readonly
     grid x $top.fromhead -sticky w
-    label $top.to -text "To:"
+    label $top.to -text [mc "To:"]
     entry $top.tosha1 -width 40 -relief flat
     $top.tosha1 insert 0 $newid
     $top.tosha1 conf -state readonly
@@ -6578,16 +6644,16 @@ proc mkpatch {} {
     $top.tohead insert 0 $newhead
     $top.tohead conf -state readonly
     grid x $top.tohead -sticky w
-    button $top.rev -text "Reverse" -command mkpatchrev -padx 5
+    button $top.rev -text [mc "Reverse"] -command mkpatchrev -padx 5
     grid $top.rev x -pady 10
-    label $top.flab -text "Output file:"
+    label $top.flab -text [mc "Output file:"]
     entry $top.fname -width 60
     $top.fname insert 0 [file normalize "patch$patchnum.patch"]
     incr patchnum
     grid $top.flab $top.fname -sticky w
     frame $top.buts
-    button $top.buts.gen -text "Generate" -command mkpatchgo
-    button $top.buts.can -text "Cancel" -command mkpatchcan
+    button $top.buts.gen -text [mc "Generate"] -command mkpatchgo
+    button $top.buts.can -text [mc "Cancel"] -command mkpatchcan
     grid $top.buts.gen $top.buts.can
     grid columnconfigure $top.buts 0 -weight 1 -uniform a
     grid columnconfigure $top.buts 1 -weight 1 -uniform a
@@ -6622,7 +6688,7 @@ proc mkpatchgo {} {
     set cmd [lrange $cmd 1 end]
     lappend cmd >$fname &
     if {[catch {eval exec $cmd} err]} {
-       error_popup "Error creating patch: $err"
+       error_popup "[mc "Error creating patch:"] $err"
     }
     catch {destroy $patchtop}
     unset patchtop
@@ -6642,9 +6708,9 @@ proc mktag {} {
     set mktagtop $top
     catch {destroy $top}
     toplevel $top
-    label $top.title -text "Create tag"
+    label $top.title -text [mc "Create tag"]
     grid $top.title - -pady 10
-    label $top.id -text "ID:"
+    label $top.id -text [mc "ID:"]
     entry $top.sha1 -width 40 -relief flat
     $top.sha1 insert 0 $rowmenuid
     $top.sha1 conf -state readonly
@@ -6653,12 +6719,12 @@ proc mktag {} {
     $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
     $top.head conf -state readonly
     grid x $top.head -sticky w
-    label $top.tlab -text "Tag name:"
+    label $top.tlab -text [mc "Tag name:"]
     entry $top.tag -width 60
     grid $top.tlab $top.tag -sticky w
     frame $top.buts
-    button $top.buts.gen -text "Create" -command mktaggo
-    button $top.buts.can -text "Cancel" -command mktagcan
+    button $top.buts.gen -text [mc "Create"] -command mktaggo
+    button $top.buts.can -text [mc "Cancel"] -command mktagcan
     grid $top.buts.gen $top.buts.can
     grid columnconfigure $top.buts 0 -weight 1 -uniform a
     grid columnconfigure $top.buts 1 -weight 1 -uniform a
@@ -6672,11 +6738,11 @@ proc domktag {} {
     set id [$mktagtop.sha1 get]
     set tag [$mktagtop.tag get]
     if {$tag == {}} {
-       error_popup "No tag name specified"
+       error_popup [mc "No tag name specified"]
        return
     }
     if {[info exists tagids($tag)]} {
-       error_popup "Tag \"$tag\" already exists"
+       error_popup [mc "Tag \"%s\" already exists" $tag]
        return
     }
     if {[catch {
@@ -6686,7 +6752,7 @@ proc domktag {} {
        puts $f $id
        close $f
     } err]} {
-       error_popup "Error creating tag: $err"
+       error_popup "[mc "Error creating tag:"] $err"
        return
     }
 
@@ -6739,9 +6805,9 @@ proc writecommit {} {
     set wrcomtop $top
     catch {destroy $top}
     toplevel $top
-    label $top.title -text "Write commit to file"
+    label $top.title -text [mc "Write commit to file"]
     grid $top.title - -pady 10
-    label $top.id -text "ID:"
+    label $top.id -text [mc "ID:"]
     entry $top.sha1 -width 40 -relief flat
     $top.sha1 insert 0 $rowmenuid
     $top.sha1 conf -state readonly
@@ -6750,16 +6816,16 @@ proc writecommit {} {
     $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
     $top.head conf -state readonly
     grid x $top.head -sticky w
-    label $top.clab -text "Command:"
+    label $top.clab -text [mc "Command:"]
     entry $top.cmd -width 60 -textvariable wrcomcmd
     grid $top.clab $top.cmd -sticky w -pady 10
-    label $top.flab -text "Output file:"
+    label $top.flab -text [mc "Output file:"]
     entry $top.fname -width 60
     $top.fname insert 0 [file normalize "commit-[string range $rowmenuid 0 6]"]
     grid $top.flab $top.fname -sticky w
     frame $top.buts
-    button $top.buts.gen -text "Write" -command wrcomgo
-    button $top.buts.can -text "Cancel" -command wrcomcan
+    button $top.buts.gen -text [mc "Write"] -command wrcomgo
+    button $top.buts.can -text [mc "Cancel"] -command wrcomcan
     grid $top.buts.gen $top.buts.can
     grid columnconfigure $top.buts 0 -weight 1 -uniform a
     grid columnconfigure $top.buts 1 -weight 1 -uniform a
@@ -6774,7 +6840,7 @@ proc wrcomgo {} {
     set cmd "echo $id | [$wrcomtop.cmd get]"
     set fname [$wrcomtop.fname get]
     if {[catch {exec sh -c $cmd >$fname &} err]} {
-       error_popup "Error writing commit: $err"
+       error_popup "[mc "Error writing commit:"] $err"
     }
     catch {destroy $wrcomtop}
     unset wrcomtop
@@ -6793,19 +6859,19 @@ proc mkbranch {} {
     set top .makebranch
     catch {destroy $top}
     toplevel $top
-    label $top.title -text "Create new branch"
+    label $top.title -text [mc "Create new branch"]
     grid $top.title - -pady 10
-    label $top.id -text "ID:"
+    label $top.id -text [mc "ID:"]
     entry $top.sha1 -width 40 -relief flat
     $top.sha1 insert 0 $rowmenuid
     $top.sha1 conf -state readonly
     grid $top.id $top.sha1 -sticky w
-    label $top.nlab -text "Name:"
+    label $top.nlab -text [mc "Name:"]
     entry $top.name -width 40
     grid $top.nlab $top.name -sticky w
     frame $top.buts
-    button $top.buts.go -text "Create" -command [list mkbrgo $top]
-    button $top.buts.can -text "Cancel" -command "catch {destroy $top}"
+    button $top.buts.go -text [mc "Create"] -command [list mkbrgo $top]
+    button $top.buts.can -text [mc "Cancel"] -command "catch {destroy $top}"
     grid $top.buts.go $top.buts.can
     grid columnconfigure $top.buts 0 -weight 1 -uniform a
     grid columnconfigure $top.buts 1 -weight 1 -uniform a
@@ -6819,7 +6885,7 @@ proc mkbrgo {top} {
     set name [$top.name get]
     set id [$top.sha1 get]
     if {$name eq {}} {
-       error_popup "Please specify a name for the new branch"
+       error_popup [mc "Please specify a name for the new branch"]
        return
     }
     catch {destroy $top}
@@ -6848,11 +6914,12 @@ proc cherrypick {} {
     set oldhead [exec git rev-parse HEAD]
     set dheads [descheads $rowmenuid]
     if {$dheads ne {} && [lsearch -exact $dheads $oldhead] >= 0} {
-       set ok [confirm_popup "Commit [string range $rowmenuid 0 7] is already\
-                       included in branch $mainhead -- really re-apply it?"]
+       set ok [confirm_popup [mc "Commit %s is already\
+               included in branch %s -- really re-apply it?" \
+                                  [string range $rowmenuid 0 7] $mainhead]]
        if {!$ok} return
     }
-    nowbusy cherrypick "Cherry-picking"
+    nowbusy cherrypick [mc "Cherry-picking"]
     update
     # Unfortunately git-cherry-pick writes stuff to stderr even when
     # no error occurs, and exec takes that as an indication of error...
@@ -6864,7 +6931,7 @@ proc cherrypick {} {
     set newhead [exec git rev-parse HEAD]
     if {$newhead eq $oldhead} {
        notbusy cherrypick
-       error_popup "No changes committed"
+       error_popup [mc "No changes committed"]
        return
     }
     addnewchild $newhead $oldhead
@@ -6887,28 +6954,28 @@ proc resethead {} {
     set w ".confirmreset"
     toplevel $w
     wm transient $w .
-    wm title $w "Confirm reset"
+    wm title $w [mc "Confirm reset"]
     message $w.m -text \
-       "Reset branch $mainhead to [string range $rowmenuid 0 7]?" \
+       [mc "Reset branch %s to %s?" $mainhead [string range $rowmenuid 0 7]] \
        -justify center -aspect 1000
     pack $w.m -side top -fill x -padx 20 -pady 20
     frame $w.f -relief sunken -border 2
-    message $w.f.rt -text "Reset type:" -aspect 1000
+    message $w.f.rt -text [mc "Reset type:"] -aspect 1000
     grid $w.f.rt -sticky w
     set resettype mixed
     radiobutton $w.f.soft -value soft -variable resettype -justify left \
-       -text "Soft: Leave working tree and index untouched"
+       -text [mc "Soft: Leave working tree and index untouched"]
     grid $w.f.soft -sticky w
     radiobutton $w.f.mixed -value mixed -variable resettype -justify left \
-       -text "Mixed: Leave working tree untouched, reset index"
+       -text [mc "Mixed: Leave working tree untouched, reset index"]
     grid $w.f.mixed -sticky w
     radiobutton $w.f.hard -value hard -variable resettype -justify left \
-       -text "Hard: Reset working tree and index\n(discard ALL local changes)"
+       -text [mc "Hard: Reset working tree and index\n(discard ALL local changes)"]
     grid $w.f.hard -sticky w
     pack $w.f -side top -fill x
-    button $w.ok -text OK -command "set confirm_ok 1; destroy $w"
+    button $w.ok -text [mc OK] -command "set confirm_ok 1; destroy $w"
     pack $w.ok -side left -fill x -padx 20 -pady 20
-    button $w.cancel -text Cancel -command "destroy $w"
+    button $w.cancel -text [mc Cancel] -command "destroy $w"
     pack $w.cancel -side right -fill x -padx 20 -pady 20
     bind $w <Visibility> "grab $w; focus $w"
     tkwait window $w
@@ -6919,7 +6986,7 @@ proc resethead {} {
     } else {
        dohidelocalchanges
        filerun $fd [list readresetstat $fd]
-       nowbusy reset "Resetting"
+       nowbusy reset [mc "Resetting"]
     }
 }
 
@@ -6976,7 +7043,7 @@ proc cobranch {} {
 
     # check the tree is clean first??
     set oldmainhead $mainhead
-    nowbusy checkout "Checking out"
+    nowbusy checkout [mc "Checking out"]
     update
     dohidelocalchanges
     if {[catch {
@@ -7006,14 +7073,14 @@ proc rmbranch {} {
     set id $headmenuid
     # this check shouldn't be needed any more...
     if {$head eq $mainhead} {
-       error_popup "Cannot delete the currently checked-out branch"
+       error_popup [mc "Cannot delete the currently checked-out branch"]
        return
     }
     set dheads [descheads $id]
     if {[llength $dheads] == 1 && $idheads($dheads) eq $head} {
        # the stuff on this branch isn't on any other branch
-       if {![confirm_popup "The commits on branch $head aren't on any other\
-                       branch.\nReally delete branch $head?"]} return
+       if {![confirm_popup [mc "The commits on branch %s aren't on any other\
+                       branch.\nReally delete branch %s?" $head $head]]} return
     }
     nowbusy rmbranch
     update
@@ -7043,7 +7110,7 @@ proc showrefs {} {
        return
     }
     toplevel $top
-    wm title $top "Tags and heads: [file tail [pwd]]"
+    wm title $top [mc "Tags and heads: %s" [file tail [pwd]]]
     text $top.list -background $bgcolor -foreground $fgcolor \
        -selectbackground $selectbgcolor -font mainfont \
        -xscrollcommand "$top.xsb set" -yscrollcommand "$top.ysb set" \
@@ -7057,14 +7124,14 @@ proc showrefs {} {
     grid $top.list $top.ysb -sticky nsew
     grid $top.xsb x -sticky ew
     frame $top.f
-    label $top.f.l -text "Filter: " -font uifont
+    label $top.f.l -text "[mc "Filter"]: " -font uifont
     entry $top.f.e -width 20 -textvariable reflistfilter -font uifont
     set reflistfilter "*"
     trace add variable reflistfilter write reflistfilter_change
     pack $top.f.e -side right -fill x -expand 1
     pack $top.f.l -side left
     grid $top.f - -sticky ew -pady 2
-    button $top.close -command [list destroy $top] -text "Close" \
+    button $top.close -command [list destroy $top] -text [mc "Close"] \
        -font uifont
     grid $top.close -
     grid columnconfigure $top 0 -weight 1
@@ -7352,9 +7419,9 @@ proc getallclines {fd} {
            dropcache $err
            return
        }
-       error_popup "Error reading commit topology information;\
+       error_popup "[mc "Error reading commit topology information;\
                branch and preceding/following tag information\
-               will be incomplete.\n($err)"
+               will be incomplete."]\n($err)"
        set cacheok 0
     }
     if {[incr allcommits -1] == 0} {
@@ -8336,7 +8403,7 @@ proc showtag {tag isnew} {
     if {[info exists tagcontents($tag)]} {
        set text $tagcontents($tag)
     } else {
-       set text "Tag: $tag\nId:  $tagids($tag)"
+       set text "[mc "Tag"]: $tag\n[mc "Id"]:  $tagids($tag)"
     }
     appendwithlinks $text {}
     $ctext conf -state disabled
@@ -8376,7 +8443,7 @@ proc choosefont {font which} {
        font create sample
        eval font config sample [font actual $font]
        toplevel $top
-       wm title $top "Gitk font chooser"
+       wm title $top [mc "Gitk font chooser"]
        label $top.l -textvariable fontparam(which) -font uifont
        pack $top.l -side top
        set fontlist [lsort [font families]]
@@ -8393,10 +8460,10 @@ proc choosefont {font which} {
            -textvariable fontparam(size) \
            -validatecommand {string is integer -strict %s}
        checkbutton $top.g.bold -padx 5 \
-           -font {{Times New Roman} 12 bold} -text "B" -indicatoron 0 \
+           -font {{Times New Roman} 12 bold} -text [mc "B"] -indicatoron 0 \
            -variable fontparam(weight) -onvalue bold -offvalue normal
        checkbutton $top.g.ital -padx 5 \
-           -font {{Times New Roman} 12 italic} -text "I" -indicatoron 0  \
+           -font {{Times New Roman} 12 italic} -text [mc "I"] -indicatoron 0  \
            -variable fontparam(slant) -onvalue italic -offvalue roman
        pack $top.g.size $top.g.bold $top.g.ital -side left
        pack $top.g -side top
@@ -8407,9 +8474,9 @@ proc choosefont {font which} {
        bind $top.c <Configure> [list centertext $top.c]
        pack $top.c -side top -fill x
        frame $top.buts
-       button $top.buts.ok -text "OK" -command fontok -default active \
+       button $top.buts.ok -text [mc "OK"] -command fontok -default active \
            -font uifont
-       button $top.buts.can -text "Cancel" -command fontcan -default normal \
+       button $top.buts.can -text [mc "Cancel"] -command fontcan -default normal \
            -font uifont
        grid $top.buts.ok $top.buts.can
        grid columnconfigure $top.buts 0 -weight 1 -uniform a
@@ -8491,85 +8558,85 @@ proc doprefs {} {
        set oldprefs($v) [set $v]
     }
     toplevel $top
-    wm title $top "Gitk preferences"
-    label $top.ldisp -text "Commit list display options"
+    wm title $top [mc "Gitk preferences"]
+    label $top.ldisp -text [mc "Commit list display options"]
     $top.ldisp configure -font uifont
     grid $top.ldisp - -sticky w -pady 10
     label $top.spacer -text " "
-    label $top.maxwidthl -text "Maximum graph width (lines)" \
+    label $top.maxwidthl -text [mc "Maximum graph width (lines)"] \
        -font optionfont
     spinbox $top.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
     grid $top.spacer $top.maxwidthl $top.maxwidth -sticky w
-    label $top.maxpctl -text "Maximum graph width (% of pane)" \
+    label $top.maxpctl -text [mc "Maximum graph width (% of pane)"] \
        -font optionfont
     spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
     grid x $top.maxpctl $top.maxpct -sticky w
     frame $top.showlocal
-    label $top.showlocal.l -text "Show local changes" -font optionfont
+    label $top.showlocal.l -text [mc "Show local changes"] -font optionfont
     checkbutton $top.showlocal.b -variable showlocalchanges
     pack $top.showlocal.b $top.showlocal.l -side left
     grid x $top.showlocal -sticky w
 
-    label $top.ddisp -text "Diff display options"
+    label $top.ddisp -text [mc "Diff display options"]
     $top.ddisp configure -font uifont
     grid $top.ddisp - -sticky w -pady 10
-    label $top.tabstopl -text "Tab spacing" -font optionfont
+    label $top.tabstopl -text [mc "Tab spacing"] -font optionfont
     spinbox $top.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
     grid x $top.tabstopl $top.tabstop -sticky w
     frame $top.ntag
-    label $top.ntag.l -text "Display nearby tags" -font optionfont
+    label $top.ntag.l -text [mc "Display nearby tags"] -font optionfont
     checkbutton $top.ntag.b -variable showneartags
     pack $top.ntag.b $top.ntag.l -side left
     grid x $top.ntag -sticky w
     frame $top.ldiff
-    label $top.ldiff.l -text "Limit diffs to listed paths" -font optionfont
+    label $top.ldiff.l -text [mc "Limit diffs to listed paths"] -font optionfont
     checkbutton $top.ldiff.b -variable limitdiffs
     pack $top.ldiff.b $top.ldiff.l -side left
     grid x $top.ldiff -sticky w
 
-    label $top.cdisp -text "Colors: press to choose"
+    label $top.cdisp -text [mc "Colors: press to choose"]
     $top.cdisp configure -font uifont
     grid $top.cdisp - -sticky w -pady 10
     label $top.bg -padx 40 -relief sunk -background $bgcolor
-    button $top.bgbut -text "Background" -font optionfont \
+    button $top.bgbut -text [mc "Background"] -font optionfont \
        -command [list choosecolor bgcolor 0 $top.bg background setbg]
     grid x $top.bgbut $top.bg -sticky w
     label $top.fg -padx 40 -relief sunk -background $fgcolor
-    button $top.fgbut -text "Foreground" -font optionfont \
+    button $top.fgbut -text [mc "Foreground"] -font optionfont \
        -command [list choosecolor fgcolor 0 $top.fg foreground setfg]
     grid x $top.fgbut $top.fg -sticky w
     label $top.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
-    button $top.diffoldbut -text "Diff: old lines" -font optionfont \
+    button $top.diffoldbut -text [mc "Diff: old lines"] -font optionfont \
        -command [list choosecolor diffcolors 0 $top.diffold "diff old lines" \
                      [list $ctext tag conf d0 -foreground]]
     grid x $top.diffoldbut $top.diffold -sticky w
     label $top.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
-    button $top.diffnewbut -text "Diff: new lines" -font optionfont \
+    button $top.diffnewbut -text [mc "Diff: new lines"] -font optionfont \
        -command [list choosecolor diffcolors 1 $top.diffnew "diff new lines" \
                      [list $ctext tag conf d1 -foreground]]
     grid x $top.diffnewbut $top.diffnew -sticky w
     label $top.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
-    button $top.hunksepbut -text "Diff: hunk header" -font optionfont \
+    button $top.hunksepbut -text [mc "Diff: hunk header"] -font optionfont \
        -command [list choosecolor diffcolors 2 $top.hunksep \
                      "diff hunk header" \
                      [list $ctext tag conf hunksep -foreground]]
     grid x $top.hunksepbut $top.hunksep -sticky w
     label $top.selbgsep -padx 40 -relief sunk -background $selectbgcolor
-    button $top.selbgbut -text "Select bg" -font optionfont \
+    button $top.selbgbut -text [mc "Select bg"] -font optionfont \
        -command [list choosecolor selectbgcolor 0 $top.selbgsep background setselbg]
     grid x $top.selbgbut $top.selbgsep -sticky w
 
-    label $top.cfont -text "Fonts: press to choose"
+    label $top.cfont -text [mc "Fonts: press to choose"]
     $top.cfont configure -font uifont
     grid $top.cfont - -sticky w -pady 10
-    mkfontdisp mainfont $top "Main font"
-    mkfontdisp textfont $top "Diff display font"
-    mkfontdisp uifont $top "User interface font"
+    mkfontdisp mainfont $top [mc "Main font"]
+    mkfontdisp textfont $top [mc "Diff display font"]
+    mkfontdisp uifont $top [mc "User interface font"]
 
     frame $top.buts
-    button $top.buts.ok -text "OK" -command prefsok -default active
+    button $top.buts.ok -text [mc "OK"] -command prefsok -default active
     $top.buts.ok configure -font uifont
-    button $top.buts.can -text "Cancel" -command prefscan -default normal
+    button $top.buts.can -text [mc "Cancel"] -command prefscan -default normal
     $top.buts.can configure -font uifont
     grid $top.buts.ok $top.buts.can
     grid columnconfigure $top.buts 0 -weight 1 -uniform a
@@ -8582,7 +8649,7 @@ proc choosecolor {v vi w x cmd} {
     global $v
 
     set c [tk_chooseColor -initialcolor [lindex [set $v] $vi] \
-              -title "Gitk: choose color for $x"]
+              -title [mc "Gitk: choose color for %s" $x]]
     if {$c eq {}} return
     $w conf -background $c
     lset $v $vi $c
@@ -8963,8 +9030,8 @@ proc tcl_encoding {enc} {
 
 # First check that Tcl/Tk is recent enough
 if {[catch {package require Tk 8.4} err]} {
-    show_error {} . "Sorry, gitk cannot run with this version of Tcl/Tk.\n\
-                    Gitk requires at least Tcl/Tk 8.4."
+    show_error {} . [mc "Sorry, gitk cannot run with this version of Tcl/Tk.\n\
+                    Gitk requires at least Tcl/Tk 8.4."]
     exit 1
 }
 
@@ -9012,6 +9079,25 @@ set diffcolors {red "#00a000" blue}
 set diffcontext 3
 set selectbgcolor gray85
 
+## For msgcat loading, first locate the installation location.
+if { [info exists ::env(GITK_MSGSDIR)] } {
+    ## Msgsdir was manually set in the environment.
+    set gitk_msgsdir $::env(GITK_MSGSDIR)
+} else {
+    ## Let's guess the prefix from argv0.
+    set gitk_prefix [file dirname [file dirname [file normalize $argv0]]]
+    set gitk_libdir [file join $gitk_prefix share gitk lib]
+    set gitk_msgsdir [file join $gitk_libdir msgs]
+    unset gitk_prefix
+}
+
+## Internationalization (i18n) through msgcat and gettext. See
+## http://www.gnu.org/software/gettext/manual/html_node/Tcl.html
+package require msgcat
+namespace import ::msgcat::mc
+## And eventually load the actual message catalog
+::msgcat::mcload $gitk_msgsdir
+
 catch {source ~/.gitk}
 
 font create optionfont -family sans-serif -size -12
@@ -9029,11 +9115,11 @@ eval font create uifont [fontflags uifont]
 
 # check that we can find a .git directory somewhere...
 if {[catch {set gitdir [gitdir]}]} {
-    show_error {} . "Cannot find a git repository here."
+    show_error {} . [mc "Cannot find a git repository here."]
     exit 1
 }
 if {![file isdirectory $gitdir]} {
-    show_error {} . "Cannot find the git directory \"$gitdir\"."
+    show_error {} . [mc "Cannot find the git directory \"%s\"." $gitdir]
     exit 1
 }
 
@@ -9072,8 +9158,8 @@ if {$i >= [llength $argv] && $revtreeargs ne {}} {
        # with git log and git rev-list, check revtreeargs for filenames.
        foreach arg $revtreeargs {
            if {[file exists $arg]} {
-               show_error {} . "Ambiguous argument '$arg': both revision\
-                                and filename"
+               show_error {} . [mc "Ambiguous argument '%s': both revision\
+                                and filename" $arg]
                exit 1
            }
        }
@@ -9084,7 +9170,7 @@ if {$i >= [llength $argv] && $revtreeargs ne {}} {
        if {$i > 0} {
            set err [string range $err [expr {$i + 6}] end]
        }
-       show_error {} . "Bad arguments to gitk:\n$err"
+       show_error {} . "[mc "Bad arguments to gitk:"]\n$err"
        exit 1
     }
 }
@@ -9096,7 +9182,7 @@ if {$mergeonly} {
     if {[catch {
        set fd [open "| git ls-files -u" r]
     } err]} {
-       show_error {} . "Couldn't get list of unmerged files: $err"
+       show_error {} . "[mc "Couldn't get list of unmerged files:"] $err"
        exit 1
     }
     while {[gets $fd line] >= 0} {
@@ -9112,11 +9198,11 @@ if {$mergeonly} {
     catch {close $fd}
     if {$mlist eq {}} {
        if {$nr_unmerged == 0} {
-           show_error {} . "No files selected: --merge specified but\
-                            no files are unmerged."
+           show_error {} . [mc "No files selected: --merge specified but\
+                            no files are unmerged."]
        } else {
-           show_error {} . "No files selected: --merge specified but\
-                            no unmerged files are within file limit."
+           show_error {} . [mc "No files selected: --merge specified but\
+                            no unmerged files are within file limit."]
        }
        exit 1
     }
@@ -9148,15 +9234,14 @@ set firsttabstop 0
 set nextviewnum 1
 set curview 0
 set selectedview 0
-set selectedhlview None
-set highlight_related None
+set selectedhlview [mc "None"]
+set highlight_related [mc "None"]
 set highlight_files {}
 set viewfiles(0) {}
 set viewperm(0) 0
 set viewargs(0) {}
 
 set loginstance 0
-set getdbg 0
 set cmdlineok 0
 set stopped 0
 set stuffsaved 0
@@ -9174,13 +9259,13 @@ if {$cmdline_files ne {} || $revtreeargs ne {}} {
     set curview 1
     set selectedview 1
     set nextviewnum 2
-    set viewname(1) "Command line"
+    set viewname(1) [mc "Command line"]
     set viewfiles(1) $cmdline_files
     set viewargs(1) $revtreeargs
     set viewperm(1) 0
     addviewmenu 1
-    .bar.view entryconf Edit* -state normal
-    .bar.view entryconf Delete* -state normal
+    .bar.view entryconf [mc "Edit view..."] -state normal
+    .bar.view entryconf [mc "Delete view"] -state normal
 }
 
 if {[info exists permviews]} {