Merge branch 'new'
[git.git] / gitk
diff --git a/gitk b/gitk
index c6649a5..7c25d2e 100755 (executable)
--- a/gitk
+++ b/gitk
@@ -16,56 +16,26 @@ proc gitdir {} {
     }
 }
 
     }
 }
 
-proc parse_args {rargs} {
-    global parsed_args cmdline_files
-
-    set parsed_args {}
-    set cmdline_files {}
-    if {[catch {
-       set args [concat --default HEAD $rargs]
-       set args [split [eval exec git-rev-parse $args] "\n"]
-       set i 0
-       foreach arg $args {
-           if {![regexp {^[0-9a-f]{40}$} $arg]} {
-               if {$arg eq "--"} {
-                   incr i
-               }
-               set cmdline_files [lrange $args $i end]
-               break
-           }
-           lappend parsed_args $arg
-           incr i
-       }
-    }]} {
-       # if git-rev-parse failed for some reason...
-       set i [lsearch -exact $rargs "--"]
-       if {$i >= 0} {
-           set cmdline_files [lrange $rargs [expr {$i+1}] end]
-           set rargs [lrange $rargs 0 [expr {$i-1}]]
-       }
-       if {$rargs == {}} {
-           set parsed_args HEAD
-       } else {
-           set parsed_args $rargs
-       }
-    }
-}
-
-proc start_rev_list {rlargs} {
+proc start_rev_list {} {
     global startmsecs nextupdate ncmupdate
     global commfd leftover tclencoding datemode
     global startmsecs nextupdate ncmupdate
     global commfd leftover tclencoding datemode
+    global revtreeargs curview viewfiles
 
     set startmsecs [clock clicks -milliseconds]
     set nextupdate [expr {$startmsecs + 100}]
     set ncmupdate 1
     initlayout
 
     set startmsecs [clock clicks -milliseconds]
     set nextupdate [expr {$startmsecs + 100}]
     set ncmupdate 1
     initlayout
+    set args $revtreeargs
+    if {$viewfiles($curview) ne {}} {
+       set args [concat $args "--" $viewfiles($curview)]
+    }
     set order "--topo-order"
     if {$datemode} {
        set order "--date-order"
     }
     if {[catch {
        set commfd [open [concat | git-rev-list --header $order \
     set order "--topo-order"
     if {$datemode} {
        set order "--date-order"
     }
     if {[catch {
        set commfd [open [concat | git-rev-list --header $order \
-                             --parents --boundary $rlargs] r]
+                             --parents --boundary --default HEAD $args] r]
     } err]} {
        puts stderr "Error executing git-rev-list: $err"
        exit 1
     } err]} {
        puts stderr "Error executing git-rev-list: $err"
        exit 1
@@ -80,11 +50,23 @@ proc start_rev_list {rlargs} {
     settextcursor watch
 }
 
     settextcursor watch
 }
 
-proc getcommits {rargs} {
+proc stop_rev_list {} {
+    global commfd
+
+    if {![info exists commfd]} return
+    catch {
+       set pid [pid $commfd]
+       exec kill $pid
+    }
+    catch {close $commfd}
+    unset commfd
+}
+
+proc getcommits {} {
     global phase canv mainfont
 
     set phase getcommits
     global phase canv mainfont
 
     set phase getcommits
-    start_rev_list $rargs
+    start_rev_list
     $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
@@ -173,6 +155,7 @@ proc getcommitlines {commfd}  {
        lappend parentlist $olds
        if {[info exists children($id)]} {
            lappend childlist $children($id)
        lappend parentlist $olds
        if {[info exists children($id)]} {
            lappend childlist $children($id)
+           unset children($id)
        } else {
            lappend childlist {}
        }
        } else {
            lappend childlist {}
        }
@@ -217,12 +200,16 @@ proc readcommit {id} {
 }
 
 proc updatecommits {} {
 }
 
 proc updatecommits {} {
-    global viewdata curview revtreeargs
+    global viewdata curview revtreeargs phase
 
 
+    if {$phase ne {}} {
+       stop_rev_list
+       set phase {}
+    }
     set n $curview
     set curview -1
     catch {unset viewdata($n)}
     set n $curview
     set curview -1
     catch {unset viewdata($n)}
-    parse_args $revtreeargs
+    readrefs
     showview $n
 }
 
     showview $n
 }
 
@@ -300,16 +287,22 @@ proc readrefs {} {
     foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
        catch {unset $v}
     }
     foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
        catch {unset $v}
     }
-    set refd [open [list | git-ls-remote [gitdir]] r]
+    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
        }
     while {0 <= [set n [gets $refd line]]} {
        if {![regexp {^([0-9a-f]{40})   refs/([^^]*)$} $line \
            match id path]} {
            continue
        }
+       if {[regexp {^remotes/.*/HEAD$} $path match]} {
+           continue
+       }
        if {![regexp {^(tags|heads)/(.*)$} $path match type name]} {
            set type others
            set name $path
        }
        if {![regexp {^(tags|heads)/(.*)$} $path match type name]} {
            set type others
            set name $path
        }
+       if {[regexp {^remotes/} $path match]} {
+           set type heads
+       }
        if {$type == "tags"} {
            set tagids($name) $id
            lappend idtags($id) $name
        if {$type == "tags"} {
            set tagids($name) $id
            lappend idtags($id) $name
@@ -351,7 +344,8 @@ proc error_popup msg {
 }
 
 proc makewindow {} {
 }
 
 proc makewindow {} {
-    global canv canv2 canv3 linespc charspc ctext cflist textfont
+    global canv canv2 canv3 linespc charspc ctext cflist
+    global textfont mainfont uifont
     global findtype findtypemenu findloc findstring fstring geometry
     global entries sha1entry sha1string sha1but
     global maincursor textcursor curtextcursor
     global findtype findtypemenu findloc findstring fstring geometry
     global entries sha1entry sha1string sha1but
     global maincursor textcursor curtextcursor
@@ -359,22 +353,29 @@ proc makewindow {} {
 
     menu .bar
     .bar add cascade -label "File" -menu .bar.file
 
     menu .bar
     .bar add cascade -label "File" -menu .bar.file
+    .bar configure -font $uifont
     menu .bar.file
     .bar.file add command -label "Update" -command updatecommits
     .bar.file add command -label "Reread references" -command rereadrefs
     .bar.file add command -label "Quit" -command doquit
     menu .bar.file
     .bar.file add command -label "Update" -command updatecommits
     .bar.file add command -label "Reread references" -command rereadrefs
     .bar.file add command -label "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
     menu .bar.edit
     .bar add cascade -label "Edit" -menu .bar.edit
     .bar.edit add command -label "Preferences" -command doprefs
-    menu .bar.view
+    .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
     .bar add cascade -label "View" -menu .bar.view
     .bar.view add command -label "New view..." -command newview
+    .bar.view add command -label "Edit view..." -command editview
     .bar.view add command -label "Delete view" -command delview -state disabled
     .bar.view add separator
     .bar.view add command -label "Delete view" -command delview -state disabled
     .bar.view add separator
-    .bar.view add command -label "All files" -command {showview 0}
+    .bar.view add radiobutton -label "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
     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.help configure -font $uifont
     . configure -menu .bar
 
     if {![info exists geometry(canv1)]} {
     . configure -menu .bar
 
     if {![info exists geometry(canv1)]} {
@@ -421,7 +422,7 @@ proc makewindow {} {
     set entries $sha1entry
     set sha1but .ctop.top.bar.sha1label
     button $sha1but -text "SHA1 ID: " -state disabled -relief flat \
     set entries $sha1entry
     set sha1but .ctop.top.bar.sha1label
     button $sha1but -text "SHA1 ID: " -state disabled -relief flat \
-       -command gotocommit -width 8
+       -command gotocommit -width 8 -font $uifont
     $sha1but conf -disabledforeground [$sha1but cget -foreground]
     pack .ctop.top.bar.sha1label -side left
     entry $sha1entry -width 40 -font $textfont -textvariable sha1string
     $sha1but conf -disabledforeground [$sha1but cget -foreground]
     pack .ctop.top.bar.sha1label -side left
     entry $sha1entry -width 40 -font $textfont -textvariable sha1string
@@ -451,19 +452,24 @@ proc makewindow {} {
        -state disabled -width 26
     pack .ctop.top.bar.rightbut -side left -fill y
 
        -state disabled -width 26
     pack .ctop.top.bar.rightbut -side left -fill y
 
-    button .ctop.top.bar.findbut -text "Find" -command dofind
+    button .ctop.top.bar.findbut -text "Find" -command dofind -font $uifont
     pack .ctop.top.bar.findbut -side left
     set findstring {}
     set fstring .ctop.top.bar.findstring
     lappend entries $fstring
     pack .ctop.top.bar.findbut -side left
     set findstring {}
     set fstring .ctop.top.bar.findstring
     lappend entries $fstring
-    entry $fstring -width 30 -font $textfont -textvariable findstring
+    entry $fstring -width 30 -font $textfont -textvariable findstring -font $textfont
     pack $fstring -side left -expand 1 -fill x
     set findtype Exact
     set findtypemenu [tk_optionMenu .ctop.top.bar.findtype \
                          findtype Exact IgnCase Regexp]
     pack $fstring -side left -expand 1 -fill x
     set findtype Exact
     set findtypemenu [tk_optionMenu .ctop.top.bar.findtype \
                          findtype Exact IgnCase Regexp]
+    .ctop.top.bar.findtype configure -font $uifont
+    .ctop.top.bar.findtype.menu configure -font $uifont
     set findloc "All fields"
     tk_optionMenu .ctop.top.bar.findloc findloc "All fields" Headline \
        Comments Author Committer Files Pickaxe
     set findloc "All fields"
     tk_optionMenu .ctop.top.bar.findloc findloc "All fields" Headline \
        Comments Author Committer Files Pickaxe
+    .ctop.top.bar.findloc configure -font $uifont
+    .ctop.top.bar.findloc.menu configure -font $uifont
+
     pack .ctop.top.bar.findloc -side right
     pack .ctop.top.bar.findtype -side right
     # for making sure type==Exact whenever loc==Pickaxe
     pack .ctop.top.bar.findloc -side right
     pack .ctop.top.bar.findtype -side right
     # for making sure type==Exact whenever loc==Pickaxe
@@ -510,7 +516,7 @@ proc makewindow {} {
     frame .ctop.cdet.right
     set cflist .ctop.cdet.right.cfiles
     listbox $cflist -bg white -selectmode extended -width $geometry(cflistw) \
     frame .ctop.cdet.right
     set cflist .ctop.cdet.right.cfiles
     listbox $cflist -bg white -selectmode extended -width $geometry(cflistw) \
-       -yscrollcommand ".ctop.cdet.right.sb set"
+       -yscrollcommand ".ctop.cdet.right.sb set" -font $mainfont
     scrollbar .ctop.cdet.right.sb -command "$cflist yview"
     pack .ctop.cdet.right.sb -side right -fill y
     pack $cflist -side left -fill both -expand 1
     scrollbar .ctop.cdet.right.sb -command "$cflist yview"
     pack .ctop.cdet.right.sb -side right -fill y
     pack $cflist -side left -fill both -expand 1
@@ -525,12 +531,20 @@ proc makewindow {} {
     bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
     bindall <2> "canvscan mark %W %x %y"
     bindall <B2-Motion> "canvscan dragto %W %x %y"
     bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
     bindall <2> "canvscan mark %W %x %y"
     bindall <B2-Motion> "canvscan dragto %W %x %y"
+    bindkey <Home> selfirstline
+    bindkey <End> sellastline
     bind . <Key-Up> "selnextline -1"
     bind . <Key-Down> "selnextline 1"
     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-Right> "goforw"
+    bindkey <Key-Left> "goback"
+    bind . <Key-Prior> "selnextpage -1"
+    bind . <Key-Next> "selnextpage 1"
+    bind . <Control-Home> "allcanvs yview moveto 0.0"
+    bind . <Control-End> "allcanvs yview moveto 1.0"
+    bind . <Control-Key-Up> "allcanvs yview scroll -1 units"
+    bind . <Control-Key-Down> "allcanvs yview scroll 1 units"
+    bind . <Control-Key-Prior> "allcanvs yview scroll -1 pages"
+    bind . <Control-Key-Next> "allcanvs yview scroll 1 pages"
     bindkey <Key-Delete> "$ctext yview scroll -1 pages"
     bindkey <Key-BackSpace> "$ctext yview scroll -1 pages"
     bindkey <Key-space> "$ctext yview scroll 1 pages"
     bindkey <Key-Delete> "$ctext yview scroll -1 pages"
     bindkey <Key-BackSpace> "$ctext yview scroll -1 pages"
     bindkey <Key-space> "$ctext yview scroll 1 pages"
@@ -623,9 +637,10 @@ proc click {w} {
 }
 
 proc savestuff {w} {
 }
 
 proc savestuff {w} {
-    global canv canv2 canv3 ctext cflist mainfont textfont
+    global canv canv2 canv3 ctext cflist mainfont textfont uifont
     global stuffsaved findmergefiles maxgraphpct
     global maxwidth
     global stuffsaved findmergefiles maxgraphpct
     global maxwidth
+    global viewname viewfiles viewperm nextviewnum
 
     if {$stuffsaved} return
     if {![winfo viewable .]} return
 
     if {$stuffsaved} return
     if {![winfo viewable .]} return
@@ -633,6 +648,7 @@ proc savestuff {w} {
        set f [open "~/.gitk-new" w]
        puts $f [list set mainfont $mainfont]
        puts $f [list set textfont $textfont]
        set f [open "~/.gitk-new" w]
        puts $f [list set mainfont $mainfont]
        puts $f [list set textfont $textfont]
+       puts $f [list set uifont $uifont]
        puts $f [list set findmergefiles $findmergefiles]
        puts $f [list set maxgraphpct $maxgraphpct]
        puts $f [list set maxwidth $maxwidth]
        puts $f [list set findmergefiles $findmergefiles]
        puts $f [list set maxgraphpct $maxgraphpct]
        puts $f [list set maxwidth $maxwidth]
@@ -648,6 +664,13 @@ proc savestuff {w} {
        set wid [expr {([winfo width $cflist] - 11) \
                           / [font measure [$cflist cget -font] "0"]}]
        puts $f "set geometry(cflistw) $wid"
        set wid [expr {([winfo width $cflist] - 11) \
                           / [font measure [$cflist cget -font] "0"]}]
        puts $f "set geometry(cflistw) $wid"
+       puts -nonewline $f "set permviews {"
+       for {set v 0} {$v < $nextviewnum} {incr v} {
+           if {$viewperm($v)} {
+               puts $f "{[list $viewname($v) $viewfiles($v)]}"
+           }
+       }
+       puts $f "}"
        close $f
        file rename -force "~/.gitk-new" "~/.gitk"
     }
        close $f
        file rename -force "~/.gitk-new" "~/.gitk"
     }
@@ -740,28 +763,109 @@ Use and redistribute under the terms of the GNU General Public License} \
     pack $w.ok -side bottom
 }
 
     pack $w.ok -side bottom
 }
 
+proc keys {} {
+    set w .keys
+    if {[winfo exists $w]} {
+       raise $w
+       return
+    }
+    toplevel $w
+    wm title $w "Gitk key bindings"
+    message $w.m -text {
+Gitk key bindings:
+
+<Ctrl-Q>               Quit
+<Home>         Move to first commit
+<End>          Move to last commit
+<Up>, p, i     Move up one commit
+<Down>, n, k   Move down one commit
+<Left>, z, j   Go back in history list
+<Right>, x, l  Go forward in history list
+<PageUp>       Move up one page in commit list
+<PageDown>     Move down one page in commit list
+<Ctrl-Home>    Scroll to top of commit list
+<Ctrl-End>     Scroll to bottom of commit list
+<Ctrl-Up>      Scroll commit list up one line
+<Ctrl-Down>    Scroll commit list down one line
+<Ctrl-PageUp>  Scroll commit list up one page
+<Ctrl-PageDown>        Scroll commit list down one page
+<Delete>, b    Scroll diff view up one page
+<Backspace>    Scroll diff view up one page
+<Space>                Scroll diff view down one page
+u              Scroll diff view up 18 lines
+d              Scroll diff view down 18 lines
+<Ctrl-F>               Find
+<Ctrl-G>               Move to next find hit
+<Ctrl-R>               Move to previous find hit
+<Return>       Move to next find hit
+/              Move to next find hit, or redo find
+?              Move to previous find hit
+f              Scroll diff view to next file
+<Ctrl-KP+>     Increase font size
+<Ctrl-plus>    Increase font size
+<Ctrl-KP->     Decrease font size
+<Ctrl-minus>   Decrease font size
+} \
+           -justify left -bg white -border 2 -relief sunken
+    pack $w.m -side top -fill both
+    button $w.ok -text Close -command "destroy $w"
+    pack $w.ok -side bottom
+}
+
 proc newview {} {
 proc newview {} {
-    global newviewname nextviewnum newviewtop
+    global nextviewnum newviewname newviewperm uifont
 
     set top .gitkview
     if {[winfo exists $top]} {
        raise $top
        return
     }
 
     set top .gitkview
     if {[winfo exists $top]} {
        raise $top
        return
     }
-    set newviewtop $top
+    set newviewname($nextviewnum) "View $nextviewnum"
+    set newviewperm($nextviewnum) 0
+    vieweditor $top $nextviewnum "Gitk view definition" 
+}
+
+proc editview {} {
+    global curview
+    global viewname viewperm newviewname newviewperm
+
+    set top .gitkvedit-$curview
+    if {[winfo exists $top]} {
+       raise $top
+       return
+    }
+    set newviewname($curview) $viewname($curview)
+    set newviewperm($curview) $viewperm($curview)
+    vieweditor $top $curview "Gitk: edit view $viewname($curview)"
+}
+
+proc vieweditor {top n title} {
+    global newviewname newviewperm viewfiles
+    global uifont
+
     toplevel $top
     toplevel $top
-    wm title $top "Gitk view definition"
-    label $top.nl -text "Name"
-    entry $top.name -width 20 -textvariable newviewname
-    set newviewname "View $nextviewnum"
-    grid $top.nl $top.name -sticky w
-    label $top.l -text "Files and directories to include:"
-    grid $top.l - -sticky w -pady 10
-    text $top.t -width 30 -height 10
-    grid $top.t - -sticky w
+    wm title $top $title
+    label $top.nl -text "Name" -font $uifont
+    entry $top.name -width 20 -textvariable newviewname($n)
+    grid $top.nl $top.name -sticky w -pady 5
+    checkbutton $top.perm -text "Remember this view" -variable newviewperm($n)
+    grid $top.perm - -pady 5 -sticky w
+    message $top.l -aspect 500 -font $uifont \
+       -text "Enter files and directories to include, one per line:"
+    grid $top.l - -sticky w
+    text $top.t -width 40 -height 10 -background white
+    if {[info exists viewfiles($n)]} {
+       foreach f $viewfiles($n) {
+           $top.t insert end $f
+           $top.t insert end "\n"
+       }
+       $top.t delete {end - 1c} end
+       $top.t mark set insert 0.0
+    }
+    grid $top.t - -sticky w -padx 5
     frame $top.buts
     frame $top.buts
-    button $top.buts.ok -text "OK" -command newviewok
-    button $top.buts.can -text "Cancel" -command newviewcan
+    button $top.buts.ok -text "OK" -command [list newviewok $top $n]
+    button $top.buts.can -text "Cancel" -command [list destroy $top]
     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.ok $top.buts.can
     grid columnconfigure $top.buts 0 -weight 1 -uniform a
     grid columnconfigure $top.buts 1 -weight 1 -uniform a
@@ -769,50 +873,89 @@ proc newview {} {
     focus $top.t
 }
 
     focus $top.t
 }
 
-proc newviewok {} {
-    global newviewtop nextviewnum
-    global viewname viewfiles
+proc viewmenuitem {n} {
+    set nmenu [.bar.view index end]
+    set targetcmd [list showview $n]
+    for {set i 6} {$i <= $nmenu} {incr i} {
+       if {[.bar.view entrycget $i -command] eq $targetcmd} {
+           return $i
+       }
+    }
+    return {}
+}
+
+proc newviewok {top n} {
+    global nextviewnum newviewperm newviewname
+    global viewname viewfiles viewperm selectedview curview
 
 
-    set n $nextviewnum
-    incr nextviewnum
-    set viewname($n) [$newviewtop.name get]
     set files {}
     set files {}
-    foreach f [split [$newviewtop.t get 0.0 end] "\n"] {
+    foreach f [split [$top.t get 0.0 end] "\n"] {
        set ft [string trim $f]
        if {$ft ne {}} {
            lappend files $ft
        }
     }
        set ft [string trim $f]
        if {$ft ne {}} {
            lappend files $ft
        }
     }
-    set viewfiles($n) $files
-    catch {destroy $newviewtop}
-    unset newviewtop
-    .bar.view add command -label $viewname($n) -command [list showview $n]
-    after idle showview $n
-}
-
-proc newviewcan {} {
-    global newviewtop
-
-    catch {destroy $newviewtop}
-    unset newviewtop
+    if {![info exists viewfiles($n)]} {
+       # creating a new view
+       incr nextviewnum
+       set viewname($n) $newviewname($n)
+       set viewperm($n) $newviewperm($n)
+       set viewfiles($n) $files
+       .bar.view add radiobutton -label $viewname($n) \
+           -command [list showview $n] -variable selectedview -value $n
+       after idle showview $n
+    } else {
+       # editing an existing view
+       set viewperm($n) $newviewperm($n)
+       if {$newviewname($n) ne $viewname($n)} {
+           set viewname($n) $newviewname($n)
+           set i [viewmenuitem $n]
+           if {$i ne {}} {
+               .bar.view entryconf $i -label $viewname($n)
+           }
+       }
+       if {$files ne $viewfiles($n)} {
+           set viewfiles($n) $files
+           if {$curview == $n} {
+               after idle updatecommits
+           }
+       }
+    }
+    catch {destroy $top}
 }
 
 proc delview {} {
 }
 
 proc delview {} {
-    global curview viewdata
+    global curview viewdata viewperm
 
     if {$curview == 0} return
 
     if {$curview == 0} return
-    set nmenu [.bar.view index end]
-    set targetcmd [list showview $curview]
-    for {set i 5} {$i <= $nmenu} {incr i} {
-       if {[.bar.view entrycget $i -command] eq $targetcmd} {
-           .bar.view delete $i
-           break
-       }
+    set i [viewmenuitem $curview]
+    if {$i ne {}} {
+       .bar.view delete $i
     }
     set viewdata($curview) {}
     }
     set viewdata($curview) {}
+    set viewperm($curview) 0
     showview 0
 }
 
     showview 0
 }
 
+proc flatten {var} {
+    global $var
+
+    set ret {}
+    foreach i [array names $var] {
+       lappend ret $i [set $var\($i\)]
+    }
+    return $ret
+}
+
+proc unflatten {var l} {
+    global $var
+
+    catch {unset $var}
+    foreach {i v} $l {
+       set $var\($i\) $v
+    }
+}
+
 proc showview {n} {
     global curview viewdata viewfiles
     global displayorder parentlist childlist rowidlist rowoffsets
 proc showview {n} {
     global curview viewdata viewfiles
     global displayorder parentlist childlist rowidlist rowoffsets
@@ -820,8 +963,10 @@ proc showview {n} {
     global numcommits rowrangelist commitlisted idrowranges
     global selectedline currentid canv canvy0
     global matchinglines treediffs
     global numcommits rowrangelist commitlisted idrowranges
     global selectedline currentid canv canvy0
     global matchinglines treediffs
-    global parsed_args
     global pending_select phase
     global pending_select phase
+    global commitidx rowlaidout rowoptim linesegends leftover
+    global commfd nextupdate
+    global selectedview
 
     if {$n == $curview} return
     set selid {}
 
     if {$n == $curview} return
     set selid {}
@@ -839,42 +984,71 @@ proc showview {n} {
        }
     }
     unselectline
        }
     }
     unselectline
+    normalline
     stopfindproc
     stopfindproc
-    if {$curview >= 0 && $phase eq {} && ![info exists viewdata($curview)]} {
-       set viewdata($curview) \
-           [list $displayorder $parentlist $childlist $rowidlist \
-                $rowoffsets $rowrangelist $commitlisted]
+    if {$curview >= 0} {
+       if {$phase ne {}} {
+           set viewdata($curview) \
+               [list $phase $displayorder $parentlist $childlist $rowidlist \
+                    $rowoffsets $rowrangelist $commitlisted \
+                    [flatten children] [flatten idrowranges] \
+                    [flatten idinlist] \
+                    $commitidx $rowlaidout $rowoptim $numcommits \
+                    $linesegends $leftover $commfd]
+           fileevent $commfd readable {}
+       } elseif {![info exists viewdata($curview)]
+                 || [lindex $viewdata($curview) 0] ne {}} {
+           set viewdata($curview) \
+               [list {} $displayorder $parentlist $childlist $rowidlist \
+                    $rowoffsets $rowrangelist $commitlisted]
+       }
     }
     catch {unset matchinglines}
     catch {unset treediffs}
     clear_display
     }
     catch {unset matchinglines}
     catch {unset treediffs}
     clear_display
-    readrefs
 
     set curview $n
 
     set curview $n
+    set selectedview $n
     .bar.view entryconf 2 -state [expr {$n == 0? "disabled": "normal"}]
     .bar.view entryconf 2 -state [expr {$n == 0? "disabled": "normal"}]
+    .bar.view entryconf 3 -state [expr {$n == 0? "disabled": "normal"}]
 
     if {![info exists viewdata($n)]} {
 
     if {![info exists viewdata($n)]} {
-       set args $parsed_args
-       if {$viewfiles($n) ne {}} {
-           set args [concat $args "--" $viewfiles($n)]
-       }
        set pending_select $selid
        set pending_select $selid
-       getcommits $args 
+       getcommits
        return
     }
 
        return
     }
 
-    set displayorder [lindex $viewdata($n) 0]
-    set parentlist [lindex $viewdata($n) 1]
-    set childlist [lindex $viewdata($n) 2]
-    set rowidlist [lindex $viewdata($n) 3]
-    set rowoffsets [lindex $viewdata($n) 4]
-    set rowrangelist [lindex $viewdata($n) 5]
-    set commitlisted [lindex $viewdata($n) 6]
-    set numcommits [llength $displayorder]
+    set v $viewdata($n)
+    set phase [lindex $v 0]
+    set displayorder [lindex $v 1]
+    set parentlist [lindex $v 2]
+    set childlist [lindex $v 3]
+    set rowidlist [lindex $v 4]
+    set rowoffsets [lindex $v 5]
+    set rowrangelist [lindex $v 6]
+    set commitlisted [lindex $v 7]
+    if {$phase eq {}} {
+       set numcommits [llength $displayorder]
+       catch {unset idrowranges}
+       catch {unset children}
+    } else {
+       unflatten children [lindex $v 8]
+       unflatten idrowranges [lindex $v 9]
+       unflatten idinlist [lindex $v 10]
+       set commitidx [lindex $v 11]
+       set rowlaidout [lindex $v 12]
+       set rowoptim [lindex $v 13]
+       set numcommits [lindex $v 14]
+       set linesegends [lindex $v 15]
+       set leftover [lindex $v 16]
+       set commfd [lindex $v 17]
+       fileevent $commfd readable [list getcommitlines $commfd]
+       set nextupdate [expr {[clock clicks -milliseconds] + 100}]
+    }
+
     catch {unset colormap}
     catch {unset rowtextx}
     catch {unset commitrow}
     catch {unset colormap}
     catch {unset rowtextx}
     catch {unset commitrow}
-    catch {unset idrowranges}
     set curview $n
     set row 0
     foreach id $displayorder {
     set curview $n
     set row 0
     foreach id $displayorder {
@@ -897,6 +1071,19 @@ proc showview {n} {
     allcanvs yview moveto $yf
     drawvisible
     selectline $row 0
     allcanvs yview moveto $yf
     drawvisible
     selectline $row 0
+    if {$phase eq {}} {
+       global maincursor textcursor
+       . config -cursor $maincursor
+       settextcursor $textcursor
+    } else {
+       . config -cursor watch
+       settextcursor watch
+       if {$phase eq "getcommits"} {
+           global mainfont
+           $canv create text 3 3 -anchor nw -text "Reading commits..." \
+               -font $mainfont -tags textitems
+       }
+    }
 }
 
 proc shortids {ids} {
 }
 
 proc shortids {ids} {
@@ -934,20 +1121,21 @@ proc ntimes {n o} {
 }
 
 proc usedinrange {id l1 l2} {
 }
 
 proc usedinrange {id l1 l2} {
-    global children commitrow
+    global children commitrow childlist
 
     if {[info exists commitrow($id)]} {
        set r $commitrow($id)
        if {$l1 <= $r && $r <= $l2} {
            return [expr {$r - $l1 + 1}]
        }
 
     if {[info exists commitrow($id)]} {
        set r $commitrow($id)
        if {$l1 <= $r && $r <= $l2} {
            return [expr {$r - $l1 + 1}]
        }
+       set kids [lindex $childlist $r]
+    } else {
+       set kids $children($id)
     }
     }
-    foreach c $children($id) {
-       if {[info exists commitrow($c)]} {
-           set r $commitrow($c)
-           if {$l1 <= $r && $r <= $l2} {
-               return [expr {$r - $l1 + 1}]
-           }
+    foreach c $kids {
+       set r $commitrow($c)
+       if {$l1 <= $r && $r <= $l2} {
+           return [expr {$r - $l1 + 1}]
        }
     }
     return 0
        }
     }
     return 0
@@ -1042,7 +1230,7 @@ proc initlayout {} {
     catch {unset rowtextx}
     catch {unset commitrow}
     catch {unset idrowranges}
     catch {unset rowtextx}
     catch {unset commitrow}
     catch {unset idrowranges}
-    catch {unset linesegends}
+    set linesegends {}
 }
 
 proc setcanvscroll {} {
 }
 
 proc setcanvscroll {} {
@@ -1091,7 +1279,7 @@ proc layoutmore {} {
 }
 
 proc showstuff {canshow} {
 }
 
 proc showstuff {canshow} {
-    global numcommits commitrow pending_select
+    global numcommits commitrow pending_select selectedline
     global linesegends idrowranges idrangedrawn
 
     if {$numcommits == 0} {
     global linesegends idrowranges idrangedrawn
 
     if {$numcommits == 0} {
@@ -1107,16 +1295,14 @@ proc showstuff {canshow} {
     set r1 [lindex $rows 1]
     set selrow -1
     for {set r $row} {$r < $canshow} {incr r} {
     set r1 [lindex $rows 1]
     set selrow -1
     for {set r $row} {$r < $canshow} {incr r} {
-       if {[info exists linesegends($r)]} {
-           foreach id $linesegends($r) {
-               set i -1
-               foreach {s e} $idrowranges($id) {
-                   incr i
-                   if {$e ne {} && $e < $numcommits && $s <= $r1 && $e >= $r0
-                       && ![info exists idrangedrawn($id,$i)]} {
-                       drawlineseg $id $i
-                       set idrangedrawn($id,$i) 1
-                   }
+       foreach id [lindex $linesegends [expr {$r+1}]] {
+           set i -1
+           foreach {s e} [rowranges $id] {
+               incr i
+               if {$e ne {} && $e < $numcommits && $s <= $r1 && $e >= $r0
+                   && ![info exists idrangedrawn($id,$i)]} {
+                   drawlineseg $id $i
+                   set idrangedrawn($id,$i) 1
                }
            }
        }
                }
            }
        }
@@ -1133,6 +1319,9 @@ proc showstuff {canshow} {
        $commitrow($pending_select) < $numcommits} {
        selectline $commitrow($pending_select) 1
     }
        $commitrow($pending_select) < $numcommits} {
        selectline $commitrow($pending_select) 1
     }
+    if {![info exists selectedline] && ![info exists pending_select]} {
+       selectline 0 1
+    }
 }
 
 proc layoutrows {row endrow last} {
 }
 
 proc layoutrows {row endrow last} {
@@ -1156,6 +1345,7 @@ proc layoutrows {row endrow last} {
                lappend oldolds $p
            }
        }
                lappend oldolds $p
            }
        }
+       set lse {}
        set nev [expr {[llength $idlist] + [llength $newolds]
                       + [llength $oldolds] - $maxwidth + 1}]
        if {$nev > 0} {
        set nev [expr {[llength $idlist] + [llength $newolds]
                       + [llength $oldolds] - $maxwidth + 1}]
        if {$nev > 0} {
@@ -1171,7 +1361,7 @@ proc layoutrows {row endrow last} {
                        set offs [incrange $offs $x 1]
                        set idinlist($i) 0
                        set rm1 [expr {$row - 1}]
                        set offs [incrange $offs $x 1]
                        set idinlist($i) 0
                        set rm1 [expr {$row - 1}]
-                       lappend linesegends($rm1) $i
+                       lappend lse $i
                        lappend idrowranges($i) $rm1
                        if {[incr nev -1] <= 0} break
                        continue
                        lappend idrowranges($i) $rm1
                        if {[incr nev -1] <= 0} break
                        continue
@@ -1182,6 +1372,7 @@ proc layoutrows {row endrow last} {
            lset rowidlist $row $idlist
            lset rowoffsets $row $offs
        }
            lset rowidlist $row $idlist
            lset rowoffsets $row $offs
        }
+       lappend linesegends $lse
        set col [lsearch -exact $idlist $id]
        if {$col < 0} {
            set col [llength $idlist]
        set col [lsearch -exact $idlist $id]
        if {$col < 0} {
            set col [llength $idlist]
@@ -1202,8 +1393,9 @@ proc layoutrows {row endrow last} {
        }
        set ranges {}
        if {[info exists idrowranges($id)]} {
        }
        set ranges {}
        if {[info exists idrowranges($id)]} {
-           lappend idrowranges($id) $row
            set ranges $idrowranges($id)
            set ranges $idrowranges($id)
+           lappend ranges $row
+           unset idrowranges($id)
        }
        lappend rowrangelist $ranges
        incr row
        }
        lappend rowrangelist $ranges
        incr row
@@ -1245,11 +1437,12 @@ proc layoutrows {row endrow last} {
 
 proc addextraid {id row} {
     global displayorder commitrow commitinfo
 
 proc addextraid {id row} {
     global displayorder commitrow commitinfo
-    global commitidx
+    global commitidx commitlisted
     global parentlist childlist children
 
     incr commitidx
     lappend displayorder $id
     global parentlist childlist children
 
     incr commitidx
     lappend displayorder $id
+    lappend commitlisted 0
     lappend parentlist {}
     set commitrow($id) $row
     readcommit $id
     lappend parentlist {}
     set commitrow($id) $row
     readcommit $id
@@ -1258,6 +1451,7 @@ proc addextraid {id row} {
     }
     if {[info exists children($id)]} {
        lappend childlist $children($id)
     }
     if {[info exists children($id)]} {
        lappend childlist $children($id)
+       unset children($id)
     } else {
        lappend childlist {}
     }
     } else {
        lappend childlist {}
     }
@@ -1276,6 +1470,7 @@ proc layouttail {} {
        unset idinlist($id)
        lappend idrowranges($id) $row
        lappend rowrangelist $idrowranges($id)
        unset idinlist($id)
        lappend idrowranges($id) $row
        lappend rowrangelist $idrowranges($id)
+       unset idrowranges($id)
        incr row
        set offs [ntimes $col 0]
        set idlist [lreplace $idlist $col $col]
        incr row
        set offs [ntimes $col 0]
        set idlist [lreplace $idlist $col $col]
@@ -1290,6 +1485,7 @@ proc layouttail {} {
        makeuparrow $id 0 $row 0
        lappend idrowranges($id) $row
        lappend rowrangelist $idrowranges($id)
        makeuparrow $id 0 $row 0
        lappend idrowranges($id) $row
        lappend rowrangelist $idrowranges($id)
+       unset idrowranges($id)
        incr row
        lappend rowidlist {}
        lappend rowoffsets {}
        incr row
        lappend rowidlist {}
        lappend rowoffsets {}
@@ -1325,8 +1521,8 @@ proc optimize_rows {row col endrow} {
            set z0 [lindex $rowoffsets $y0 $x0]
            if {$z0 eq {}} {
                set id [lindex $idlist $col]
            set z0 [lindex $rowoffsets $y0 $x0]
            if {$z0 eq {}} {
                set id [lindex $idlist $col]
-               if {[info exists idrowranges($id)] &&
-                   $y0 > [lindex $idrowranges($id) 0]} {
+               set ranges [rowranges $id]
+               if {$ranges ne {} && $y0 > [lindex $ranges 0]} {
                    set isarrow 1
                }
            }
                    set isarrow 1
                }
            }
@@ -1384,8 +1580,8 @@ proc optimize_rows {row col endrow} {
                if {$o eq {}} {
                    # check if this is the link to the first child
                    set id [lindex $idlist $col]
                if {$o eq {}} {
                    # check if this is the link to the first child
                    set id [lindex $idlist $col]
-                   if {[info exists idrowranges($id)] &&
-                       $row == [lindex $idrowranges($id) 0]} {
+                   set ranges [rowranges $id]
+                   if {$ranges ne {} && $row == [lindex $ranges 0]} {
                        # it is, work out offset to child
                        set y0 [expr {$row - 1}]
                        set id [lindex $displayorder $y0]
                        # it is, work out offset to child
                        set y0 [expr {$row - 1}]
                        set id [lindex $displayorder $y0]
@@ -1440,10 +1636,11 @@ proc linewidth {id} {
 }
 
 proc rowranges {id} {
 }
 
 proc rowranges {id} {
-    global idrowranges commitrow numcommits rowrangelist
+    global phase idrowranges commitrow rowlaidout rowrangelist
 
     set ranges {}
 
     set ranges {}
-    if {[info exists commitrow($id)] && $commitrow($id) < $numcommits} {
+    if {$phase eq {} ||
+       ([info exists commitrow($id)] && $commitrow($id) < $rowlaidout)} {
        set ranges [lindex $rowrangelist $commitrow($id)]
     } elseif {[info exists idrowranges($id)]} {
        set ranges $idrowranges($id)
        set ranges [lindex $rowrangelist $commitrow($id)]
     } elseif {[info exists idrowranges($id)]} {
        set ranges $idrowranges($id)
@@ -1650,10 +1847,11 @@ proc drawcmittext {id row col rmx} {
 proc drawcmitrow {row} {
     global displayorder rowidlist
     global idrangedrawn iddrawn
 proc drawcmitrow {row} {
     global displayorder rowidlist
     global idrangedrawn iddrawn
-    global commitinfo commitlisted parentlist numcommits
+    global commitinfo parentlist numcommits
 
     if {$row >= $numcommits} return
     foreach id [lindex $rowidlist $row] {
 
     if {$row >= $numcommits} return
     foreach id [lindex $rowidlist $row] {
+       if {$id eq {}} continue
        set i -1
        foreach {s e} [rowranges $id] {
            incr i
        set i -1
        foreach {s e} [rowranges $id] {
            incr i
@@ -1896,6 +2094,14 @@ proc drawtags {id x xt y1} {
            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
            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
+           if {[regexp {^(remotes/.*/|remotes/)} $tag match remoteprefix]} {
+               set rwid [font measure $mainfont $remoteprefix]
+               set xi [expr {$x + 1}]
+               set yti [expr {$yt + 1}]
+               set xri [expr {$x + $rwid}]
+               $canv create polygon $xi $yti $xri $yti $xri $yb $xi $yb \
+                       -width 0 -fill "#ffddaa" -tags tag.$id
+           }
        }
        set t [$canv create text $xl $y1 -anchor w -text $tag \
                   -font $mainfont -tags tag.$id]
        }
        set t [$canv create text $xl $y1 -anchor w -text $tag \
                   -font $mainfont -tags tag.$id]
@@ -1921,7 +2127,7 @@ proc xcoord {i level ln} {
 proc finishcommits {} {
     global commitidx phase
     global canv mainfont ctext maincursor textcursor
 proc finishcommits {} {
     global commitidx phase
     global canv mainfont ctext maincursor textcursor
-    global findinprogress
+    global findinprogress pending_select
 
     if {$commitidx > 0} {
        drawrest
 
     if {$commitidx > 0} {
        drawrest
@@ -1935,6 +2141,7 @@ proc finishcommits {} {
        settextcursor $textcursor
     }
     set phase {}
        settextcursor $textcursor
     }
     set phase {}
+    catch {unset pending_select}
 }
 
 # Don't change the text pane cursor if it is currently the hand cursor,
 }
 
 # Don't change the text pane cursor if it is currently the hand cursor,
@@ -1953,12 +2160,16 @@ proc drawrest {} {
     global startmsecs
     global canvy0 numcommits linespc
     global rowlaidout commitidx
     global startmsecs
     global canvy0 numcommits linespc
     global rowlaidout commitidx
+    global pending_select
 
     set row $rowlaidout
     layoutrows $rowlaidout $commitidx 1
     layouttail
     optimize_rows $row 0 $commitidx
     showstuff $commitidx
 
     set row $rowlaidout
     layoutrows $rowlaidout $commitidx 1
     layouttail
     optimize_rows $row 0 $commitidx
     showstuff $commitidx
+    if {[info exists pending_select]} {
+       selectline 0 1
+    }
 
     set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}]
     #puts "overall $drawmsecs ms for $numcommits commits"
 
     set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}]
     #puts "overall $drawmsecs ms for $numcommits commits"
@@ -2148,7 +2359,7 @@ proc stopfindproc {{done 0}} {
     }
     if {[info exists findinprogress]} {
        unset findinprogress
     }
     if {[info exists findinprogress]} {
        unset findinprogress
-       if {$phase != "incrdraw"} {
+       if {$phase eq {}} {
            . config -cursor $maincursor
            settextcursor $textcursor
        }
            . config -cursor $maincursor
            settextcursor $textcursor
        }
@@ -2487,6 +2698,22 @@ proc appendwithlinks {text} {
     $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
 }
 
     $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
 }
 
+proc viewnextline {dir} {
+    global canv linespc
+
+    $canv delete hover
+    set ymax [lindex [$canv cget -scrollregion] 3]
+    set wnow [$canv yview]
+    set wtop [expr {[lindex $wnow 0] * $ymax}]
+    set newtop [expr {$wtop + $dir * $linespc}]
+    if {$newtop < 0} {
+       set newtop 0
+    } elseif {$newtop > $ymax} {
+       set newtop $ymax
+    }
+    allcanvs yview moveto [expr {$newtop * 1.0 / $ymax}]
+}
+
 proc selectline {l isnew} {
     global canv canv2 canv3 ctext commitinfo selectedline
     global displayorder linehtag linentag linedtag
 proc selectline {l isnew} {
     global canv canv2 canv3 ctext commitinfo selectedline
     global displayorder linehtag linentag linedtag
@@ -2623,6 +2850,18 @@ proc selectline {l isnew} {
     }
 }
 
     }
 }
 
+proc selfirstline {} {
+    unmarkmatches
+    selectline 0 1
+}
+
+proc sellastline {} {
+    global numcommits
+    unmarkmatches
+    set l [expr {$numcommits - 1}]
+    selectline $l 1
+}
+
 proc selnextline {dir} {
     global selectedline
     if {![info exists selectedline]} return
 proc selnextline {dir} {
     global selectedline
     if {![info exists selectedline]} return
@@ -2631,6 +2870,25 @@ proc selnextline {dir} {
     selectline $l 1
 }
 
     selectline $l 1
 }
 
+proc selnextpage {dir} {
+    global canv linespc selectedline numcommits
+
+    set lpp [expr {([winfo height $canv] - 2) / $linespc}]
+    if {$lpp < 1} {
+       set lpp 1
+    }
+    allcanvs yview scroll [expr {$dir * $lpp}] units
+    if {![info exists selectedline]} return
+    set l [expr {$selectedline + $dir * $lpp}]
+    if {$l < 0} {
+       set l 0
+    } elseif {$l >= $numcommits} {
+        set l [expr $numcommits - 1]
+    }
+    unmarkmatches
+    selectline $l 1    
+}
+
 proc unselectline {} {
     global selectedline currentid
 
 proc unselectline {} {
     global selectedline currentid
 
@@ -2640,17 +2898,18 @@ proc unselectline {} {
 }
 
 proc addtohistory {cmd} {
 }
 
 proc addtohistory {cmd} {
-    global history historyindex
+    global history historyindex curview
 
 
+    set elt [list $curview $cmd]
     if {$historyindex > 0
     if {$historyindex > 0
-       && [lindex $history [expr {$historyindex - 1}]] == $cmd} {
+       && [lindex $history [expr {$historyindex - 1}]] == $elt} {
        return
     }
 
     if {$historyindex < [llength $history]} {
        return
     }
 
     if {$historyindex < [llength $history]} {
-       set history [lreplace $history $historyindex end $cmd]
+       set history [lreplace $history $historyindex end $elt]
     } else {
     } else {
-       lappend history $cmd
+       lappend history $elt
     }
     incr historyindex
     if {$historyindex > 1} {
     }
     incr historyindex
     if {$historyindex > 1} {
@@ -2661,13 +2920,23 @@ proc addtohistory {cmd} {
     .ctop.top.bar.rightbut conf -state disabled
 }
 
     .ctop.top.bar.rightbut conf -state disabled
 }
 
+proc godo {elt} {
+    global curview
+
+    set view [lindex $elt 0]
+    set cmd [lindex $elt 1]
+    if {$curview != $view} {
+       showview $view
+    }
+    eval $cmd
+}
+
 proc goback {} {
     global history historyindex
 
     if {$historyindex > 1} {
        incr historyindex -1
 proc goback {} {
     global history historyindex
 
     if {$historyindex > 1} {
        incr historyindex -1
-       set cmd [lindex $history [expr {$historyindex - 1}]]
-       eval $cmd
+       godo [lindex $history [expr {$historyindex - 1}]]
        .ctop.top.bar.rightbut conf -state normal
     }
     if {$historyindex <= 1} {
        .ctop.top.bar.rightbut conf -state normal
     }
     if {$historyindex <= 1} {
@@ -2681,7 +2950,7 @@ proc goforw {} {
     if {$historyindex < [llength $history]} {
        set cmd [lindex $history $historyindex]
        incr historyindex
     if {$historyindex < [llength $history]} {
        set cmd [lindex $history $historyindex]
        incr historyindex
-       eval $cmd
+       godo $cmd
        .ctop.top.bar.leftbut conf -state normal
     }
     if {$historyindex >= [llength $history]} {
        .ctop.top.bar.leftbut conf -state normal
     }
     if {$historyindex >= [llength $history]} {
@@ -3017,7 +3286,7 @@ proc incrfont {inc} {
     foreach e $entries {
        $e conf -font $mainfont
     }
     foreach e $entries {
        $e conf -font $mainfont
     }
-    if {$phase == "getcommits"} {
+    if {$phase eq "getcommits"} {
        $canv itemconf textitems -font $mainfont
     }
     redisplay
        $canv itemconf textitems -font $mainfont
     }
     redisplay
@@ -3047,13 +3316,15 @@ proc sha1change {n1 n2 op} {
 }
 
 proc gotocommit {} {
 }
 
 proc gotocommit {} {
-    global sha1string currentid commitrow tagids
+    global sha1string currentid commitrow tagids headids
     global displayorder numcommits
 
     if {$sha1string == {}
        || ([info exists currentid] && $sha1string == $currentid)} return
     if {[info exists tagids($sha1string)]} {
        set id $tagids($sha1string)
     global displayorder numcommits
 
     if {$sha1string == {}
        || ([info exists currentid] && $sha1string == $currentid)} return
     if {[info exists tagids($sha1string)]} {
        set id $tagids($sha1string)
+    } elseif {[info exists headids($sha1string)]} {
+       set id $headids($sha1string)
     } else {
        set id [string tolower $sha1string]
        if {[regexp {^[0-9a-f]{4,39}$} $id]} {
     } else {
        set id [string tolower $sha1string]
        if {[regexp {^[0-9a-f]{4,39}$} $id]} {
@@ -3079,7 +3350,7 @@ proc gotocommit {} {
     if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
        set type "SHA1 id"
     } else {
     if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
        set type "SHA1 id"
     } else {
-       set type "Tag"
+       set type "Tag/Head"
     }
     error_popup "$type $sha1string is not known"
 }
     }
     error_popup "$type $sha1string is not known"
 }
@@ -3571,7 +3842,6 @@ proc listrefs {id} {
 
 proc rereadrefs {} {
     global idtags idheads idotherrefs
 
 proc rereadrefs {} {
     global idtags idheads idotherrefs
-    global tagids headids otherrefids
 
     set refids [concat [array names idtags] \
                    [array names idheads] [array names idotherrefs]]
 
     set refids [concat [array names idtags] \
                    [array names idheads] [array names idotherrefs]]
@@ -3980,6 +4250,7 @@ if {$tclencoding == {}} {
 
 set mainfont {Helvetica 9}
 set textfont {Courier 9}
 
 set mainfont {Helvetica 9}
 set textfont {Courier 9}
+set uifont {Helvetica 9 bold}
 set findmergefiles 0
 set maxgraphpct 50
 set maxwidth 16
 set findmergefiles 0
 set maxgraphpct 50
 set maxwidth 16
@@ -4022,7 +4293,9 @@ set optim_delay 16
 
 set nextviewnum 1
 set curview 0
 
 set nextviewnum 1
 set curview 0
+set selectedview 0
 set viewfiles(0) {}
 set viewfiles(0) {}
+set viewperm(0) 0
 
 set stopped 0
 set stuffsaved 0
 
 set stopped 0
 set stuffsaved 0
@@ -4030,16 +4303,41 @@ set patchnum 0
 setcoords
 makewindow
 readrefs
 setcoords
 makewindow
 readrefs
-parse_args $revtreeargs
-set args $parsed_args
+
+set cmdline_files {}
+catch {
+    set fileargs [eval exec git-rev-parse --no-revs --no-flags $revtreeargs]
+    set cmdline_files [split $fileargs "\n"]
+    set n [llength $cmdline_files]
+    set revtreeargs [lrange $revtreeargs 0 end-$n]
+}
+if {[lindex $revtreeargs end] eq "--"} {
+    set revtreeargs [lrange $revtreeargs 0 end-1]
+}
+
 if {$cmdline_files ne {}} {
     # create a view for the files/dirs specified on the command line
     set curview 1
 if {$cmdline_files ne {}} {
     # create a view for the files/dirs specified on the command line
     set curview 1
+    set selectedview 1
     set nextviewnum 2
     set viewname(1) "Command line"
     set viewfiles(1) $cmdline_files
     set nextviewnum 2
     set viewname(1) "Command line"
     set viewfiles(1) $cmdline_files
-    .bar.view add command -label $viewname(1) -command {showview 1}
+    set viewperm(1) 0
+    .bar.view add radiobutton -label $viewname(1) -command {showview 1} \
+       -variable selectedview -value 1
     .bar.view entryconf 2 -state normal
     .bar.view entryconf 2 -state normal
-    set args [concat $args "--" $cmdline_files]
+    .bar.view entryconf 3 -state normal
+}
+
+if {[info exists permviews]} {
+    foreach v $permviews {
+       set n $nextviewnum
+       incr nextviewnum
+       set viewname($n) [lindex $v 0]
+       set viewfiles($n) [lindex $v 1]
+       set viewperm($n) 1
+       .bar.view add radiobutton -label $viewname($n) \
+           -command [list showview $n] -variable selectedview -value $n
+    }
 }
 }
-getcommits $args
+getcommits