sha1_to_hex: properly terminate the SHA1
[git.git] / gitk
diff --git a/gitk b/gitk
index a904bab..f12b3ce 100755 (executable)
--- a/gitk
+++ b/gitk
@@ -1,6 +1,6 @@
 #!/bin/sh
 # Tcl ignores the next line -*- tcl -*- \
 #!/bin/sh
 # Tcl ignores the next line -*- tcl -*- \
-exec wish "$0" -- "${1+$@}"
+exec wish "$0" -- "$@"
 
 # Copyright (C) 2005 Paul Mackerras.  All rights reserved.
 # This program is free software; it may be used, copied, modified
 
 # Copyright (C) 2005 Paul Mackerras.  All rights reserved.
 # This program is free software; it may be used, copied, modified
@@ -16,22 +16,9 @@ proc gitdir {} {
     }
 }
 
     }
 }
 
-proc getcommits {rargs} {
-    global commits commfd phase canv mainfont env
-    global startmsecs nextupdate ncmupdate
-    global ctext maincursor textcursor leftover
+proc parse_args {rargs} {
+    global parsed_args
 
 
-    # check that we can find a .git directory somewhere...
-    set gitdir [gitdir]
-    if {![file isdirectory $gitdir]} {
-       error_popup "Cannot find the git directory \"$gitdir\"."
-       exit 1
-    }
-    set commits {}
-    set phase getcommits
-    set startmsecs [clock clicks -milliseconds]
-    set nextupdate [expr $startmsecs + 100]
-    set ncmupdate 1
     if [catch {
        set parse_args [concat --default HEAD $rargs]
        set parsed_args [split [eval exec git-rev-parse $parse_args] "\n"]
     if [catch {
        set parse_args [concat --default HEAD $rargs]
        set parsed_args [split [eval exec git-rev-parse $parse_args] "\n"]
@@ -42,26 +29,56 @@ proc getcommits {rargs} {
        }
        set parsed_args $rargs
     }
        }
        set parsed_args $rargs
     }
+    return $parsed_args
+}
+
+proc start_rev_list {rlargs} {
+    global startmsecs nextupdate ncmupdate
+    global commfd leftover tclencoding
+
+    set startmsecs [clock clicks -milliseconds]
+    set nextupdate [expr {$startmsecs + 100}]
+    set ncmupdate 1
     if [catch {
     if [catch {
-       set commfd [open "|git-rev-list --header --topo-order --parents $parsed_args" r]
+       set commfd [open [concat | git-rev-list --header --topo-order \
+                             --parents $rlargs] r]
     } err] {
        puts stderr "Error executing git-rev-list: $err"
        exit 1
     }
     set leftover {}
     fconfigure $commfd -blocking 0 -translation lf
     } err] {
        puts stderr "Error executing git-rev-list: $err"
        exit 1
     }
     set leftover {}
     fconfigure $commfd -blocking 0 -translation lf
+    if {$tclencoding != {}} {
+       fconfigure $commfd -encoding $tclencoding
+    }
     fileevent $commfd readable [list getcommitlines $commfd]
     fileevent $commfd readable [list getcommitlines $commfd]
+    . config -cursor watch
+    settextcursor watch
+}
+
+proc getcommits {rargs} {
+    global oldcommits commits phase canv mainfont env
+
+    # check that we can find a .git directory somewhere...
+    set gitdir [gitdir]
+    if {![file isdirectory $gitdir]} {
+       error_popup "Cannot find the git directory \"$gitdir\"."
+       exit 1
+    }
+    set oldcommits {}
+    set commits {}
+    set phase getcommits
+    start_rev_list [parse_args $rargs]
     $canv delete all
     $canv create text 3 3 -anchor nw -text "Reading commits..." \
        -font $mainfont -tags textitems
     $canv delete all
     $canv create text 3 3 -anchor nw -text "Reading commits..." \
        -font $mainfont -tags textitems
-    . config -cursor watch
-    settextcursor watch
 }
 
 proc getcommitlines {commfd}  {
 }
 
 proc getcommitlines {commfd}  {
-    global commits parents cdate children
-    global commitlisted phase commitinfo nextupdate
+    global oldcommits commits parents cdate children nchildren
+    global commitlisted phase nextupdate
     global stopped redisplaying leftover
     global stopped redisplaying leftover
+    global canv
 
     set stuff [read $commfd]
     if {$stuff == {}} {
 
     set stuff [read $commfd]
     if {$stuff == {}} {
@@ -74,9 +91,9 @@ proc getcommitlines {commfd}  {
        }
        if {[string range $err 0 4] == "usage"} {
            set err \
        }
        if {[string range $err 0 4] == "usage"} {
            set err \
-{Gitk: error reading commits: bad arguments to git-rev-list.
-(Note: arguments to gitk are passed to git-rev-list
-to allow selection of commits to be displayed.)}
+               "Gitk: error reading commits: bad arguments to git-rev-list.\
+               (Note: arguments to gitk are passed to git-rev-list\
+               to allow selection of commits to be displayed.)"
        } else {
            set err "Error reading commits: $err"
        }
        } else {
            set err "Error reading commits: $err"
        }
@@ -122,7 +139,7 @@ to allow selection of commits to be displayed.)}
        lappend commits $id
        set commitlisted($id) 1
        parsecommit $id $cmit 1 [lrange $ids 1 end]
        lappend commits $id
        set commitlisted($id) 1
        parsecommit $id $cmit 1 [lrange $ids 1 end]
-       drawcommit $id
+       drawcommit $id 1
        if {[clock clicks -milliseconds] >= $nextupdate} {
            doupdate 1
        }
        if {[clock clicks -milliseconds] >= $nextupdate} {
            doupdate 1
        }
@@ -132,7 +149,7 @@ to allow selection of commits to be displayed.)}
                set stopped 0
                set phase "getcommits"
                foreach id $commits {
                set stopped 0
                set phase "getcommits"
                foreach id $commits {
-                   drawcommit $id
+                   drawcommit $id 1
                    if {$stopped} break
                    if {[clock clicks -milliseconds] >= $nextupdate} {
                        doupdate 1
                    if {$stopped} break
                    if {[clock clicks -milliseconds] >= $nextupdate} {
                        doupdate 1
@@ -168,16 +185,99 @@ proc readcommit {id} {
     parsecommit $id $contents 0 {}
 }
 
     parsecommit $id $contents 0 {}
 }
 
-proc parsecommit {id contents listed olds} {
-    global commitinfo children nchildren parents nparents cdate ncleft
+proc updatecommits {rargs} {
+    global commitlisted commfd phase
+    global startmsecs nextupdate ncmupdate
+    global idtags idheads idotherrefs
+    global leftover
+    global parsed_args
+    global canv mainfont
+    global oldcommits commits
+    global parents nchildren children ncleft
+
+    set old_args $parsed_args
+    parse_args $rargs
+
+    if {$phase == "getcommits" || $phase == "incrdraw"} {
+       # havent read all the old commits, just start again from scratch
+       stopfindproc
+       set oldcommits {}
+       set commits {}
+       foreach v {children nchildren parents commitlisted commitinfo
+                  selectedline matchinglines treediffs
+                  mergefilelist currentid rowtextx} {
+           global $v
+           catch {unset $v}
+       }
+       readrefs
+       if {$phase == "incrdraw"} {
+           allcanvs delete all
+           $canv create text 3 3 -anchor nw -text "Reading commits..." \
+               -font $mainfont -tags textitems
+           set phase getcommits
+       }
+       start_rev_list $parsed_args
+       return
+    }
+
+    foreach id $old_args {
+       if {![regexp {^[0-9a-f]{40}$} $id]} continue
+       if {[info exists oldref($id)]} continue
+       set oldref($id) $id
+       lappend ignoreold "^$id"
+    }
+    foreach id $parsed_args {
+       if {![regexp {^[0-9a-f]{40}$} $id]} continue
+       if {[info exists ref($id)]} continue
+       set ref($id) $id
+       lappend ignorenew "^$id"
+    }
+
+    foreach a $old_args {
+       if {![info exists ref($a)]} {
+           lappend ignorenew $a
+       }
+    }
+
+    set phase updatecommits
+    set oldcommits $commits
+    set commits {}
+    set removed_commits [split [eval exec git-rev-list $ignorenew] "\n" ]
+    if {[llength $removed_commits] > 0} {
+       allcanvs delete all
+       foreach c $removed_commits {
+           set i [lsearch -exact $oldcommits $c]
+           if {$i >= 0} {
+               set oldcommits [lreplace $oldcommits $i $i]
+               unset commitlisted($c)
+               foreach p $parents($c) {
+                   if {[info exists nchildren($p)]} {
+                       set j [lsearch -exact $children($p) $c]
+                       if {$j >= 0} {
+                           set children($p) [lreplace $children($p) $j $j]
+                           incr nchildren($p) -1
+                       }
+                   }
+               }
+           }
+       }
+       set phase removecommits
+    }
+
+    set args {}
+    foreach a $parsed_args {
+       if {![info exists oldref($a)]} {
+           lappend args $a
+       }
+    }
+
+    readrefs
+    start_rev_list [concat $ignoreold $args]
+}
+
+proc updatechildren {id olds} {
+    global children nchildren parents nparents ncleft
 
 
-    set inhdr 1
-    set comment {}
-    set headline {}
-    set auname {}
-    set audate {}
-    set comname {}
-    set comdate {}
     if {![info exists nchildren($id)]} {
        set children($id) {}
        set nchildren($id) 0
     if {![info exists nchildren($id)]} {
        set children($id) {}
        set nchildren($id) 0
@@ -196,42 +296,57 @@ proc parsecommit {id contents listed olds} {
            incr ncleft($p)
        }
     }
            incr ncleft($p)
        }
     }
-    foreach line [split $contents "\n"] {
-       if {$inhdr} {
-           if {$line == {}} {
-               set inhdr 0
-           } else {
-               set tag [lindex $line 0]
-               if {$tag == "author"} {
-                   set x [expr {[llength $line] - 2}]
-                   set audate [lindex $line $x]
-                   set auname [lrange $line 1 [expr {$x - 1}]]
-               } elseif {$tag == "committer"} {
-                   set x [expr {[llength $line] - 2}]
-                   set comdate [lindex $line $x]
-                   set comname [lrange $line 1 [expr {$x - 1}]]
-               }
-           }
-       } else {
-           if {$comment == {}} {
-               set headline [string trim $line]
-           } else {
-               append comment "\n"
-           }
-           if {!$listed} {
-               # git-rev-list indents the comment by 4 spaces;
-               # if we got this via git-cat-file, add the indentation
-               append comment "    "
-           }
-           append comment $line
+}
+
+proc parsecommit {id contents listed olds} {
+    global commitinfo cdate
+
+    set inhdr 1
+    set comment {}
+    set headline {}
+    set auname {}
+    set audate {}
+    set comname {}
+    set comdate {}
+    updatechildren $id $olds
+    set hdrend [string first "\n\n" $contents]
+    if {$hdrend < 0} {
+       # should never happen...
+       set hdrend [string length $contents]
+    }
+    set header [string range $contents 0 [expr {$hdrend - 1}]]
+    set comment [string range $contents [expr {$hdrend + 2}] end]
+    foreach line [split $header "\n"] {
+       set tag [lindex $line 0]
+       if {$tag == "author"} {
+           set audate [lindex $line end-1]
+           set auname [lrange $line 1 end-2]
+       } elseif {$tag == "committer"} {
+           set comdate [lindex $line end-1]
+           set comname [lrange $line 1 end-2]
        }
     }
        }
     }
-    if {$audate != {}} {
-       set audate [clock format $audate -format "%Y-%m-%d %H:%M:%S"]
+    set headline {}
+    # take the first line of the comment as the headline
+    set i [string first "\n" $comment]
+    if {$i >= 0} {
+       set headline [string trim [string range $comment 0 $i]]
+    } else {
+       set headline $comment
+    }
+    if {!$listed} {
+       # git-rev-list indents the comment by 4 spaces;
+       # if we got this via git-cat-file, add the indentation
+       set newcomment {}
+       foreach line [split $comment "\n"] {
+           append newcomment "    "
+           append newcomment $line
+           append newcomment "\n"
+       }
+       set comment $newcomment
     }
     if {$comdate != {}} {
        set cdate($id) $comdate
     }
     if {$comdate != {}} {
        set cdate($id) $comdate
-       set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"]
     }
     set commitinfo($id) [list $headline $auname $audate \
                             $comname $comdate $comment]
     }
     set commitinfo($id) [list $headline $auname $audate \
                             $comname $comdate $comment]
@@ -239,77 +354,46 @@ proc parsecommit {id contents listed olds} {
 
 proc readrefs {} {
     global tagids idtags headids idheads tagcontents
 
 proc readrefs {} {
     global tagids idtags headids idheads tagcontents
+    global otherrefids idotherrefs
 
 
-    set tags [glob -nocomplain -types f [gitdir]/refs/tags/*]
-    foreach f $tags {
-       catch {
-           set fd [open $f r]
-           set line [read $fd]
-           if {[regexp {^[0-9a-f]{40}} $line id]} {
-               set direct [file tail $f]
-               set tagids($direct) $id
-               lappend idtags($id) $direct
-               set tagblob [exec git-cat-file tag $id]
-               set contents [split $tagblob "\n"]
-               set obj {}
-               set type {}
-               set tag {}
-               foreach l $contents {
-                   if {$l == {}} break
-                   switch -- [lindex $l 0] {
-                       "object" {set obj [lindex $l 1]}
-                       "type" {set type [lindex $l 1]}
-                       "tag" {set tag [string range $l 4 end]}
-                   }
-               }
-               if {$obj != {} && $type == "commit" && $tag != {}} {
-                   set tagids($tag) $obj
-                   lappend idtags($obj) $tag
-                   set tagcontents($tag) $tagblob
-               }
-           }
-           close $fd
-       }
+    foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
+       catch {unset $v}
     }
     }
-    set heads [glob -nocomplain -types f [gitdir]/refs/heads/*]
-    foreach f $heads {
-       catch {
-           set fd [open $f r]
-           set line [read $fd 40]
-           if {[regexp {^[0-9a-f]{40}} $line id]} {
-               set head [file tail $f]
-               set headids($head) $line
-               lappend idheads($line) $head
-           }
-           close $fd
+    set refd [open [list | git-ls-remote [gitdir]] r]
+    while {0 <= [set n [gets $refd line]]} {
+       if {![regexp {^([0-9a-f]{40})   refs/([^^]*)$} $line \
+           match id path]} {
+           continue
        }
        }
-    }
-    readotherrefs refs {} {tags heads}
-}
-
-proc readotherrefs {base dname excl} {
-    global otherrefids idotherrefs
-
-    set git [gitdir]
-    set files [glob -nocomplain -types f [file join $git $base *]]
-    foreach f $files {
-       catch {
-           set fd [open $f r]
-           set line [read $fd 40]
-           if {[regexp {^[0-9a-f]{40}} $line id]} {
-               set name "$dname[file tail $f]"
-               set otherrefids($name) $id
-               lappend idotherrefs($id) $name
+       if {![regexp {^(tags|heads)/(.*)$} $path match type name]} {
+           set type others
+           set name $path
+       }
+       if {$type == "tags"} {
+           set tagids($name) $id
+           lappend idtags($id) $name
+           set obj {}
+           set type {}
+           set tag {}
+           catch {
+               set commit [exec git-rev-parse "$id^0"]
+               if {"$commit" != "$id"} {
+                   set tagids($name) $commit
+                   lappend idtags($commit) $name
+               }
+           }           
+           catch {
+               set tagcontents($name) [exec git-cat-file tag "$id"]
            }
            }
-           close $fd
+       } elseif { $type == "heads" } {
+           set headids($name) $id
+           lappend idheads($id) $name
+       } else {
+           set otherrefids($name) $id
+           lappend idotherrefs($id) $name
        }
     }
        }
     }
-    set dirs [glob -nocomplain -types d [file join $git $base *]]
-    foreach d $dirs {
-       set dir [file tail $d]
-       if {[lsearch -exact $excl $dir] >= 0} continue
-       readotherrefs [file join $base $dir] "$dname$dir/" {}
-    }
+    close $refd
 }
 
 proc error_popup msg {
 }
 
 proc error_popup msg {
@@ -324,28 +408,32 @@ proc error_popup msg {
     tkwait window $w
 }
 
     tkwait window $w
 }
 
-proc makewindow {} {
+proc makewindow {rargs} {
     global canv canv2 canv3 linespc charspc ctext cflist textfont
     global findtype findtypemenu findloc findstring fstring geometry
     global entries sha1entry sha1string sha1but
     global maincursor textcursor curtextcursor
     global canv canv2 canv3 linespc charspc ctext cflist textfont
     global findtype findtypemenu findloc findstring fstring geometry
     global entries sha1entry sha1string sha1but
     global maincursor textcursor curtextcursor
-    global rowctxmenu gaudydiff mergemax
+    global rowctxmenu mergemax
 
     menu .bar
     .bar add cascade -label "File" -menu .bar.file
     menu .bar.file
 
     menu .bar
     .bar add cascade -label "File" -menu .bar.file
     menu .bar.file
+    .bar.file add command -label "Update" -command [list updatecommits $rargs]
     .bar.file add command -label "Reread references" -command rereadrefs
     .bar.file add command -label "Quit" -command doquit
     .bar.file add command -label "Reread references" -command rereadrefs
     .bar.file add command -label "Quit" -command doquit
+    menu .bar.edit
+    .bar add cascade -label "Edit" -menu .bar.edit
+    .bar.edit add command -label "Preferences" -command doprefs
     menu .bar.help
     .bar add cascade -label "Help" -menu .bar.help
     .bar.help add command -label "About gitk" -command about
     . configure -menu .bar
 
     if {![info exists geometry(canv1)]} {
     menu .bar.help
     .bar add cascade -label "Help" -menu .bar.help
     .bar.help add command -label "About gitk" -command about
     . configure -menu .bar
 
     if {![info exists geometry(canv1)]} {
-       set geometry(canv1) [expr 45 * $charspc]
-       set geometry(canv2) [expr 30 * $charspc]
-       set geometry(canv3) [expr 15 * $charspc]
-       set geometry(canvh) [expr 25 * $linespc + 4]
+       set geometry(canv1) [expr {45 * $charspc}]
+       set geometry(canv2) [expr {30 * $charspc}]
+       set geometry(canv3) [expr {15 * $charspc}]
+       set geometry(canvh) [expr {25 * $linespc + 4}]
        set geometry(ctextw) 80
        set geometry(ctexth) 30
        set geometry(cflistw) 30
        set geometry(ctextw) 80
        set geometry(ctexth) 30
        set geometry(cflistw) 30
@@ -446,25 +534,19 @@ proc makewindow {} {
     .ctop.cdet add .ctop.cdet.left
 
     $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
     .ctop.cdet add .ctop.cdet.left
 
     $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
-    if {$gaudydiff} {
-       $ctext tag conf hunksep -back blue -fore white
-       $ctext tag conf d0 -back "#ff8080"
-       $ctext tag conf d1 -back green
-    } else {
-       $ctext tag conf hunksep -fore blue
-       $ctext tag conf d0 -fore red
-       $ctext tag conf d1 -fore "#00a000"
-       $ctext tag conf m0 -fore red
-       $ctext tag conf m1 -fore blue
-       $ctext tag conf m2 -fore green
-       $ctext tag conf m3 -fore purple
-       $ctext tag conf m4 -fore brown
-       $ctext tag conf mmax -fore darkgrey
-       set mergemax 5
-       $ctext tag conf mresult -font [concat $textfont bold]
-       $ctext tag conf msep -font [concat $textfont bold]
-       $ctext tag conf found -back yellow
-    }
+    $ctext tag conf hunksep -fore blue
+    $ctext tag conf d0 -fore red
+    $ctext tag conf d1 -fore "#00a000"
+    $ctext tag conf m0 -fore red
+    $ctext tag conf m1 -fore blue
+    $ctext tag conf m2 -fore green
+    $ctext tag conf m3 -fore purple
+    $ctext tag conf m4 -fore brown
+    $ctext tag conf mmax -fore darkgrey
+    set mergemax 5
+    $ctext tag conf mresult -font [concat $textfont bold]
+    $ctext tag conf msep -font [concat $textfont bold]
+    $ctext tag conf found -back yellow
 
     frame .ctop.cdet.right
     set cflist .ctop.cdet.right.cfiles
 
     frame .ctop.cdet.right
     set cflist .ctop.cdet.right.cfiles
@@ -486,6 +568,8 @@ proc makewindow {} {
     bindall <B2-Motion> "allcanvs scan dragto 0 %y"
     bind . <Key-Up> "selnextline -1"
     bind . <Key-Down> "selnextline 1"
     bindall <B2-Motion> "allcanvs scan dragto 0 %y"
     bind . <Key-Up> "selnextline -1"
     bind . <Key-Down> "selnextline 1"
+    bind . <Key-Right> "goforw"
+    bind . <Key-Left> "goback"
     bind . <Key-Prior> "allcanvs yview scroll -1 pages"
     bind . <Key-Next> "allcanvs yview scroll 1 pages"
     bindkey <Key-Delete> "$ctext yview scroll -1 pages"
     bind . <Key-Prior> "allcanvs yview scroll -1 pages"
     bind . <Key-Next> "allcanvs yview scroll 1 pages"
     bindkey <Key-Delete> "$ctext yview scroll -1 pages"
@@ -493,6 +577,12 @@ proc makewindow {} {
     bindkey <Key-space> "$ctext yview scroll 1 pages"
     bindkey p "selnextline -1"
     bindkey n "selnextline 1"
     bindkey <Key-space> "$ctext yview scroll 1 pages"
     bindkey p "selnextline -1"
     bindkey n "selnextline 1"
+    bindkey z "goback"
+    bindkey x "goforw"
+    bindkey i "selnextline -1"
+    bindkey k "selnextline 1"
+    bindkey j "goback"
+    bindkey l "goforw"
     bindkey b "$ctext yview scroll -1 pages"
     bindkey d "$ctext yview scroll 18 units"
     bindkey u "$ctext yview scroll -18 units"
     bindkey b "$ctext yview scroll -1 pages"
     bindkey d "$ctext yview scroll 18 units"
     bindkey u "$ctext yview scroll -18 units"
@@ -557,7 +647,7 @@ proc click {w} {
 
 proc savestuff {w} {
     global canv canv2 canv3 ctext cflist mainfont textfont
 
 proc savestuff {w} {
     global canv canv2 canv3 ctext cflist mainfont textfont
-    global stuffsaved findmergefiles gaudydiff maxgraphpct
+    global stuffsaved findmergefiles maxgraphpct
     global maxwidth
 
     if {$stuffsaved} return
     global maxwidth
 
     if {$stuffsaved} return
@@ -567,15 +657,14 @@ proc savestuff {w} {
        puts $f [list set mainfont $mainfont]
        puts $f [list set textfont $textfont]
        puts $f [list set findmergefiles $findmergefiles]
        puts $f [list set mainfont $mainfont]
        puts $f [list set textfont $textfont]
        puts $f [list set findmergefiles $findmergefiles]
-       puts $f [list set gaudydiff $gaudydiff]
        puts $f [list set maxgraphpct $maxgraphpct]
        puts $f [list set maxwidth $maxwidth]
        puts $f "set geometry(width) [winfo width .ctop]"
        puts $f "set geometry(height) [winfo height .ctop]"
        puts $f [list set maxgraphpct $maxgraphpct]
        puts $f [list set maxwidth $maxwidth]
        puts $f "set geometry(width) [winfo width .ctop]"
        puts $f "set geometry(height) [winfo height .ctop]"
-       puts $f "set geometry(canv1) [expr [winfo width $canv]-2]"
-       puts $f "set geometry(canv2) [expr [winfo width $canv2]-2]"
-       puts $f "set geometry(canv3) [expr [winfo width $canv3]-2]"
-       puts $f "set geometry(canvh) [expr [winfo height $canv]-2]"
+       puts $f "set geometry(canv1) [expr {[winfo width $canv]-2}]"
+       puts $f "set geometry(canv2) [expr {[winfo width $canv2]-2}]"
+       puts $f "set geometry(canv3) [expr {[winfo width $canv3]-2}]"
+       puts $f "set geometry(canvh) [expr {[winfo height $canv]-2}]"
        set wid [expr {([winfo width $ctext] - 8) \
                           / [font measure $textfont "0"]}]
        puts $f "set geometry(ctextw) $wid"
        set wid [expr {([winfo width $ctext] - 8) \
                           / [font measure $textfont "0"]}]
        puts $f "set geometry(ctextw) $wid"
@@ -604,12 +693,12 @@ proc resizeclistpanes {win w} {
                set sash0 30
            }
            if {$sash1 < $sash0 + 20} {
                set sash0 30
            }
            if {$sash1 < $sash0 + 20} {
-               set sash1 [expr $sash0 + 20]
+               set sash1 [expr {$sash0 + 20}]
            }
            if {$sash1 > $w - 10} {
            }
            if {$sash1 > $w - 10} {
-               set sash1 [expr $w - 10]
+               set sash1 [expr {$w - 10}]
                if {$sash0 > $sash1 - 20} {
                if {$sash0 > $sash1 - 20} {
-                   set sash0 [expr $sash1 - 20]
+                   set sash0 [expr {$sash1 - 20}]
                }
            }
        }
                }
            }
        }
@@ -632,7 +721,7 @@ proc resizecdetpanes {win w} {
                set sash0 45
            }
            if {$sash0 > $w - 15} {
                set sash0 45
            }
            if {$sash0 > $w - 15} {
-               set sash0 [expr $w - 15]
+               set sash0 [expr {$w - 15}]
            }
        }
        $win sash place 0 $sash0 [lindex $s0 1]
            }
        }
        $win sash place 0 $sash0 [lindex $s0 1]
@@ -675,7 +764,7 @@ Use and redistribute under the terms of the GNU General Public License} \
 }
 
 proc assigncolor {id} {
 }
 
 proc assigncolor {id} {
-    global commitinfo colormap commcolors colors nextcolor
+    global colormap commcolors colors nextcolor
     global parents nparents children nchildren
     global cornercrossings crossings
 
     global parents nparents children nchildren
     global cornercrossings crossings
 
@@ -747,7 +836,6 @@ proc assigncolor {id} {
 
 proc initgraph {} {
     global canvy canvy0 lineno numcommits nextcolor linespc
 
 proc initgraph {} {
     global canvy canvy0 lineno numcommits nextcolor linespc
-    global mainline mainlinearrow sidelines
     global nchildren ncleft
     global displist nhyperspace
 
     global nchildren ncleft
     global displist nhyperspace
 
@@ -756,9 +844,11 @@ proc initgraph {} {
     set canvy $canvy0
     set lineno -1
     set numcommits 0
     set canvy $canvy0
     set lineno -1
     set numcommits 0
-    catch {unset mainline}
-    catch {unset mainlinearrow}
-    catch {unset sidelines}
+    foreach v {mainline mainlinearrow sidelines colormap cornercrossings
+               crossings idline lineid} {
+       global $v
+       catch {unset $v}
+    }
     foreach id [array names nchildren] {
        set ncleft($id) $nchildren($id)
     }
     foreach id [array names nchildren] {
        set ncleft($id) $nchildren($id)
     }
@@ -775,6 +865,34 @@ proc bindline {t id} {
     $canv bind $t <Button-1> "lineclick %x %y $id 1"
 }
 
     $canv bind $t <Button-1> "lineclick %x %y $id 1"
 }
 
+proc drawlines {id xtra delold} {
+    global mainline mainlinearrow sidelines lthickness colormap canv
+
+    if {$delold} {
+       $canv delete lines.$id
+    }
+    if {[info exists mainline($id)]} {
+       set t [$canv create line $mainline($id) \
+                  -width [expr {($xtra + 1) * $lthickness}] \
+                  -fill $colormap($id) -tags lines.$id \
+                  -arrow $mainlinearrow($id)]
+       $canv lower $t
+       bindline $t $id
+    }
+    if {[info exists sidelines($id)]} {
+       foreach ls $sidelines($id) {
+           set coords [lindex $ls 0]
+           set thick [lindex $ls 1]
+           set arrow [lindex $ls 2]
+           set t [$canv create line $coords -fill $colormap($id) \
+                      -width [expr {($thick + $xtra) * $lthickness}] \
+                      -arrow $arrow -tags lines.$id]
+           $canv lower $t
+           bindline $t $id
+       }
+    }
+}
+
 # level here is an index in displist
 proc drawcommitline {level} {
     global parents children nparents displist
 # level here is an index in displist
 proc drawcommitline {level} {
     global parents children nparents displist
@@ -815,34 +933,19 @@ proc drawcommitline {level} {
     }
     set x [xcoord $level $level $lineno]
     set y1 $canvy
     }
     set x [xcoord $level $level $lineno]
     set y1 $canvy
-    set canvy [expr $canvy + $linespc]
+    set canvy [expr {$canvy + $linespc}]
     allcanvs conf -scrollregion \
     allcanvs conf -scrollregion \
-       [list 0 0 0 [expr $y1 + 0.5 * $linespc + 2]]
+       [list 0 0 0 [expr {$y1 + 0.5 * $linespc + 2}]]
     if {[info exists mainline($id)]} {
        lappend mainline($id) $x $y1
        if {$mainlinearrow($id) ne "none"} {
            set mainline($id) [trimdiagstart $mainline($id)]
        }
     if {[info exists mainline($id)]} {
        lappend mainline($id) $x $y1
        if {$mainlinearrow($id) ne "none"} {
            set mainline($id) [trimdiagstart $mainline($id)]
        }
-       set t [$canv create line $mainline($id) \
-                  -width $lthickness -fill $colormap($id) \
-                  -arrow $mainlinearrow($id)]
-       $canv lower $t
-       bindline $t $id
-    }
-    if {[info exists sidelines($id)]} {
-       foreach ls $sidelines($id) {
-           set coords [lindex $ls 0]
-           set thick [lindex $ls 1]
-           set arrow [lindex $ls 2]
-           set t [$canv create line $coords -fill $colormap($id) \
-                      -width [expr {$thick * $lthickness}] -arrow $arrow]
-           $canv lower $t
-           bindline $t $id
-       }
     }
     }
+    drawlines $id 0 0
     set orad [expr {$linespc / 3}]
     set orad [expr {$linespc / 3}]
-    set t [$canv create oval [expr $x - $orad] [expr $y1 - $orad] \
-              [expr $x + $orad - 1] [expr $y1 + $orad - 1] \
+    set t [$canv create oval [expr {$x - $orad}] [expr {$y1 - $orad}] \
+              [expr {$x + $orad - 1}] [expr {$y1 + $orad - 1}] \
               -fill $ofill -outline black -width 1]
     $canv raise $t
     $canv bind $t <1> {selcanvline {} %x %y}
               -fill $ofill -outline black -width 1]
     $canv raise $t
     $canv bind $t <1> {selcanvline {} %x %y}
@@ -859,6 +962,7 @@ proc drawcommitline {level} {
     set headline [lindex $commitinfo($id) 0]
     set name [lindex $commitinfo($id) 1]
     set date [lindex $commitinfo($id) 2]
     set headline [lindex $commitinfo($id) 0]
     set name [lindex $commitinfo($id) 1]
     set date [lindex $commitinfo($id) 2]
+    set date [formatdate $date]
     set linehtag($lineno) [$canv create text $xt $y1 -anchor w \
                               -text $headline -font $mainfont ]
     $canv bind $linehtag($lineno) <Button-3> "rowmenu %X %Y $id"
     set linehtag($lineno) [$canv create text $xt $y1 -anchor w \
                               -text $headline -font $mainfont ]
     $canv bind $linehtag($lineno) <Button-3> "rowmenu %X %Y $id"
@@ -896,8 +1000,8 @@ proc drawtags {id x xt y1} {
     }
 
     set delta [expr {int(0.5 * ($linespc - $lthickness))}]
     }
 
     set delta [expr {int(0.5 * ($linespc - $lthickness))}]
-    set yt [expr $y1 - 0.5 * $linespc]
-    set yb [expr $yt + $linespc - 1]
+    set yt [expr {$y1 - 0.5 * $linespc}]
+    set yb [expr {$yt + $linespc - 1}]
     set xvals {}
     set wvals {}
     foreach tag $marks {
     set xvals {}
     set wvals {}
     foreach tag $marks {
@@ -910,12 +1014,12 @@ proc drawtags {id x xt y1} {
               -width $lthickness -fill black -tags tag.$id]
     $canv lower $t
     foreach tag $marks x $xvals wid $wvals {
               -width $lthickness -fill black -tags tag.$id]
     $canv lower $t
     foreach tag $marks x $xvals wid $wvals {
-       set xl [expr $x + $delta]
-       set xr [expr $x + $delta + $wid + $lthickness]
+       set xl [expr {$x + $delta}]
+       set xr [expr {$x + $delta + $wid + $lthickness}]
        if {[incr ntags -1] >= 0} {
            # draw a tag
        if {[incr ntags -1] >= 0} {
            # draw a tag
-           set t [$canv create polygon $x [expr $yt + $delta] $xl $yt \
-                      $xr $yt $xr $yb $xl $yb $x [expr $yb - $delta] \
+           set t [$canv create polygon $x [expr {$yt + $delta}] $xl $yt \
+                      $xr $yt $xr $yb $xl $yb $x [expr {$yb - $delta}] \
                       -width 1 -outline black -fill yellow -tags tag.$id]
            $canv bind $t <1> [list showtag $tag 1]
            set rowtextx($idline($id)) [expr {$xr + $linespc}]
                       -width 1 -outline black -fill yellow -tags tag.$id]
            $canv bind $t <1> [list showtag $tag 1]
            set rowtextx($idline($id)) [expr {$xr + $linespc}]
@@ -926,7 +1030,7 @@ proc drawtags {id x xt y1} {
            } else {
                set col "#ddddff"
            }
            } else {
                set col "#ddddff"
            }
-           set xl [expr $xl - $delta/2]
+           set xl [expr {$xl - $delta/2}]
            $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
                -width 1 -outline black -fill $col -tags tag.$id
        }
            $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
                -width 1 -outline black -fill $col -tags tag.$id
        }
@@ -1413,62 +1517,75 @@ proc decidenext {{noread 0}} {
            }
        }
     }
            }
        }
     }
-    if {$level < 0} {
-       if {$todo != {}} {
-           puts "ERROR: none of the pending commits can be done yet:"
-           foreach p $todo {
-               puts "  $p ($ncleft($p))"
-           }
-       }
-       return -1
-    }
 
     return $level
 }
 
 
     return $level
 }
 
-proc drawcommit {id} {
-    global phase todo nchildren datemode nextupdate
-    global numcommits ncmupdate displayorder todo onscreen
+proc drawcommit {id reading} {
+    global phase todo nchildren datemode nextupdate revlistorder ncleft
+    global numcommits ncmupdate displayorder todo onscreen parents
+    global commitlisted commitordered
 
     if {$phase != "incrdraw"} {
        set phase incrdraw
        set displayorder {}
        set todo {}
        initgraph
 
     if {$phase != "incrdraw"} {
        set phase incrdraw
        set displayorder {}
        set todo {}
        initgraph
+       catch {unset commitordered}
     }
     }
+    set commitordered($id) 1
     if {$nchildren($id) == 0} {
        lappend todo $id
        set onscreen($id) 0
     }
     if {$nchildren($id) == 0} {
        lappend todo $id
        set onscreen($id) 0
     }
-    set level [decidenext 1]
-    if {$level == {} || $id != [lindex $todo $level]} {
-       return
-    }
-    while 1 {
-       lappend displayorder [lindex $todo $level]
-       if {[updatetodo $level $datemode]} {
-           set level [decidenext 1]
-           if {$level == {}} break
+    if {$revlistorder} {
+       set level [lsearch -exact $todo $id]
+       if {$level < 0} {
+           error_popup "oops, $id isn't in todo"
+           return
        }
        }
-       set id [lindex $todo $level]
-       if {![info exists commitlisted($id)]} {
-           break
+       lappend displayorder $id
+       updatetodo $level 0
+    } else {
+       set level [decidenext 1]
+       if {$level == {} || $level < 0} return
+       while 1 {
+           set id [lindex $todo $level]
+           if {![info exists commitordered($id)]} {
+               break
+           }
+           lappend displayorder [lindex $todo $level]
+           if {[updatetodo $level $datemode]} {
+               set level [decidenext 1]
+               if {$level == {} || $level < 0} break
+           }
        }
     }
        }
     }
-    drawmore 1
+    drawmore $reading
 }
 
 proc finishcommits {} {
 }
 
 proc finishcommits {} {
-    global phase
+    global phase oldcommits commits
     global canv mainfont ctext maincursor textcursor
     global canv mainfont ctext maincursor textcursor
+    global parents displayorder todo
 
 
-    if {$phase != "incrdraw"} {
+    if {$phase == "incrdraw" || $phase == "removecommits"} {
+       foreach id $oldcommits {
+           lappend commits $id
+           drawcommit $id 0
+       }
+       set oldcommits {}
+       drawrest
+    } elseif {$phase == "updatecommits"} {
+       # there were no new commits, in fact
+       set commits $oldcommits
+       set oldcommits {}
+       set phase {}
+    } else {
        $canv delete all
        $canv create text 3 3 -anchor nw -text "No commits selected" \
            -font $mainfont -tags textitems
        set phase {}
        $canv delete all
        $canv create text 3 3 -anchor nw -text "No commits selected" \
            -font $mainfont -tags textitems
        set phase {}
-    } else {
-       drawrest
     }
     . config -cursor $maincursor
     settextcursor $textcursor
     }
     . config -cursor $maincursor
     settextcursor $textcursor
@@ -1491,7 +1608,7 @@ proc drawgraph {} {
 
     if {$displayorder == {}} return
     set startmsecs [clock clicks -milliseconds]
 
     if {$displayorder == {}} return
     set startmsecs [clock clicks -milliseconds]
-    set nextupdate [expr $startmsecs + 100]
+    set nextupdate [expr {$startmsecs + 100}]
     set ncmupdate 1
     initgraph
     foreach id $displayorder {
     set ncmupdate 1
     initgraph
     foreach id $displayorder {
@@ -1502,9 +1619,9 @@ proc drawgraph {} {
 
 proc drawrest {} {
     global phase stopped redisplaying selectedline
 
 proc drawrest {} {
     global phase stopped redisplaying selectedline
-    global datemode todo displayorder
+    global datemode todo displayorder ncleft
     global numcommits ncmupdate
     global numcommits ncmupdate
-    global nextupdate startmsecs
+    global nextupdate startmsecs revlistorder
 
     set level [decidenext]
     if {$level >= 0} {
 
     set level [decidenext]
     if {$level >= 0} {
@@ -1517,10 +1634,17 @@ proc drawrest {} {
                if {$level < 0} break
            }
        }
                if {$level < 0} break
            }
        }
-       drawmore 0
     }
     }
+    if {$todo != {}} {
+       puts "ERROR: none of the pending commits can be done yet:"
+       foreach p $todo {
+           puts "  $p ($ncleft($p))"
+       }
+    }
+
+    drawmore 0
     set phase {}
     set phase {}
-    set drawmsecs [expr [clock clicks -milliseconds] - $startmsecs]
+    set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}]
     #puts "overall $drawmsecs ms for $numcommits commits"
     if {$redisplaying} {
        if {$stopped == 0 && [info exists selectedline]} {
     #puts "overall $drawmsecs ms for $numcommits commits"
     if {$redisplaying} {
        if {$stopped == 0 && [info exists selectedline]} {
@@ -1548,8 +1672,8 @@ proc findmatches {f} {
        set matches {}
        set i 0
        while {[set j [string first $foundstring $str $i]] >= 0} {
        set matches {}
        set i 0
        while {[set j [string first $foundstring $str $i]] >= 0} {
-           lappend matches [list $j [expr $j+$foundstrlen-1]]
-           set i [expr $j + $foundstrlen]
+           lappend matches [list $j [expr {$j+$foundstrlen-1}]]
+           set i [expr {$j + $foundstrlen}]
        }
     }
     return $matches
        }
     }
     return $matches
@@ -1630,7 +1754,7 @@ proc findselectline {l} {
        set matches [findmatches $f]
        foreach match $matches {
            set start [lindex $match 0]
        set matches [findmatches $f]
        foreach match $matches {
            set start [lindex $match 0]
-           set end [expr [lindex $match 1] + 1]
+           set end [expr {[lindex $match 1] + 1}]
            $ctext tag add found "1.0 + $start c" "1.0 + $end c"
        }
     }
            $ctext tag add found "1.0 + $start c" "1.0 + $end c"
        }
     }
@@ -1984,9 +2108,10 @@ proc markmatches {canv l str tag matches font} {
        set start [lindex $match 0]
        set end [lindex $match 1]
        if {$start > $end} continue
        set start [lindex $match 0]
        set end [lindex $match 1]
        if {$start > $end} continue
-       set xoff [font measure $font [string range $str 0 [expr $start-1]]]
-       set xlen [font measure $font [string range $str 0 [expr $end]]]
-       set t [$canv create rect [expr $x0+$xoff] $y0 [expr $x0+$xlen+2] $y1 \
+       set xoff [font measure $font [string range $str 0 [expr {$start-1}]]]
+       set xlen [font measure $font [string range $str 0 [expr {$end}]]]
+       set t [$canv create rect [expr {$x0+$xoff}] $y0 \
+                  [expr {$x0+$xlen+2}] $y1 \
                   -outline {} -tags matches -fill yellow]
        $canv lower $t
     }
                   -outline {} -tags matches -fill yellow]
        $canv lower $t
     }
@@ -2059,6 +2184,7 @@ proc selectline {l isnew} {
     global commentend idtags idline linknum
 
     $canv delete hover
     global commentend idtags idline linknum
 
     $canv delete hover
+    normalline
     if {![info exists lineid($l)] || ![info exists linehtag($l)]} return
     $canv delete secsel
     set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \
     if {![info exists lineid($l)] || ![info exists linehtag($l)]} return
     $canv delete secsel
     set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \
@@ -2077,8 +2203,8 @@ proc selectline {l isnew} {
     set ytop [expr {$y - $linespc - 1}]
     set ybot [expr {$y + $linespc + 1}]
     set wnow [$canv yview]
     set ytop [expr {$y - $linespc - 1}]
     set ybot [expr {$y + $linespc + 1}]
     set wnow [$canv yview]
-    set wtop [expr [lindex $wnow 0] * $ymax]
-    set wbot [expr [lindex $wnow 1] * $ymax]
+    set wtop [expr {[lindex $wnow 0] * $ymax}]
+    set wbot [expr {[lindex $wnow 1] * $ymax}]
     set wh [expr {$wbot - $wtop}]
     set newtop $wtop
     if {$ytop < $wtop} {
     set wh [expr {$wbot - $wtop}]
     set newtop $wtop
     if {$ytop < $wtop} {
@@ -2104,7 +2230,7 @@ proc selectline {l isnew} {
        if {$newtop < 0} {
            set newtop 0
        }
        if {$newtop < 0} {
            set newtop 0
        }
-       allcanvs yview moveto [expr $newtop * 1.0 / $ymax]
+       allcanvs yview moveto [expr {$newtop * 1.0 / $ymax}]
     }
 
     if {$isnew} {
     }
 
     if {$isnew} {
@@ -2126,8 +2252,10 @@ proc selectline {l isnew} {
     $ctext mark set fmark.0 0.0
     $ctext mark gravity fmark.0 left
     set info $commitinfo($id)
     $ctext mark set fmark.0 0.0
     $ctext mark gravity fmark.0 left
     set info $commitinfo($id)
-    $ctext insert end "Author: [lindex $info 1]  [lindex $info 2]\n"
-    $ctext insert end "Committer: [lindex $info 3]  [lindex $info 4]\n"
+    set date [formatdate [lindex $info 2]]
+    $ctext insert end "Author: [lindex $info 1]  $date\n"
+    set date [formatdate [lindex $info 4]]
+    $ctext insert end "Committer: [lindex $info 3]  $date\n"
     if {[info exists idtags($id)]} {
        $ctext insert end "Tags:"
        foreach tag $idtags($id) {
     if {[info exists idtags($id)]} {
        $ctext insert end "Tags:"
        foreach tag $idtags($id) {
@@ -2161,7 +2289,7 @@ proc selectline {l isnew} {
     $cflist delete 0 end
     $cflist insert end "Comments"
     if {$nparents($id) == 1} {
     $cflist delete 0 end
     $cflist insert end "Comments"
     if {$nparents($id) == 1} {
-       startdiff [concat $id $parents($id)]
+       startdiff $id
     } elseif {$nparents($id) > 1} {
        mergediff $id
     }
     } elseif {$nparents($id) > 1} {
        mergediff $id
     }
@@ -2170,7 +2298,7 @@ proc selectline {l isnew} {
 proc selnextline {dir} {
     global selectedline
     if {![info exists selectedline]} return
 proc selnextline {dir} {
     global selectedline
     if {![info exists selectedline]} return
-    set l [expr $selectedline + $dir]
+    set l [expr {$selectedline + $dir}]
     unmarkmatches
     selectline $l 1
 }
     unmarkmatches
     selectline $l 1
 }
@@ -2270,12 +2398,12 @@ proc contmergediff {ids} {
     # diff the child against each of the parents, and diff
     # each of the parents against the GCA.
     while 1 {
     # diff the child against each of the parents, and diff
     # each of the parents against the GCA.
     while 1 {
-       if {[lindex $ids 0] == $diffmergeid && $diffmergegca ne {}} {
-           set ids [list [lindex $ids 1] $diffmergegca]
+       if {[lindex $ids 1] == $diffmergeid && $diffmergegca ne {}} {
+           set ids [list $diffmergegca [lindex $ids 0]]
        } else {
            if {[incr diffpindex] >= $nparents($diffmergeid)} break
            set p [lindex $parents($diffmergeid) $diffpindex]
        } else {
            if {[incr diffpindex] >= $nparents($diffmergeid)} break
            set p [lindex $parents($diffmergeid) $diffpindex]
-           set ids [list $diffmergeid $p]
+           set ids [list $p $diffmergeid]
        }
        if {![info exists treediffs($ids)]} {
            set diffids $ids
        }
        if {![info exists treediffs($ids)]} {
            set diffids $ids
@@ -2293,8 +2421,8 @@ proc contmergediff {ids} {
     if {$diffmergegca ne {}} {
        set files {}
        foreach p $parents($diffmergeid) {
     if {$diffmergegca ne {}} {
        set files {}
        foreach p $parents($diffmergeid) {
-           set gcadiffs $treediffs([list $p $diffmergegca])
-           foreach f $treediffs([list $diffmergeid $p]) {
+           set gcadiffs $treediffs([list $diffmergegca $p])
+           foreach f $treediffs([list $p $diffmergeid]) {
                if {[lsearch -exact $files $f] < 0
                    && [lsearch -exact $gcadiffs $f] >= 0} {
                    lappend files $f
                if {[lsearch -exact $files $f] < 0
                    && [lsearch -exact $gcadiffs $f] >= 0} {
                    lappend files $f
@@ -2307,7 +2435,7 @@ proc contmergediff {ids} {
        set files $treediffs([list $diffmergeid $p])
        for {set i 1} {$i < $nparents($diffmergeid) && $files ne {}} {incr i} {
            set p [lindex $parents($diffmergeid) $i]
        set files $treediffs([list $diffmergeid $p])
        for {set i 1} {$i < $nparents($diffmergeid) && $files ne {}} {incr i} {
            set p [lindex $parents($diffmergeid) $i]
-           set df $treediffs([list $diffmergeid $p])
+           set df $treediffs([list $p $diffmergeid])
            set nf {}
            foreach f $files {
                if {[lsearch -exact $df $f] >= 0} {
            set nf {}
            foreach f $files {
                if {[lsearch -exact $df $f] >= 0} {
@@ -2784,9 +2912,7 @@ proc gettreediffs {ids} {
     global treediff parents treepending
     set treepending $ids
     set treediff {}
     global treediff parents treepending
     set treepending $ids
     set treediff {}
-    set id [lindex $ids 0]
-    set p [lindex $ids 1]
-    if [catch {set gdtf [open "|git-diff-tree -r $p $id" r]}] return
+    if [catch {set gdtf [open [concat | git-diff-tree --no-commit-id -r $ids] r]}] return
     fconfigure $gdtf -blocking 0
     fileevent $gdtf readable [list gettreediffline $gdtf $ids]
 }
     fconfigure $gdtf -blocking 0
     fileevent $gdtf readable [list gettreediffline $gdtf $ids]
 }
@@ -2819,10 +2945,8 @@ proc getblobdiffs {ids} {
     global diffopts blobdifffd diffids env curdifftag curtagstart
     global difffilestart nextupdate diffinhdr treediffs
 
     global diffopts blobdifffd diffids env curdifftag curtagstart
     global difffilestart nextupdate diffinhdr treediffs
 
-    set id [lindex $ids 0]
-    set p [lindex $ids 1]
     set env(GIT_DIFF_OPTS) $diffopts
     set env(GIT_DIFF_OPTS) $diffopts
-    set cmd [list | git-diff-tree -r -p -C $p $id]
+    set cmd [concat | git-diff-tree --no-commit-id -r -p -C $ids]
     if {[catch {set bdf [open $cmd r]} err]} {
        puts "error getting diffs: $err"
        return
     if {[catch {set bdf [open $cmd r]} err]} {
        puts "error getting diffs: $err"
        return
@@ -2841,7 +2965,6 @@ proc getblobdiffline {bdf ids} {
     global diffids blobdifffd ctext curdifftag curtagstart
     global diffnexthead diffnextnote difffilestart
     global nextupdate diffinhdr treediffs
     global diffids blobdifffd ctext curdifftag curtagstart
     global diffnexthead diffnextnote difffilestart
     global nextupdate diffinhdr treediffs
-    global gaudydiff
 
     set n [gets $bdf line]
     if {$n < 0} {
 
     set n [gets $bdf line]
     if {$n < 0} {
@@ -2890,26 +3013,14 @@ proc getblobdiffline {bdf ids} {
        set diffinhdr 0
     } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
                   $line match f1l f1c f2l f2c rest]} {
        set diffinhdr 0
     } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
                   $line match f1l f1c f2l f2c rest]} {
-       if {$gaudydiff} {
-           $ctext insert end "\t" hunksep
-           $ctext insert end "    $f1l    " d0 "    $f2l    " d1
-           $ctext insert end "    $rest \n" hunksep
-       } else {
-           $ctext insert end "$line\n" hunksep
-       }
+       $ctext insert end "$line\n" hunksep
        set diffinhdr 0
     } else {
        set x [string range $line 0 0]
        if {$x == "-" || $x == "+"} {
            set tag [expr {$x == "+"}]
        set diffinhdr 0
     } else {
        set x [string range $line 0 0]
        if {$x == "-" || $x == "+"} {
            set tag [expr {$x == "+"}]
-           if {$gaudydiff} {
-               set line [string range $line 1 end]
-           }
            $ctext insert end "$line\n" d$tag
        } elseif {$x == " "} {
            $ctext insert end "$line\n" d$tag
        } elseif {$x == " "} {
-           if {$gaudydiff} {
-               set line [string range $line 1 end]
-           }
            $ctext insert end "$line\n"
        } elseif {$diffinhdr || $x == "\\"} {
            # e.g. "\ No newline at end of file"
            $ctext insert end "$line\n"
        } elseif {$diffinhdr || $x == "\\"} {
            # e.g. "\ No newline at end of file"
@@ -2965,8 +3076,8 @@ proc setcoords {} {
 
     set linespc [font metrics $mainfont -linespace]
     set charspc [font measure $mainfont "m"]
 
     set linespc [font metrics $mainfont -linespace]
     set charspc [font measure $mainfont "m"]
-    set canvy0 [expr 3 + 0.5 * $linespc]
-    set canvx0 [expr 3 + 0.5 * $linespc]
+    set canvy0 [expr {3 + 0.5 * $linespc}]
+    set canvx0 [expr {3 + 0.5 * $linespc}]
     set lthickness [expr {int($linespc / 9) + 1}]
     set xspc1(0) $linespc
     set xspc2 $linespc
     set lthickness [expr {int($linespc / 9) + 1}]
     set xspc1(0) $linespc
     set xspc2 $linespc
@@ -3123,19 +3234,108 @@ proc linehover {} {
     set t [$canv create rectangle $x0 $y0 $x1 $y1 \
               -fill \#ffff80 -outline black -width 1 -tags hover]
     $canv raise $t
     set t [$canv create rectangle $x0 $y0 $x1 $y1 \
               -fill \#ffff80 -outline black -width 1 -tags hover]
     $canv raise $t
-    set t [$canv create text $x $y -anchor nw -text $text -tags hover]
+    set t [$canv create text $x $y -anchor nw -text $text -tags hover -font $mainfont]
     $canv raise $t
 }
 
     $canv raise $t
 }
 
+proc clickisonarrow {id y} {
+    global mainline mainlinearrow sidelines lthickness
+
+    set thresh [expr {2 * $lthickness + 6}]
+    if {[info exists mainline($id)]} {
+       if {$mainlinearrow($id) ne "none"} {
+           if {abs([lindex $mainline($id) 1] - $y) < $thresh} {
+               return "up"
+           }
+       }
+    }
+    if {[info exists sidelines($id)]} {
+       foreach ls $sidelines($id) {
+           set coords [lindex $ls 0]
+           set arrow [lindex $ls 2]
+           if {$arrow eq "first" || $arrow eq "both"} {
+               if {abs([lindex $coords 1] - $y) < $thresh} {
+                   return "up"
+               }
+           }
+           if {$arrow eq "last" || $arrow eq "both"} {
+               if {abs([lindex $coords end] - $y) < $thresh} {
+                   return "down"
+               }
+           }
+       }
+    }
+    return {}
+}
+
+proc arrowjump {id dirn y} {
+    global mainline sidelines canv canv2 canv3
+
+    set yt {}
+    if {$dirn eq "down"} {
+       if {[info exists mainline($id)]} {
+           set y1 [lindex $mainline($id) 1]
+           if {$y1 > $y} {
+               set yt $y1
+           }
+       }
+       if {[info exists sidelines($id)]} {
+           foreach ls $sidelines($id) {
+               set y1 [lindex $ls 0 1]
+               if {$y1 > $y && ($yt eq {} || $y1 < $yt)} {
+                   set yt $y1
+               }
+           }
+       }
+    } else {
+       if {[info exists sidelines($id)]} {
+           foreach ls $sidelines($id) {
+               set y1 [lindex $ls 0 end]
+               if {$y1 < $y && ($yt eq {} || $y1 > $yt)} {
+                   set yt $y1
+               }
+           }
+       }
+    }
+    if {$yt eq {}} return
+    set ymax [lindex [$canv cget -scrollregion] 3]
+    if {$ymax eq {} || $ymax <= 0} return
+    set view [$canv yview]
+    set yspan [expr {[lindex $view 1] - [lindex $view 0]}]
+    set yfrac [expr {$yt / $ymax - $yspan / 2}]
+    if {$yfrac < 0} {
+       set yfrac 0
+    }
+    $canv yview moveto $yfrac
+    $canv2 yview moveto $yfrac
+    $canv3 yview moveto $yfrac
+}
+
 proc lineclick {x y id isnew} {
 proc lineclick {x y id isnew} {
-    global ctext commitinfo children cflist canv
+    global ctext commitinfo children cflist canv thickerline
 
     unmarkmatches
     unselectline
 
     unmarkmatches
     unselectline
+    normalline
+    $canv delete hover
+    # draw this line thicker than normal
+    drawlines $id 1 1
+    set thickerline $id
+    if {$isnew} {
+       set ymax [lindex [$canv cget -scrollregion] 3]
+       if {$ymax eq {}} return
+       set yfrac [lindex [$canv yview] 0]
+       set y [expr {$y + $yfrac * $ymax}]
+    }
+    set dirn [clickisonarrow $id $y]
+    if {$dirn ne {}} {
+       arrowjump $id $dirn $y
+       return
+    }
+
     if {$isnew} {
     if {$isnew} {
-       addtohistory [list lineclick $x $x $id 0]
+       addtohistory [list lineclick $x $y $id 0]
     }
     }
-    $canv delete hover
     # fill the details pane with info about this line
     $ctext conf -state normal
     $ctext delete 0.0 end
     # fill the details pane with info about this line
     $ctext conf -state normal
     $ctext delete 0.0 end
@@ -3148,7 +3348,8 @@ proc lineclick {x y id isnew} {
     set info $commitinfo($id)
     $ctext insert end "\n\t[lindex $info 0]\n"
     $ctext insert end "\tAuthor:\t[lindex $info 1]\n"
     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 "\tDate:\t[lindex $info 2]\n"
+    set date [formatdate [lindex $info 2]]
+    $ctext insert end "\tDate:\t$date\n"
     if {[info exists children($id)]} {
        $ctext insert end "\nChildren:"
        set i 0
     if {[info exists children($id)]} {
        $ctext insert end "\nChildren:"
        set i 0
@@ -3160,7 +3361,8 @@ proc lineclick {x y id isnew} {
            $ctext tag bind link$i <1> [list selbyid $child]
            $ctext insert end "\n\t[lindex $info 0]"
            $ctext insert end "\n\tAuthor:\t[lindex $info 1]"
            $ctext tag bind link$i <1> [list selbyid $child]
            $ctext insert end "\n\t[lindex $info 0]"
            $ctext insert end "\n\tAuthor:\t[lindex $info 1]"
-           $ctext insert end "\n\tDate:\t[lindex $info 2]\n"
+           set date [formatdate [lindex $info 2]]
+           $ctext insert end "\n\tDate:\t$date\n"
        }
     }
     $ctext conf -state disabled
        }
     }
     $ctext conf -state disabled
@@ -3168,6 +3370,14 @@ proc lineclick {x y id isnew} {
     $cflist delete 0 end
 }
 
     $cflist delete 0 end
 }
 
+proc normalline {} {
+    global thickerline
+    if {[info exists thickerline]} {
+       drawlines $thickerline 0 1
+       unset thickerline
+    }
+}
+
 proc selbyid {id} {
     global idline
     if {[info exists idline($id)]} {
 proc selbyid {id} {
     global idline
     if {[info exists idline($id)]} {
@@ -3240,7 +3450,7 @@ proc doseldiff {oldid newid} {
     $ctext conf -state disabled
     $ctext tag delete Comments
     $ctext tag remove found 1.0 end
     $ctext conf -state disabled
     $ctext tag delete Comments
     $ctext tag remove found 1.0 end
-    startdiff [list $newid $oldid]
+    startdiff [list $oldid $newid]
 }
 
 proc mkpatch {} {
 }
 
 proc mkpatch {} {
@@ -3496,9 +3706,6 @@ proc rereadrefs {} {
            set ref($id) [listrefs $id]
        }
     }
            set ref($id) [listrefs $id]
        }
     }
-    foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
-       catch {unset $v}
-    }
     readrefs
     set refids [lsort -unique [concat $refids [array names idtags] \
                        [array names idheads] [array names idotherrefs]]]
     readrefs
     set refids [lsort -unique [concat $refids [array names idtags] \
                        [array names idheads] [array names idotherrefs]]]
@@ -3535,34 +3742,390 @@ proc doquit {} {
     destroy .
 }
 
     destroy .
 }
 
+proc doprefs {} {
+    global maxwidth maxgraphpct diffopts findmergefiles
+    global oldprefs prefstop
+
+    set top .gitkprefs
+    set prefstop $top
+    if {[winfo exists $top]} {
+       raise $top
+       return
+    }
+    foreach v {maxwidth maxgraphpct diffopts findmergefiles} {
+       set oldprefs($v) [set $v]
+    }
+    toplevel $top
+    wm title $top "Gitk preferences"
+    label $top.ldisp -text "Commit list display options"
+    grid $top.ldisp - -sticky w -pady 10
+    label $top.spacer -text " "
+    label $top.maxwidthl -text "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)" \
+       -font optionfont
+    spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
+    grid x $top.maxpctl $top.maxpct -sticky w
+    checkbutton $top.findm -variable findmergefiles
+    label $top.findml -text "Include merges for \"Find\" in \"Files\"" \
+       -font optionfont
+    grid $top.findm $top.findml - -sticky w
+    label $top.ddisp -text "Diff display options"
+    grid $top.ddisp - -sticky w -pady 10
+    label $top.diffoptl -text "Options for diff program" \
+       -font optionfont
+    entry $top.diffopt -width 20 -textvariable diffopts
+    grid x $top.diffoptl $top.diffopt -sticky w
+    frame $top.buts
+    button $top.buts.ok -text "OK" -command prefsok
+    button $top.buts.can -text "Cancel" -command prefscan
+    grid $top.buts.ok $top.buts.can
+    grid columnconfigure $top.buts 0 -weight 1 -uniform a
+    grid columnconfigure $top.buts 1 -weight 1 -uniform a
+    grid $top.buts - - -pady 10 -sticky ew
+}
+
+proc prefscan {} {
+    global maxwidth maxgraphpct diffopts findmergefiles
+    global oldprefs prefstop
+
+    foreach v {maxwidth maxgraphpct diffopts findmergefiles} {
+       set $v $oldprefs($v)
+    }
+    catch {destroy $prefstop}
+    unset prefstop
+}
+
+proc prefsok {} {
+    global maxwidth maxgraphpct
+    global oldprefs prefstop
+
+    catch {destroy $prefstop}
+    unset prefstop
+    if {$maxwidth != $oldprefs(maxwidth)
+       || $maxgraphpct != $oldprefs(maxgraphpct)} {
+       redisplay
+    }
+}
+
+proc formatdate {d} {
+    return [clock format $d -format "%Y-%m-%d %H:%M:%S"]
+}
+
+# This list of encoding names and aliases is distilled from
+# http://www.iana.org/assignments/character-sets.
+# Not all of them are supported by Tcl.
+set encoding_aliases {
+    { ANSI_X3.4-1968 iso-ir-6 ANSI_X3.4-1986 ISO_646.irv:1991 ASCII
+      ISO646-US US-ASCII us IBM367 cp367 csASCII }
+    { ISO-10646-UTF-1 csISO10646UTF1 }
+    { ISO_646.basic:1983 ref csISO646basic1983 }
+    { INVARIANT csINVARIANT }
+    { ISO_646.irv:1983 iso-ir-2 irv csISO2IntlRefVersion }
+    { BS_4730 iso-ir-4 ISO646-GB gb uk csISO4UnitedKingdom }
+    { NATS-SEFI iso-ir-8-1 csNATSSEFI }
+    { NATS-SEFI-ADD iso-ir-8-2 csNATSSEFIADD }
+    { NATS-DANO iso-ir-9-1 csNATSDANO }
+    { NATS-DANO-ADD iso-ir-9-2 csNATSDANOADD }
+    { SEN_850200_B iso-ir-10 FI ISO646-FI ISO646-SE se csISO10Swedish }
+    { SEN_850200_C iso-ir-11 ISO646-SE2 se2 csISO11SwedishForNames }
+    { KS_C_5601-1987 iso-ir-149 KS_C_5601-1989 KSC_5601 korean csKSC56011987 }
+    { ISO-2022-KR csISO2022KR }
+    { EUC-KR csEUCKR }
+    { ISO-2022-JP csISO2022JP }
+    { ISO-2022-JP-2 csISO2022JP2 }
+    { JIS_C6220-1969-jp JIS_C6220-1969 iso-ir-13 katakana x0201-7
+      csISO13JISC6220jp }
+    { JIS_C6220-1969-ro iso-ir-14 jp ISO646-JP csISO14JISC6220ro }
+    { IT iso-ir-15 ISO646-IT csISO15Italian }
+    { PT iso-ir-16 ISO646-PT csISO16Portuguese }
+    { ES iso-ir-17 ISO646-ES csISO17Spanish }
+    { greek7-old iso-ir-18 csISO18Greek7Old }
+    { latin-greek iso-ir-19 csISO19LatinGreek }
+    { DIN_66003 iso-ir-21 de ISO646-DE csISO21German }
+    { NF_Z_62-010_(1973) iso-ir-25 ISO646-FR1 csISO25French }
+    { Latin-greek-1 iso-ir-27 csISO27LatinGreek1 }
+    { ISO_5427 iso-ir-37 csISO5427Cyrillic }
+    { JIS_C6226-1978 iso-ir-42 csISO42JISC62261978 }
+    { BS_viewdata iso-ir-47 csISO47BSViewdata }
+    { INIS iso-ir-49 csISO49INIS }
+    { INIS-8 iso-ir-50 csISO50INIS8 }
+    { INIS-cyrillic iso-ir-51 csISO51INISCyrillic }
+    { ISO_5427:1981 iso-ir-54 ISO5427Cyrillic1981 }
+    { ISO_5428:1980 iso-ir-55 csISO5428Greek }
+    { GB_1988-80 iso-ir-57 cn ISO646-CN csISO57GB1988 }
+    { GB_2312-80 iso-ir-58 chinese csISO58GB231280 }
+    { NS_4551-1 iso-ir-60 ISO646-NO no csISO60DanishNorwegian
+      csISO60Norwegian1 }
+    { NS_4551-2 ISO646-NO2 iso-ir-61 no2 csISO61Norwegian2 }
+    { NF_Z_62-010 iso-ir-69 ISO646-FR fr csISO69French }
+    { videotex-suppl iso-ir-70 csISO70VideotexSupp1 }
+    { PT2 iso-ir-84 ISO646-PT2 csISO84Portuguese2 }
+    { ES2 iso-ir-85 ISO646-ES2 csISO85Spanish2 }
+    { MSZ_7795.3 iso-ir-86 ISO646-HU hu csISO86Hungarian }
+    { JIS_C6226-1983 iso-ir-87 x0208 JIS_X0208-1983 csISO87JISX0208 }
+    { greek7 iso-ir-88 csISO88Greek7 }
+    { ASMO_449 ISO_9036 arabic7 iso-ir-89 csISO89ASMO449 }
+    { iso-ir-90 csISO90 }
+    { JIS_C6229-1984-a iso-ir-91 jp-ocr-a csISO91JISC62291984a }
+    { JIS_C6229-1984-b iso-ir-92 ISO646-JP-OCR-B jp-ocr-b
+      csISO92JISC62991984b }
+    { JIS_C6229-1984-b-add iso-ir-93 jp-ocr-b-add csISO93JIS62291984badd }
+    { JIS_C6229-1984-hand iso-ir-94 jp-ocr-hand csISO94JIS62291984hand }
+    { JIS_C6229-1984-hand-add iso-ir-95 jp-ocr-hand-add
+      csISO95JIS62291984handadd }
+    { JIS_C6229-1984-kana iso-ir-96 csISO96JISC62291984kana }
+    { ISO_2033-1983 iso-ir-98 e13b csISO2033 }
+    { ANSI_X3.110-1983 iso-ir-99 CSA_T500-1983 NAPLPS csISO99NAPLPS }
+    { ISO_8859-1:1987 iso-ir-100 ISO_8859-1 ISO-8859-1 latin1 l1 IBM819
+      CP819 csISOLatin1 }
+    { ISO_8859-2:1987 iso-ir-101 ISO_8859-2 ISO-8859-2 latin2 l2 csISOLatin2 }
+    { T.61-7bit iso-ir-102 csISO102T617bit }
+    { T.61-8bit T.61 iso-ir-103 csISO103T618bit }
+    { ISO_8859-3:1988 iso-ir-109 ISO_8859-3 ISO-8859-3 latin3 l3 csISOLatin3 }
+    { ISO_8859-4:1988 iso-ir-110 ISO_8859-4 ISO-8859-4 latin4 l4 csISOLatin4 }
+    { ECMA-cyrillic iso-ir-111 KOI8-E csISO111ECMACyrillic }
+    { CSA_Z243.4-1985-1 iso-ir-121 ISO646-CA csa7-1 ca csISO121Canadian1 }
+    { CSA_Z243.4-1985-2 iso-ir-122 ISO646-CA2 csa7-2 csISO122Canadian2 }
+    { CSA_Z243.4-1985-gr iso-ir-123 csISO123CSAZ24341985gr }
+    { ISO_8859-6:1987 iso-ir-127 ISO_8859-6 ISO-8859-6 ECMA-114 ASMO-708
+      arabic csISOLatinArabic }
+    { ISO_8859-6-E csISO88596E ISO-8859-6-E }
+    { ISO_8859-6-I csISO88596I ISO-8859-6-I }
+    { ISO_8859-7:1987 iso-ir-126 ISO_8859-7 ISO-8859-7 ELOT_928 ECMA-118
+      greek greek8 csISOLatinGreek }
+    { T.101-G2 iso-ir-128 csISO128T101G2 }
+    { ISO_8859-8:1988 iso-ir-138 ISO_8859-8 ISO-8859-8 hebrew
+      csISOLatinHebrew }
+    { ISO_8859-8-E csISO88598E ISO-8859-8-E }
+    { ISO_8859-8-I csISO88598I ISO-8859-8-I }
+    { CSN_369103 iso-ir-139 csISO139CSN369103 }
+    { JUS_I.B1.002 iso-ir-141 ISO646-YU js yu csISO141JUSIB1002 }
+    { ISO_6937-2-add iso-ir-142 csISOTextComm }
+    { IEC_P27-1 iso-ir-143 csISO143IECP271 }
+    { ISO_8859-5:1988 iso-ir-144 ISO_8859-5 ISO-8859-5 cyrillic
+      csISOLatinCyrillic }
+    { JUS_I.B1.003-serb iso-ir-146 serbian csISO146Serbian }
+    { JUS_I.B1.003-mac macedonian iso-ir-147 csISO147Macedonian }
+    { ISO_8859-9:1989 iso-ir-148 ISO_8859-9 ISO-8859-9 latin5 l5 csISOLatin5 }
+    { greek-ccitt iso-ir-150 csISO150 csISO150GreekCCITT }
+    { NC_NC00-10:81 cuba iso-ir-151 ISO646-CU csISO151Cuba }
+    { ISO_6937-2-25 iso-ir-152 csISO6937Add }
+    { GOST_19768-74 ST_SEV_358-88 iso-ir-153 csISO153GOST1976874 }
+    { ISO_8859-supp iso-ir-154 latin1-2-5 csISO8859Supp }
+    { ISO_10367-box iso-ir-155 csISO10367Box }
+    { ISO-8859-10 iso-ir-157 l6 ISO_8859-10:1992 csISOLatin6 latin6 }
+    { latin-lap lap iso-ir-158 csISO158Lap }
+    { JIS_X0212-1990 x0212 iso-ir-159 csISO159JISX02121990 }
+    { DS_2089 DS2089 ISO646-DK dk csISO646Danish }
+    { us-dk csUSDK }
+    { dk-us csDKUS }
+    { JIS_X0201 X0201 csHalfWidthKatakana }
+    { KSC5636 ISO646-KR csKSC5636 }
+    { ISO-10646-UCS-2 csUnicode }
+    { ISO-10646-UCS-4 csUCS4 }
+    { DEC-MCS dec csDECMCS }
+    { hp-roman8 roman8 r8 csHPRoman8 }
+    { macintosh mac csMacintosh }
+    { IBM037 cp037 ebcdic-cp-us ebcdic-cp-ca ebcdic-cp-wt ebcdic-cp-nl
+      csIBM037 }
+    { IBM038 EBCDIC-INT cp038 csIBM038 }
+    { IBM273 CP273 csIBM273 }
+    { IBM274 EBCDIC-BE CP274 csIBM274 }
+    { IBM275 EBCDIC-BR cp275 csIBM275 }
+    { IBM277 EBCDIC-CP-DK EBCDIC-CP-NO csIBM277 }
+    { IBM278 CP278 ebcdic-cp-fi ebcdic-cp-se csIBM278 }
+    { IBM280 CP280 ebcdic-cp-it csIBM280 }
+    { IBM281 EBCDIC-JP-E cp281 csIBM281 }
+    { IBM284 CP284 ebcdic-cp-es csIBM284 }
+    { IBM285 CP285 ebcdic-cp-gb csIBM285 }
+    { IBM290 cp290 EBCDIC-JP-kana csIBM290 }
+    { IBM297 cp297 ebcdic-cp-fr csIBM297 }
+    { IBM420 cp420 ebcdic-cp-ar1 csIBM420 }
+    { IBM423 cp423 ebcdic-cp-gr csIBM423 }
+    { IBM424 cp424 ebcdic-cp-he csIBM424 }
+    { IBM437 cp437 437 csPC8CodePage437 }
+    { IBM500 CP500 ebcdic-cp-be ebcdic-cp-ch csIBM500 }
+    { IBM775 cp775 csPC775Baltic }
+    { IBM850 cp850 850 csPC850Multilingual }
+    { IBM851 cp851 851 csIBM851 }
+    { IBM852 cp852 852 csPCp852 }
+    { IBM855 cp855 855 csIBM855 }
+    { IBM857 cp857 857 csIBM857 }
+    { IBM860 cp860 860 csIBM860 }
+    { IBM861 cp861 861 cp-is csIBM861 }
+    { IBM862 cp862 862 csPC862LatinHebrew }
+    { IBM863 cp863 863 csIBM863 }
+    { IBM864 cp864 csIBM864 }
+    { IBM865 cp865 865 csIBM865 }
+    { IBM866 cp866 866 csIBM866 }
+    { IBM868 CP868 cp-ar csIBM868 }
+    { IBM869 cp869 869 cp-gr csIBM869 }
+    { IBM870 CP870 ebcdic-cp-roece ebcdic-cp-yu csIBM870 }
+    { IBM871 CP871 ebcdic-cp-is csIBM871 }
+    { IBM880 cp880 EBCDIC-Cyrillic csIBM880 }
+    { IBM891 cp891 csIBM891 }
+    { IBM903 cp903 csIBM903 }
+    { IBM904 cp904 904 csIBBM904 }
+    { IBM905 CP905 ebcdic-cp-tr csIBM905 }
+    { IBM918 CP918 ebcdic-cp-ar2 csIBM918 }
+    { IBM1026 CP1026 csIBM1026 }
+    { EBCDIC-AT-DE csIBMEBCDICATDE }
+    { EBCDIC-AT-DE-A csEBCDICATDEA }
+    { EBCDIC-CA-FR csEBCDICCAFR }
+    { EBCDIC-DK-NO csEBCDICDKNO }
+    { EBCDIC-DK-NO-A csEBCDICDKNOA }
+    { EBCDIC-FI-SE csEBCDICFISE }
+    { EBCDIC-FI-SE-A csEBCDICFISEA }
+    { EBCDIC-FR csEBCDICFR }
+    { EBCDIC-IT csEBCDICIT }
+    { EBCDIC-PT csEBCDICPT }
+    { EBCDIC-ES csEBCDICES }
+    { EBCDIC-ES-A csEBCDICESA }
+    { EBCDIC-ES-S csEBCDICESS }
+    { EBCDIC-UK csEBCDICUK }
+    { EBCDIC-US csEBCDICUS }
+    { UNKNOWN-8BIT csUnknown8BiT }
+    { MNEMONIC csMnemonic }
+    { MNEM csMnem }
+    { VISCII csVISCII }
+    { VIQR csVIQR }
+    { KOI8-R csKOI8R }
+    { IBM00858 CCSID00858 CP00858 PC-Multilingual-850+euro }
+    { IBM00924 CCSID00924 CP00924 ebcdic-Latin9--euro }
+    { IBM01140 CCSID01140 CP01140 ebcdic-us-37+euro }
+    { IBM01141 CCSID01141 CP01141 ebcdic-de-273+euro }
+    { IBM01142 CCSID01142 CP01142 ebcdic-dk-277+euro ebcdic-no-277+euro }
+    { IBM01143 CCSID01143 CP01143 ebcdic-fi-278+euro ebcdic-se-278+euro }
+    { IBM01144 CCSID01144 CP01144 ebcdic-it-280+euro }
+    { IBM01145 CCSID01145 CP01145 ebcdic-es-284+euro }
+    { IBM01146 CCSID01146 CP01146 ebcdic-gb-285+euro }
+    { IBM01147 CCSID01147 CP01147 ebcdic-fr-297+euro }
+    { IBM01148 CCSID01148 CP01148 ebcdic-international-500+euro }
+    { IBM01149 CCSID01149 CP01149 ebcdic-is-871+euro }
+    { IBM1047 IBM-1047 }
+    { PTCP154 csPTCP154 PT154 CP154 Cyrillic-Asian }
+    { Amiga-1251 Ami1251 Amiga1251 Ami-1251 }
+    { UNICODE-1-1 csUnicode11 }
+    { CESU-8 csCESU-8 }
+    { BOCU-1 csBOCU-1 }
+    { UNICODE-1-1-UTF-7 csUnicode11UTF7 }
+    { ISO-8859-14 iso-ir-199 ISO_8859-14:1998 ISO_8859-14 latin8 iso-celtic
+      l8 }
+    { ISO-8859-15 ISO_8859-15 Latin-9 }
+    { ISO-8859-16 iso-ir-226 ISO_8859-16:2001 ISO_8859-16 latin10 l10 }
+    { GBK CP936 MS936 windows-936 }
+    { JIS_Encoding csJISEncoding }
+    { Shift_JIS MS_Kanji csShiftJIS }
+    { Extended_UNIX_Code_Packed_Format_for_Japanese csEUCPkdFmtJapanese
+      EUC-JP }
+    { Extended_UNIX_Code_Fixed_Width_for_Japanese csEUCFixWidJapanese }
+    { ISO-10646-UCS-Basic csUnicodeASCII }
+    { ISO-10646-Unicode-Latin1 csUnicodeLatin1 ISO-10646 }
+    { ISO-Unicode-IBM-1261 csUnicodeIBM1261 }
+    { ISO-Unicode-IBM-1268 csUnicodeIBM1268 }
+    { ISO-Unicode-IBM-1276 csUnicodeIBM1276 }
+    { ISO-Unicode-IBM-1264 csUnicodeIBM1264 }
+    { ISO-Unicode-IBM-1265 csUnicodeIBM1265 }
+    { ISO-8859-1-Windows-3.0-Latin-1 csWindows30Latin1 }
+    { ISO-8859-1-Windows-3.1-Latin-1 csWindows31Latin1 }
+    { ISO-8859-2-Windows-Latin-2 csWindows31Latin2 }
+    { ISO-8859-9-Windows-Latin-5 csWindows31Latin5 }
+    { Adobe-Standard-Encoding csAdobeStandardEncoding }
+    { Ventura-US csVenturaUS }
+    { Ventura-International csVenturaInternational }
+    { PC8-Danish-Norwegian csPC8DanishNorwegian }
+    { PC8-Turkish csPC8Turkish }
+    { IBM-Symbols csIBMSymbols }
+    { IBM-Thai csIBMThai }
+    { HP-Legal csHPLegal }
+    { HP-Pi-font csHPPiFont }
+    { HP-Math8 csHPMath8 }
+    { Adobe-Symbol-Encoding csHPPSMath }
+    { HP-DeskTop csHPDesktop }
+    { Ventura-Math csVenturaMath }
+    { Microsoft-Publishing csMicrosoftPublishing }
+    { Windows-31J csWindows31J }
+    { GB2312 csGB2312 }
+    { Big5 csBig5 }
+}
+
+proc tcl_encoding {enc} {
+    global encoding_aliases
+    set names [encoding names]
+    set lcnames [string tolower $names]
+    set enc [string tolower $enc]
+    set i [lsearch -exact $lcnames $enc]
+    if {$i < 0} {
+       # look for "isonnn" instead of "iso-nnn" or "iso_nnn"
+       if {[regsub {^iso[-_]} $enc iso encx]} {
+           set i [lsearch -exact $lcnames $encx]
+       }
+    }
+    if {$i < 0} {
+       foreach l $encoding_aliases {
+           set ll [string tolower $l]
+           if {[lsearch -exact $ll $enc] < 0} continue
+           # look through the aliases for one that tcl knows about
+           foreach e $ll {
+               set i [lsearch -exact $lcnames $e]
+               if {$i < 0} {
+                   if {[regsub {^iso[-_]} $e iso ex]} {
+                       set i [lsearch -exact $lcnames $ex]
+                   }
+               }
+               if {$i >= 0} break
+           }
+           break
+       }
+    }
+    if {$i >= 0} {
+       return [lindex $names $i]
+    }
+    return {}
+}
+
 # defaults...
 set datemode 0
 # defaults...
 set datemode 0
-set boldnames 0
 set diffopts "-U 5 -p"
 set wrcomcmd "git-diff-tree --stdin -p --pretty"
 
 set diffopts "-U 5 -p"
 set wrcomcmd "git-diff-tree --stdin -p --pretty"
 
+set gitencoding {}
+catch {
+    set gitencoding [exec git-repo-config --get i18n.commitencoding]
+}
+if {$gitencoding == ""} {
+    set gitencoding "utf-8"
+}
+set tclencoding [tcl_encoding $gitencoding]
+if {$tclencoding == {}} {
+    puts stderr "Warning: encoding $gitencoding is not supported by Tcl/Tk"
+}
+
 set mainfont {Helvetica 9}
 set textfont {Courier 9}
 set findmergefiles 0
 set mainfont {Helvetica 9}
 set textfont {Courier 9}
 set findmergefiles 0
-set gaudydiff 0
 set maxgraphpct 50
 set maxwidth 16
 set maxgraphpct 50
 set maxwidth 16
+set revlistorder 0
+set fastdate 0
 
 set colors {green red blue magenta darkgrey brown orange}
 
 catch {source ~/.gitk}
 
 set namefont $mainfont
 
 set colors {green red blue magenta darkgrey brown orange}
 
 catch {source ~/.gitk}
 
 set namefont $mainfont
-if {$boldnames} {
-    lappend namefont bold
-}
+
+font create optionfont -family sans-serif -size -12
 
 set revtreeargs {}
 foreach arg $argv {
     switch -regexp -- $arg {
        "^$" { }
 
 set revtreeargs {}
 foreach arg $argv {
     switch -regexp -- $arg {
        "^$" { }
-       "^-b" { set boldnames 1 }
        "^-d" { set datemode 1 }
        "^-d" { set datemode 1 }
+       "^-r" { set revlistorder 1 }
        default {
            lappend revtreeargs $arg
        }
        default {
            lappend revtreeargs $arg
        }
@@ -3577,6 +4140,6 @@ set redisplaying 0
 set stuffsaved 0
 set patchnum 0
 setcoords
 set stuffsaved 0
 set patchnum 0
 setcoords
-makewindow
+makewindow $revtreeargs
 readrefs
 getcommits $revtreeargs
 readrefs
 getcommits $revtreeargs