gitk: Reorganize processing of arguments for git log
[gitweb.git] / gitk
diff --git a/gitk b/gitk
index a6eea5014649605fb6d11f5d56cd16229e34d93c..4f8397707021ff2fe7a2a13cf3c9afc181bd9e3c 100755 (executable)
--- a/gitk
+++ b/gitk
@@ -90,28 +90,109 @@ proc dorunq {} {
     }
 }
 
+proc unmerged_files {files} {
+    global nr_unmerged
+
+    # find the list of unmerged files
+    set mlist {}
+    set nr_unmerged 0
+    if {[catch {
+       set fd [open "| git ls-files -u" r]
+    } err]} {
+       show_error {} . "[mc "Couldn't get list of unmerged files:"] $err"
+       exit 1
+    }
+    while {[gets $fd line] >= 0} {
+       set i [string first "\t" $line]
+       if {$i < 0} continue
+       set fname [string range $line [expr {$i+1}] end]
+       if {[lsearch -exact $mlist $fname] >= 0} continue
+       incr nr_unmerged
+       if {$files eq {} || [path_filter $files $fname]} {
+           lappend mlist $fname
+       }
+    }
+    catch {close $fd}
+    return $mlist
+}
+
+proc parseviewargs {n arglist} {
+    global viewargs vdatemode vmergeonly
+
+    set vdatemode($n) 0
+    set vmergeonly($n) 0
+    set glargs {}
+    foreach arg $viewargs($n) {
+       switch -glob -- $arg {
+           "-d" -
+           "--date-order" {
+               set vdatemode($n) 1
+           }
+           "--merge" {
+               set vmergeonly($n) 1
+               lappend glargs $arg
+           }
+           default {
+               lappend glargs $arg
+           }
+       }
+    }
+    return $glargs
+}
+
 # Start off a git log process and arrange to read its output
 proc start_rev_list {view} {
-    global startmsecs
-    global commfd leftover tclencoding datemode
-    global viewargs viewfiles commitidx viewcomplete
+    global startmsecs commitidx viewcomplete
+    global commfd leftover tclencoding
+    global viewargs viewargscmd vactualargs viewfiles vfilelimit
     global showlocalchanges commitinterest mainheadid
     global progressdirn progresscoords proglastnc curview
-    global viewactive loginstance viewinstances
+    global viewactive loginstance viewinstances vmergeonly
     global pending_select mainheadid
 
     set startmsecs [clock clicks -milliseconds]
     set commitidx($view) 0
-    set viewcomplete($view) 0
-    set viewactive($view) 1
+    # these are set this way for the error exits
+    set viewcomplete($view) 1
+    set viewactive($view) 0
     varcinit $view
 
+    set args $viewargs($view)
+    if {$viewargscmd($view) ne {}} {
+       if {[catch {
+           set str [exec sh -c $viewargscmd($view)]
+       } err]} {
+           error_popup "Error executing --argscmd command: $err"
+           return 0
+       }
+       set args [concat $args [split $str "\n"]]
+    }
+    set args [parseviewargs $view $args]
+    set vactualargs($view) $args
+
+    set files $viewfiles($view)
+    if {$vmergeonly($view)} {
+       set files [unmerged_files $files]
+       if {$files eq {}} {
+           global nr_unmerged
+           if {$nr_unmerged == 0} {
+               error_popup [mc "No files selected: --merge specified but\
+                            no files are unmerged."]
+           } else {
+               error_popup [mc "No files selected: --merge specified but\
+                            no unmerged files are within file limit."]
+           }
+           return 0
+       }
+    }
+    set vfilelimit($view) $files
+
     if {[catch {
        set fd [open [concat | git log --no-color -z --pretty=raw --parents \
-                        --boundary $viewargs($view) "--" $viewfiles($view)] r]
+                        --boundary $args "--" $files] r]
     } err]} {
        error_popup "[mc "Error executing git log:"] $err"
-       exit 1
+       return 0
     }
     set i [incr loginstance]
     set viewinstances($view) [list $i]
@@ -132,6 +213,9 @@ proc start_rev_list {view} {
        set proglastnc 0
        set pending_select $mainheadid
     }
+    set viewcomplete($view) 0
+    set viewactive($view) 1
+    return 1
 }
 
 proc stop_rev_list {view} {
@@ -152,20 +236,25 @@ proc stop_rev_list {view} {
 }
 
 proc getcommits {} {
-    global canv curview need_redisplay
+    global canv curview need_redisplay viewactive
 
     initlayout
-    start_rev_list $curview
-    show_status [mc "Reading commits..."]
-    set need_redisplay 1
+    if {[start_rev_list $curview]} {
+       show_status [mc "Reading commits..."]
+       set need_redisplay 1
+    } else {
+       show_status [mc "No commits selected"]
+    }
 }
 
 proc updatecommits {} {
-    global curview viewargs viewfiles viewinstances
+    global curview vactualargs vfilelimit viewinstances
     global viewactive viewcomplete loginstance tclencoding mainheadid
     global startmsecs commfd showneartags showlocalchanges leftover
     global mainheadid pending_select
+    global isworktree
 
+    set isworktree [expr {[exec git rev-parse --is-inside-work-tree] == "true"}]
     set oldmainid $mainheadid
     rereadrefs
     if {$showlocalchanges} {
@@ -179,8 +268,8 @@ proc updatecommits {} {
     set view $curview
     if {[catch {
        set fd [open [concat | git log --no-color -z --pretty=raw --parents \
-                         --boundary $viewargs($view) --not [seeds $view] \
-                         "--" $viewfiles($view)] r]
+                         --boundary $vactualargs($view) --not [seeds $view] \
+                         "--" $vfilelimit($view)] r]
     } err]} {
        error_popup "Error executing git log: $err"
        exit 1
@@ -304,13 +393,13 @@ proc seeds {v} {
 }
 
 proc newvarc {view id} {
-    global varcid varctok parents children datemode
+    global varcid varctok parents children vdatemode
     global vupptr vdownptr vleftptr vbackptr varcrow varcix varcstart
     global commitdata commitinfo vseedcount varccommits vlastins
 
     set a [llength $varctok($view)]
     set vid $view,$id
-    if {[llength $children($vid)] == 0 || $datemode} {
+    if {[llength $children($vid)] == 0 || $vdatemode($view)} {
        if {![info exists commitinfo($id)]} {
            parsecommit $id $commitdata($id) 1
        }
@@ -410,7 +499,7 @@ proc splitvarc {p v} {
 
 proc renumbervarc {a v} {
     global parents children varctok varcstart varccommits
-    global vupptr vdownptr vleftptr vbackptr vlastins varcid vtokmod datemode
+    global vupptr vdownptr vleftptr vbackptr vlastins varcid vtokmod vdatemode
 
     set t1 [clock clicks -milliseconds]
     set todo {}
@@ -446,7 +535,7 @@ proc renumbervarc {a v} {
                                      $children($v,$id)]
        }
        set oldtok [lindex $varctok($v) $a]
-       if {!$datemode} {
+       if {!$vdatemode($v)} {
            set tok {}
        } else {
            set tok $oldtok
@@ -609,9 +698,7 @@ proc insertfakerow {id p} {
     set numcommits [incr commitidx($v)]
     # note we deliberately don't update varcstart($v) even if $i == 0
     set varccommits($v,$a) [linsert $varccommits($v,$a) $i $id]
-    if {[string compare [lindex $varctok($v) $a] $vtokmod($v)] < 0} {
-       modify_arc $v $a $i
-    }
+    modify_arc $v $a $i
     if {[info exists targetid]} {
        if {![comes_before $targetid $p]} {
            incr targetrow
@@ -648,9 +735,7 @@ proc removefakerow {id} {
     if {$j >= 0} {
        set children($v,$p) [lreplace $children($v,$p) $j $j]
     }
-    if {[string compare [lindex $varctok($v) $a] $vtokmod($v)] < 0} {
-       modify_arc $v $a $i
-    }
+    modify_arc $v $a $i
     if {[info exist currentid] && $id eq $currentid} {
        unset currentid
        unset selectedline
@@ -693,9 +778,19 @@ proc vtokcmp {v a b} {
                [lindex $varctok($v) $varcid($v,$b)]]
 }
 
+# This assumes that if lim is not given, the caller has checked that
+# arc a's token is less than $vtokmod($v)
 proc modify_arc {v a {lim {}}} {
     global varctok vtokmod varcmod varcrow vupptr curview vrowmod varccommits
 
+    if {$lim ne {}} {
+       set c [string compare [lindex $varctok($v) $a] $vtokmod($v)]
+       if {$c > 0} return
+       if {$c == 0} {
+           set r [lindex $varcrow($v) $a]
+           if {$r ne {} && $vrowmod($v) <= $r + $lim} return
+       }
+    }
     set vtokmod($v) [lindex $varctok($v) $a]
     set varcmod($v) $a
     if {$v == $curview} {
@@ -721,6 +816,14 @@ proc update_arcrows {v} {
     global vupptr vdownptr vleftptr varctok
     global displayorder parentlist curview cached_commitrow
 
+    if {$vrowmod($v) == $commitidx($v)} return
+    if {$v == $curview} {
+       if {[llength $displayorder] > $vrowmod($v)} {
+           set displayorder [lrange $displayorder 0 [expr {$vrowmod($v) - 1}]]
+           set parentlist [lrange $parentlist 0 [expr {$vrowmod($v) - 1}]]
+       }
+       catch {unset cached_commitrow}
+    }
     set narctot [expr {[llength $varctok($v)] - 1}]
     set a $varcmod($v)
     while {$a != 0 && [lindex $varcix($v) $a] eq {}} {
@@ -739,23 +842,12 @@ proc update_arcrows {v} {
        set row 0
     } else {
        set arcn [lindex $varcix($v) $a]
-       # see if a is the last arc; if so, nothing to do
-       if {$arcn == $narctot - 1} {
-           return
-       }
        if {[llength $vrownum($v)] > $arcn + 1} {
            set vrownum($v) [lrange $vrownum($v) 0 $arcn]
            set varcorder($v) [lrange $varcorder($v) 0 $arcn]
        }
        set row [lindex $varcrow($v) $a]
     }
-    if {$v == $curview} {
-       if {[llength $displayorder] > $vrowmod($v)} {
-           set displayorder [lrange $displayorder 0 [expr {$vrowmod($v) - 1}]]
-           set parentlist [lrange $parentlist 0 [expr {$vrowmod($v) - 1}]]
-       }
-       catch {unset cached_commitrow}
-    }
     while {1} {
        set p $a
        incr row [llength $varccommits($v,$a)]
@@ -969,20 +1061,18 @@ proc rewrite_commit {v id rwid} {
        # fix the graph after joining $id to $rwid
        set a $varcid($v,$ch)
        fix_reversal $rwid $a $v
-       if {[string compare [lindex $varctok($v) $a] $vtokmod($v)] < 0} {
-           # parentlist is wrong for the last element of arc $a
-           # even if displayorder is right, hence the 3rd arg here
-           modify_arc $v $a [expr {[llength $varccommits($v,$a)] - 1}]
-       }
+       # parentlist is wrong for the last element of arc $a
+       # even if displayorder is right, hence the 3rd arg here
+       modify_arc $v $a [expr {[llength $varccommits($v,$a)] - 1}]
     }
 }
 
 proc getcommitlines {fd inst view updating}  {
     global cmitlisted commitinterest leftover
-    global commitidx commitdata datemode
+    global commitidx commitdata vdatemode
     global parents children curview hlview
     global idpending ordertok
-    global varccommits varcid varctok vtokmod viewfiles
+    global varccommits varcid varctok vtokmod vfilelimit
 
     set stuff [read $fd 500000]
     # git log doesn't terminate the last commit with a null...
@@ -1085,7 +1175,7 @@ proc getcommitlines {fd inst view updating}  {
        set vid $view,$id
 
        if {!$listed && $updating && ![info exists varcid($vid)] &&
-           $viewfiles($view) ne {}} {
+           $vfilelimit($view) ne {}} {
            # git log doesn't rewrite parents for unlisted commits
            # when doing path limiting, so work around that here
            # by working out the rewritten parent with git rev-list
@@ -1093,7 +1183,7 @@ proc getcommitlines {fd inst view updating}  {
            # parent as a substitute parent for $id's children.
            if {![catch {
                set rwid [exec git rev-list --first-parent --max-count=1 \
-                             $id -- $viewfiles($view)]
+                             $id -- $vfilelimit($view)]
            }]} {
                if {$rwid ne {} && [info exists varcid($view,$rwid)]} {
                    # use $rwid in place of $id
@@ -1121,7 +1211,7 @@ proc getcommitlines {fd inst view updating}  {
        } elseif {$a == 0 && [llength $children($vid)] == 1} {
            set k [lindex $children($vid) 0]
            if {[llength $parents($view,$k)] == 1 &&
-               (!$datemode ||
+               (!$vdatemode($view) ||
                 $varcid($view,$k) == [llength $varctok($view)] - 1)} {
                set a $varcid($view,$k)
            }
@@ -1217,7 +1307,7 @@ proc chewcommits {} {
     if {$viewcomplete($curview)} {
        global commitidx varctok
        global numcommits startmsecs
-       global mainheadid commitinfo nullid
+       global mainheadid nullid
 
        if {[info exists pending_select]} {
            set row [first_real_row]
@@ -1649,6 +1739,7 @@ proc makewindow {} {
     }
     frame .bleft.top
     frame .bleft.mid
+    frame .bleft.bottom
 
     button .bleft.top.search -text [mc "Search"] -command dosearch
     pack .bleft.top.search -side left -padx 5
@@ -1676,18 +1767,25 @@ proc makewindow {} {
     checkbutton .bleft.mid.ignspace -text [mc "Ignore space change"] \
        -command changeignorespace -variable ignorespace
     pack .bleft.mid.ignspace -side left -padx 5
-    set ctext .bleft.ctext
+    set ctext .bleft.bottom.ctext
     text $ctext -background $bgcolor -foreground $fgcolor \
        -state disabled -font textfont \
-       -yscrollcommand scrolltext -wrap none
+       -yscrollcommand scrolltext -wrap none \
+       -xscrollcommand ".bleft.bottom.sbhorizontal set"
     if {$have_tk85} {
        $ctext conf -tabstyle wordprocessor
     }
-    scrollbar .bleft.sb -command "$ctext yview"
+    scrollbar .bleft.bottom.sb -command "$ctext yview"
+    scrollbar .bleft.bottom.sbhorizontal -command "$ctext xview" -orient h \
+       -width 10
     pack .bleft.top -side top -fill x
     pack .bleft.mid -side top -fill x
-    pack .bleft.sb -side right -fill y
-    pack $ctext -side left -fill both -expand 1
+    grid $ctext .bleft.bottom.sb -sticky nsew
+    grid .bleft.bottom.sbhorizontal -sticky ew
+    grid columnconfigure .bleft.bottom 0 -weight 1
+    grid rowconfigure .bleft.bottom 0 -weight 1
+    grid rowconfigure .bleft.bottom 1 -weight 0
+    pack .bleft.bottom -side top -fill both -expand 1
     lappend bglist $ctext
     lappend fglist $ctext
 
@@ -1752,9 +1850,17 @@ proc makewindow {} {
     .pwbottom add .bright
     .ctop add .pwbottom
 
-    # restore window position if known
+    # restore window width & height if known
     if {[info exists geometry(main)]} {
-        wm geometry . "$geometry(main)"
+       if {[scan $geometry(main) "%dx%d" w h] >= 2} {
+           if {$w > [winfo screenwidth .]} {
+               set w [winfo screenwidth .]
+           }
+           if {$h > [winfo screenheight .]} {
+               set h [winfo screenheight .]
+           }
+           wm geometry . "${w}x$h"
+       }
     }
 
     if {[tk windowingsystem] eq {aqua}} {
@@ -1982,9 +2088,10 @@ proc savestuff {w} {
     global canv canv2 canv3 mainfont textfont uifont tabstop
     global stuffsaved findmergefiles maxgraphpct
     global maxwidth showneartags showlocalchanges
-    global viewname viewfiles viewargs viewperm nextviewnum
+    global viewname viewfiles viewargs viewargscmd viewperm nextviewnum
     global cmitmode wrapcomment datetimeformat limitdiffs
     global colors bgcolor fgcolor diffcolors diffcontext selectbgcolor
+    global autoselect
 
     if {$stuffsaved} return
     if {![winfo viewable .]} return
@@ -1999,6 +2106,7 @@ proc savestuff {w} {
        puts $f [list set maxwidth $maxwidth]
        puts $f [list set cmitmode $cmitmode]
        puts $f [list set wrapcomment $wrapcomment]
+       puts $f [list set autoselect $autoselect]
        puts $f [list set showneartags $showneartags]
        puts $f [list set showlocalchanges $showlocalchanges]
        puts $f [list set datetimeformat $datetimeformat]
@@ -2021,7 +2129,7 @@ proc savestuff {w} {
        puts -nonewline $f "set permviews {"
        for {set v 0} {$v < $nextviewnum} {incr v} {
            if {$viewperm($v)} {
-               puts $f "{[list $viewname($v) $viewfiles($v) $viewargs($v)]}"
+               puts $f "{[list $viewname($v) $viewfiles($v) $viewargs($v) $viewargscmd($v)]}"
            }
        }
        puts $f "}"
@@ -2672,7 +2780,7 @@ proc shellsplit {str} {
 
 proc newview {ishighlight} {
     global nextviewnum newviewname newviewperm newishighlight
-    global newviewargs revtreeargs
+    global newviewargs revtreeargs viewargscmd newviewargscmd curview
 
     set newishighlight $ishighlight
     set top .gitkview
@@ -2680,16 +2788,17 @@ proc newview {ishighlight} {
        raise $top
        return
     }
-    set newviewname($nextviewnum) "View $nextviewnum"
+    set newviewname($nextviewnum) "[mc "View"] $nextviewnum"
     set newviewperm($nextviewnum) 0
     set newviewargs($nextviewnum) [shellarglist $revtreeargs]
+    set newviewargscmd($nextviewnum) $viewargscmd($curview)
     vieweditor $top $nextviewnum [mc "Gitk view definition"]
 }
 
 proc editview {} {
     global curview
     global viewname viewperm newviewname newviewperm
-    global viewargs newviewargs
+    global viewargs newviewargs viewargscmd newviewargscmd
 
     set top .gitkvedit-$curview
     if {[winfo exists $top]} {
@@ -2699,6 +2808,7 @@ proc editview {} {
     set newviewname($curview) $viewname($curview)
     set newviewperm($curview) $viewperm($curview)
     set newviewargs($curview) [shellarglist $viewargs($curview)]
+    set newviewargscmd($curview) $viewargscmd($curview)
     vieweditor $top $curview "Gitk: edit view $viewname($curview)"
 }
 
@@ -2719,6 +2829,14 @@ proc vieweditor {top n title} {
     entry $top.args -width 50 -textvariable newviewargs($n) \
        -background $bgcolor
     grid $top.args - -sticky ew -padx 5
+
+    message $top.ac -aspect 1000 \
+       -text [mc "Command to generate more commits to include:"]
+    grid $top.ac - -sticky w -pady 5
+    entry $top.argscmd -width 50 -textvariable newviewargscmd($n) \
+       -background white
+    grid $top.argscmd - -sticky ew -padx 5
+
     message $top.l -aspect 1000 \
        -text [mc "Enter files and directories to include, one per line:"]
     grid $top.l - -sticky w
@@ -2762,7 +2880,7 @@ proc allviewmenus {n op args} {
 proc newviewok {top n} {
     global nextviewnum newviewperm newviewname newishighlight
     global viewname viewfiles viewperm selectedview curview
-    global viewargs newviewargs viewhlmenu
+    global viewargs newviewargs viewargscmd newviewargscmd viewhlmenu
 
     if {[catch {
        set newargs [shellsplit $newviewargs($n)]
@@ -2786,6 +2904,7 @@ proc newviewok {top n} {
        set viewperm($n) $newviewperm($n)
        set viewfiles($n) $files
        set viewargs($n) $newargs
+       set viewargscmd($n) $newviewargscmd($n)
        addviewmenu $n
        if {!$newishighlight} {
            run showview $n
@@ -2802,9 +2921,11 @@ proc newviewok {top n} {
            # doviewmenu $viewhlmenu 1 [list addvhighlight $n] \
                # entryconf [list -label $viewname($n) -value $viewname($n)]
        }
-       if {$files ne $viewfiles($n) || $newargs ne $viewargs($n)} {
+       if {$files ne $viewfiles($n) || $newargs ne $viewargs($n) || \
+               $newviewargscmd($n) ne $viewargscmd($n)} {
            set viewfiles($n) $files
            set viewargs($n) $newargs
+           set viewargscmd($n) $newviewargscmd($n)
            if {$curview == $n} {
                run reloadcommits
            }
@@ -2836,7 +2957,7 @@ proc addviewmenu {n} {
 }
 
 proc showview {n} {
-    global curview viewfiles cached_commitrow ordertok
+    global curview cached_commitrow ordertok
     global displayorder parentlist rowidlist rowisopt rowfinal
     global colormap rowtextx nextcolor canvxmax
     global numcommits viewcomplete
@@ -3624,8 +3745,9 @@ proc dohidelocalchanges {} {
 # spawn off a process to do git diff-index --cached HEAD
 proc dodiffindex {} {
     global lserial showlocalchanges
+    global isworktree
 
-    if {!$showlocalchanges} return
+    if {!$showlocalchanges || !$isworktree} return
     incr lserial
     set fd [open "|git diff-index --cached HEAD" r]
     fconfigure $fd -blocking 0
@@ -5428,7 +5550,8 @@ proc selectline {l isnew} {
     global commentend idtags linknum
     global mergemax numcommits pending_select
     global cmitmode showneartags allcommits
-    global targetrow targetid
+    global targetrow targetid lastscrollrows
+    global autoselect
 
     catch {unset pending_select}
     $canv delete hover
@@ -5439,6 +5562,11 @@ proc selectline {l isnew} {
     set id [commitonrow $l]
     set targetid $id
     set targetrow $l
+    set selectedline $l
+    set currentid $id
+    if {$lastscrollrows < $numcommits} {
+       setcanvscroll
+    }
 
     set y [expr {$canvy0 + $l * $linespc}]
     set ymax [lindex [$canv cget -scrollregion] 3]
@@ -5482,17 +5610,20 @@ proc selectline {l isnew} {
        addtohistory [list selbyid $id]
     }
 
-    set selectedline $l
-    set currentid $id
     $sha1entry delete 0 end
     $sha1entry insert 0 $id
-    $sha1entry selection from 0
-    $sha1entry selection to end
+    if {$autoselect} {
+       $sha1entry selection from 0
+       $sha1entry selection to end
+    }
     rhighlight_sel $id
 
     $ctext conf -state normal
     clear_ctext
     set linknum 0
+    if {![info exists commitinfo($id)]} {
+       getcommit $id
+    }
     set info $commitinfo($id)
     set date [formatdate [lindex $info 2]]
     $ctext insert end "[mc "Author"]: [lindex $info 1]  $date\n"
@@ -5815,14 +5946,14 @@ proc mergediff {id} {
     global diffids
     global parents
     global diffcontext
-    global limitdiffs viewfiles curview
+    global limitdiffs vfilelimit curview
 
     set diffmergeid $id
     set diffids $id
     # this doesn't seem to actually affect anything...
     set cmd [concat | git diff-tree --no-commit-id --cc -U$diffcontext $id]
-    if {$limitdiffs && $viewfiles($curview) ne {}} {
-       set cmd [concat $cmd -- $viewfiles($curview)]
+    if {$limitdiffs && $vfilelimit($curview) ne {}} {
+       set cmd [concat $cmd -- $vfilelimit($curview)]
     }
     if {[catch {set mdf [open $cmd r]} err]} {
        error_popup "[mc "Error getting merge diffs:"] $err"
@@ -6000,7 +6131,7 @@ proc gettreediffs {ids} {
 
 proc gettreediffline {gdtf ids} {
     global treediff treediffs treepending diffids diffmergeid
-    global cmitmode viewfiles curview limitdiffs
+    global cmitmode vfilelimit curview limitdiffs
 
     set nr 0
     while {[incr nr] <= 1000 && [gets $gdtf line] >= 0} {
@@ -6017,10 +6148,10 @@ proc gettreediffline {gdtf ids} {
        return [expr {$nr >= 1000? 2: 1}]
     }
     close $gdtf
-    if {$limitdiffs && $viewfiles($curview) ne {}} {
+    if {$limitdiffs && $vfilelimit($curview) ne {}} {
        set flist {}
        foreach f $treediff {
-           if {[path_filter $viewfiles($curview) $f]} {
+           if {[path_filter $vfilelimit($curview) $f]} {
                lappend flist $f
            }
        }
@@ -6066,14 +6197,14 @@ proc getblobdiffs {ids} {
     global diffinhdr treediffs
     global diffcontext
     global ignorespace
-    global limitdiffs viewfiles curview
+    global limitdiffs vfilelimit curview
 
     set cmd [diffcmd $ids "-p -C --no-commit-id -U$diffcontext"]
     if {$ignorespace} {
        append cmd " -w"
     }
-    if {$limitdiffs && $viewfiles($curview) ne {}} {
-       set cmd [concat $cmd -- $viewfiles($curview)]
+    if {$limitdiffs && $vfilelimit($curview) ne {}} {
+       set cmd [concat $cmd -- $vfilelimit($curview)]
     }
     if {[catch {set bdf [open $cmd r]} err]} {
        puts "error getting diffs: $err"
@@ -6385,7 +6516,7 @@ proc searchmarkvisible {doall} {
 proc scrolltext {f0 f1} {
     global searchstring
 
-    .bleft.sb set $f0 $f1
+    .bleft.bottom.sb set $f0 $f1
     if {$searchstring ne {}} {
        searchmarkvisible 0
     }
@@ -8722,7 +8853,7 @@ proc doprefs {} {
     global maxwidth maxgraphpct
     global oldprefs prefstop showneartags showlocalchanges
     global bgcolor fgcolor ctext diffcolors selectbgcolor
-    global tabstop limitdiffs
+    global tabstop limitdiffs autoselect
 
     set top .gitkprefs
     set prefstop $top
@@ -8752,6 +8883,11 @@ proc doprefs {} {
     checkbutton $top.showlocal.b -variable showlocalchanges
     pack $top.showlocal.b $top.showlocal.l -side left
     grid x $top.showlocal -sticky w
+    frame $top.autoselect
+    label $top.autoselect.l -text [mc "Auto-select SHA1"] -font optionfont
+    checkbutton $top.autoselect.b -variable autoselect
+    pack $top.autoselect.b $top.autoselect.l -side left
+    grid x $top.autoselect -sticky w
 
     label $top.ddisp -text [mc "Diff display options"]
     grid $top.ddisp - -sticky w -pady 10
@@ -9207,7 +9343,6 @@ if {[catch {package require Tk 8.4} err]} {
 }
 
 # defaults...
-set datemode 0
 set wrcomcmd "git diff-tree --stdin -p --pretty"
 
 set gitencoding {}
@@ -9242,6 +9377,7 @@ set maxlinelen 200
 set showlocalchanges 1
 set limitdiffs 1
 set datetimeformat "%Y-%m-%d %H:%M:%S"
+set autoselect 1
 
 set colors {green red blue magenta darkgrey brown orange}
 set bgcolor white
@@ -9297,22 +9433,20 @@ if {![file isdirectory $gitdir]} {
     exit 1
 }
 
-set mergeonly 0
 set revtreeargs {}
 set cmdline_files {}
 set i 0
+set revtreeargscmd {}
 foreach arg $argv {
-    switch -- $arg {
+    switch -glob -- $arg {
        "" { }
-       "-d" { set datemode 1 }
-       "--merge" {
-           set mergeonly 1
-           lappend revtreeargs $arg
-       }
        "--" {
            set cmdline_files [lrange $argv [expr {$i + 1}] end]
            break
        }
+       "--argscmd=*" {
+           set revtreeargscmd [string range $arg 10 end]
+       }
        default {
            lappend revtreeargs $arg
        }
@@ -9321,7 +9455,7 @@ foreach arg $argv {
 }
 
 if {$i >= [llength $argv] && $revtreeargs ne {}} {
-    # no -- on command line, but some arguments (other than -d)
+    # no -- on command line, but some arguments (other than --argscmd)
     if {[catch {
        set f [eval exec git rev-parse --no-revs --no-flags $revtreeargs]
        set cmdline_files [split $f "\n"]
@@ -9349,40 +9483,6 @@ if {$i >= [llength $argv] && $revtreeargs ne {}} {
     }
 }
 
-if {$mergeonly} {
-    # find the list of unmerged files
-    set mlist {}
-    set nr_unmerged 0
-    if {[catch {
-       set fd [open "| git ls-files -u" r]
-    } err]} {
-       show_error {} . "[mc "Couldn't get list of unmerged files:"] $err"
-       exit 1
-    }
-    while {[gets $fd line] >= 0} {
-       set i [string first "\t" $line]
-       if {$i < 0} continue
-       set fname [string range $line [expr {$i+1}] end]
-       if {[lsearch -exact $mlist $fname] >= 0} continue
-       incr nr_unmerged
-       if {$cmdline_files eq {} || [path_filter $cmdline_files $fname]} {
-           lappend mlist $fname
-       }
-    }
-    catch {close $fd}
-    if {$mlist eq {}} {
-       if {$nr_unmerged == 0} {
-           show_error {} . [mc "No files selected: --merge specified but\
-                            no files are unmerged."]
-       } else {
-           show_error {} . [mc "No files selected: --merge specified but\
-                            no unmerged files are within file limit."]
-       }
-       exit 1
-    }
-    set cmdline_files $mlist
-}
-
 set nullid "0000000000000000000000000000000000000000"
 set nullid2 "0000000000000000000000000000000000000001"
 
@@ -9414,6 +9514,7 @@ set highlight_files {}
 set viewfiles(0) {}
 set viewperm(0) 0
 set viewargs(0) {}
+set viewargscmd(0) {}
 
 set loginstance 0
 set cmdlineok 0
@@ -9421,6 +9522,7 @@ set stopped 0
 set stuffsaved 0
 set patchnum 0
 set lserial 0
+set isworktree [expr {[exec git rev-parse --is-inside-work-tree] == "true"}]
 setcoords
 makewindow
 # wait for the window to become visible
@@ -9428,7 +9530,7 @@ tkwait visibility .
 wm title . "[file tail $argv0]: [file tail [pwd]]"
 readrefs
 
-if {$cmdline_files ne {} || $revtreeargs ne {}} {
+if {$cmdline_files ne {} || $revtreeargs ne {} || $revtreeargscmd ne {}} {
     # create a view for the files/dirs specified on the command line
     set curview 1
     set selectedview 1
@@ -9436,7 +9538,9 @@ if {$cmdline_files ne {} || $revtreeargs ne {}} {
     set viewname(1) [mc "Command line"]
     set viewfiles(1) $cmdline_files
     set viewargs(1) $revtreeargs
+    set viewargscmd(1) $revtreeargscmd
     set viewperm(1) 0
+    set vdatemode(1) 0
     addviewmenu 1
     .bar.view entryconf [mc "Edit view..."] -state normal
     .bar.view entryconf [mc "Delete view"] -state normal
@@ -9449,6 +9553,7 @@ if {[info exists permviews]} {
        set viewname($n) [lindex $v 0]
        set viewfiles($n) [lindex $v 1]
        set viewargs($n) [lindex $v 2]
+       set viewargscmd($n) [lindex $v 3]
        set viewperm($n) 1
        addviewmenu $n
     }