git-gui: Use a smaller pipe buffer for update-index.
[gitweb.git] / git-gui
diff --git a/git-gui b/git-gui
index bee17de4ddccb8abd99773dd538cad90d26e54bb..7e28328cf0d5eca0d5c3085954e5bff5c135594f 100755 (executable)
--- a/git-gui
+++ b/git-gui
@@ -90,15 +90,15 @@ proc save_config {} {
 
        foreach name [array names default_config] {
                set value $global_config_new($name)
-               if {$value != $global_config($name)} {
-                       if {$value == $default_config($name)} {
+               if {$value ne $global_config($name)} {
+                       if {$value eq $default_config($name)} {
                                catch {exec git repo-config --global --unset $name}
                        } else {
                                regsub -all "\[{}\]" $value {"} value
                                exec git repo-config --global $name $value
                        }
                        set global_config($name) $value
-                       if {$value == $repo_config($name)} {
+                       if {$value eq $repo_config($name)} {
                                catch {exec git repo-config --unset $name}
                                set repo_config($name) $value
                        }
@@ -107,8 +107,8 @@ proc save_config {} {
 
        foreach name [array names default_config] {
                set value $repo_config_new($name)
-               if {$value != $repo_config($name)} {
-                       if {$value == $global_config($name)} {
+               if {$value ne $repo_config($name)} {
+                       if {$value eq $global_config($name)} {
                                catch {exec git repo-config --unset $name}
                        } else {
                                regsub -all "\[{}\]" $value {"} value
@@ -123,7 +123,7 @@ proc error_popup {msg} {
        global gitdir appname
 
        set title $appname
-       if {$gitdir != {}} {
+       if {$gitdir ne {}} {
                append title { (}
                append title [lindex \
                        [file split [file normalize [file dirname $gitdir]]] \
@@ -142,7 +142,7 @@ proc info_popup {msg} {
        global gitdir appname
 
        set title $appname
-       if {$gitdir != {}} {
+       if {$gitdir ne {}} {
                append title { (}
                append title [lindex \
                        [file split [file normalize [file dirname $gitdir]]] \
@@ -167,13 +167,13 @@ if {   [catch {set cdup [exec git rev-parse --show-cdup]} err]
        error_popup "Cannot find the git directory:\n\n$err"
        exit 1
 }
-if {$cdup != ""} {
+if {$cdup ne ""} {
        cd $cdup
 }
 unset cdup
 
 set single_commit 0
-if {$appname == {git-citool}} {
+if {$appname eq {git-citool}} {
        set single_commit 1
 }
 
@@ -183,7 +183,6 @@ if {$appname == {git-citool}} {
 
 set status_active 0
 set diff_active 0
-set commit_active 0
 
 set disable_on_lock [list]
 set index_lock_type none
@@ -195,13 +194,13 @@ set commit_type {}
 proc lock_index {type} {
        global index_lock_type disable_on_lock
 
-       if {$index_lock_type == {none}} {
+       if {$index_lock_type eq {none}} {
                set index_lock_type $type
                foreach w $disable_on_lock {
                        uplevel #0 $w disabled
                }
                return 1
-       } elseif {$index_lock_type == {begin-update} && $type == {update}} {
+       } elseif {$index_lock_type eq {begin-update} && $type eq {update}} {
                set index_lock_type $type
                return 1
        }
@@ -243,9 +242,9 @@ proc update_status {{final Ready.}} {
        if {$status_active || ![lock_index read]} return
 
        repository_state new_HEAD new_type
-       if {$commit_type == {amend} 
-               && $new_type == {normal}
-               && $new_HEAD == $HEAD} {
+       if {$commit_type eq {amend}
+               && $new_type eq {normal}
+               && $new_HEAD eq $HEAD} {
        } else {
                set HEAD $new_HEAD
                set PARENT $new_HEAD
@@ -255,7 +254,7 @@ proc update_status {{final Ready.}} {
        array unset file_states
 
        if {![$ui_comm edit modified]
-               || [string trim [$ui_comm get 0.0 end]] == {}} {
+               || [string trim [$ui_comm get 0.0 end]] eq {}} {
                if {[load_message GITGUI_MSG]} {
                } elseif {[load_message MERGE_MSG]} {
                } elseif {[load_message SQUASH_MSG]} {
@@ -264,7 +263,7 @@ proc update_status {{final Ready.}} {
                $ui_comm edit reset
        }
 
-       if {$repo_config(gui.trustmtime) == {true}} {
+       if {$repo_config(gui.trustmtime) eq {true}} {
                update_status_stage2 {} $final
        } else {
                set status_active 1
@@ -287,7 +286,7 @@ proc update_status_stage2 {fd final} {
        global status_active
        global buf_rdi buf_rdf buf_rlo
 
-       if {$fd != {}} {
+       if {$fd ne {}} {
                read $fd
                if {![eof $fd]} return
                close $fd
@@ -443,7 +442,7 @@ proc clear_diff {} {
 proc reshow_diff {} {
        global ui_fname_value ui_status_value file_states
 
-       if {$ui_fname_value == {}
+       if {$ui_fname_value eq {}
                || [catch {set s $file_states($ui_fname_value)}]} {
                clear_diff
        } else {
@@ -456,7 +455,7 @@ proc handle_empty_diff {} {
 
        set path $ui_fname_value
        set s $file_states($path)
-       if {[lindex $s 0] != {_M}} return
+       if {[lindex $s 0] ne {_M}} return
 
        info_popup "No differences detected.
 
@@ -489,13 +488,13 @@ prevent possible confusion.
 
 proc show_diff {path {w {}} {lno {}}} {
        global file_states file_lists
-       global PARENT diff_3way diff_active
+       global PARENT diff_3way diff_active repo_config
        global ui_diff ui_fname_value ui_fstatus_value ui_status_value
 
        if {$diff_active || ![lock_index read]} return
 
        clear_diff
-       if {$w == {} || $lno == {}} {
+       if {$w eq {} || $lno == {}} {
                foreach w [array names file_lists] {
                        set lno [lsearch -sorted $file_lists($w) $path]
                        if {$lno >= 0} {
@@ -504,7 +503,7 @@ proc show_diff {path {w {}} {lno {}}} {
                        }
                }
        }
-       if {$w != {} && $lno >= 1} {
+       if {$w ne {} && $lno >= 1} {
                $w tag add in_diff $lno.0 [expr $lno + 1].0
        }
 
@@ -516,10 +515,16 @@ proc show_diff {path {w {}} {lno {}}} {
        set ui_fstatus_value [mapdesc $m $path]
        set ui_status_value "Loading diff of [escape_path $path]..."
 
-       set cmd [list | git diff-index -p $PARENT -- $path]
+       set cmd [list | git diff-index]
+       lappend cmd --no-color
+       if {$repo_config(gui.diffcontext) > 0} {
+               lappend cmd "-U$repo_config(gui.diffcontext)"
+       }
+       lappend cmd -p
+
        switch $m {
        MM {
-               set cmd [list | git diff-index -p -c $PARENT $path]
+               lappend cmd -c
        }
        _O {
                if {[catch {
@@ -543,6 +548,10 @@ proc show_diff {path {w {}} {lno {}}} {
        }
        }
 
+       lappend cmd $PARENT
+       lappend cmd --
+       lappend cmd $path
+
        if {[catch {set fd [open $cmd r]} err]} {
                set diff_active 0
                unlock_index
@@ -605,8 +614,8 @@ proc read_diff {fd} {
                unlock_index
                set ui_status_value {Ready.}
 
-               if {$repo_config(gui.trustmtime) == {true}
-                       && [$ui_diff index end] == {2.0}} {
+               if {$repo_config(gui.trustmtime) eq {true}
+                       && [$ui_diff index end] eq {2.0}} {
                        handle_empty_diff
                }
        }
@@ -619,8 +628,8 @@ proc read_diff {fd} {
 proc load_last_commit {} {
        global HEAD PARENT commit_type ui_comm
 
-       if {$commit_type == {amend}} return
-       if {$commit_type != {normal}} {
+       if {$commit_type eq {amend}} return
+       if {$commit_type ne {normal}} {
                error_popup "Can't amend a $commit_type commit."
                return
        }
@@ -664,18 +673,18 @@ proc load_last_commit {} {
 
 proc commit_tree {} {
        global tcl_platform HEAD gitdir commit_type file_states
-       global commit_active pch_error
+       global pch_error
        global ui_status_value ui_comm
 
-       if {$commit_active || ![lock_index update]} return
+       if {![lock_index update]} return
 
        # -- Our in memory state should match the repository.
        #
        repository_state curHEAD cur_type
-       if {$commit_type == {amend} 
-               && $cur_type == {normal}
-               && $curHEAD == $HEAD} {
-       } elseif {$commit_type != $cur_type || $HEAD != $curHEAD} {
+       if {$commit_type eq {amend}
+               && $cur_type eq {normal}
+               && $curHEAD eq $HEAD} {
+       } elseif {$commit_type ne $cur_type || $HEAD ne $curHEAD} {
                error_popup {Last scanned state does not match repository state.
 
 Its highly likely that another Git program modified the
@@ -726,7 +735,7 @@ You must include at least 1 file before you can commit.
        # -- A message is required.
        #
        set msg [string trim [$ui_comm get 1.0 end]]
-       if {$msg == {}} {
+       if {$msg eq {}} {
                error_popup {Please supply a commit message.
 
 A good commit message has the following format:
@@ -739,12 +748,10 @@ A good commit message has the following format:
                return
        }
 
-       set commit_active 1
-
        # -- Ask the pre-commit hook for the go-ahead.
        #
        set pchook [file join $gitdir hooks pre-commit]
-       if {$tcl_platform(platform) == {windows} && [file isfile $pchook]} {
+       if {$tcl_platform(platform) eq {windows} && [file isfile $pchook]} {
                set pchook [list sh -c [concat \
                        "if test -x \"$pchook\";" \
                        "then exec \"$pchook\" 2>&1;" \
@@ -754,7 +761,7 @@ A good commit message has the following format:
        } else {
                set pchook {}
        }
-       if {$pchook != {}} {
+       if {$pchook ne {}} {
                set ui_status_value {Calling pre-commit hook...}
                set pch_error {}
                set fd_ph [open "| $pchook" r]
@@ -767,7 +774,7 @@ A good commit message has the following format:
 }
 
 proc commit_stage1 {fd_ph curHEAD msg} {
-       global commit_active pch_error ui_status_value
+       global pch_error ui_status_value
 
        append pch_error [read $fd_ph]
        fconfigure $fd_ph -blocking 1
@@ -776,14 +783,13 @@ proc commit_stage1 {fd_ph curHEAD msg} {
                        set ui_status_value {Commit declined by pre-commit hook.}
                        hook_failed_popup pre-commit $pch_error
                        unlock_index
-                       set commit_active 0
-                       set pch_error {}
-                       return
+               } else {
+                       commit_stage2 $curHEAD $msg
                }
-               commit_stage2 $curHEAD $msg
-               return
+               set pch_error {}
+       } else {
+               fconfigure $fd_ph -blocking 0
        }
-       fconfigure $fd_ph -blocking 0
 }
 
 proc commit_stage2 {curHEAD msg} {
@@ -797,14 +803,13 @@ proc commit_stage2 {curHEAD msg} {
 }
 
 proc commit_stage3 {fd_wt curHEAD msg} {
-       global single_commit gitdir HEAD PARENT commit_type
-       global commit_active ui_status_value ui_comm
+       global single_commit gitdir HEAD PARENT commit_type tcl_platform
+       global ui_status_value ui_comm
        global file_states
 
        gets $fd_wt tree_id
-       if {$tree_id == {} || [catch {close $fd_wt} err]} {
+       if {$tree_id eq {} || [catch {close $fd_wt} err]} {
                error_popup "write-tree failed:\n\n$err"
-               set commit_active 0
                set ui_status_value {Commit failed.}
                unlock_index
                return
@@ -813,10 +818,10 @@ proc commit_stage3 {fd_wt curHEAD msg} {
        # -- Create the commit.
        #
        set cmd [list git commit-tree $tree_id]
-       if {$PARENT != {}} {
+       if {$PARENT ne {}} {
                lappend cmd -p $PARENT
        }
-       if {$commit_type == {merge}} {
+       if {$commit_type eq {merge}} {
                if {[catch {
                                set fd_mh [open [file join $gitdir MERGE_HEAD] r]
                                while {[gets $fd_mh merge_head] >= 0} {
@@ -825,20 +830,18 @@ proc commit_stage3 {fd_wt curHEAD msg} {
                                close $fd_mh
                        } err]} {
                        error_popup "Loading MERGE_HEAD failed:\n\n$err"
-                       set commit_active 0
                        set ui_status_value {Commit failed.}
                        unlock_index
                        return
                }
        }
-       if {$PARENT == {}} {
+       if {$PARENT eq {}} {
                # git commit-tree writes to stderr during initial commit.
                lappend cmd 2>/dev/null
        }
        lappend cmd << $msg
        if {[catch {set cmt_id [eval exec $cmd]} err]} {
                error_popup "commit-tree failed:\n\n$err"
-               set commit_active 0
                set ui_status_value {Commit failed.}
                unlock_index
                return
@@ -847,7 +850,7 @@ proc commit_stage3 {fd_wt curHEAD msg} {
        # -- Update the HEAD ref.
        #
        set reflogm commit
-       if {$commit_type != {normal}} {
+       if {$commit_type ne {normal}} {
                append reflogm " ($commit_type)"
        }
        set i [string first "\n" $msg]
@@ -859,7 +862,6 @@ proc commit_stage3 {fd_wt curHEAD msg} {
        set cmd [list git update-ref -m $reflogm HEAD $cmt_id $curHEAD]
        if {[catch {eval exec $cmd} err]} {
                error_popup "update-ref failed:\n\n$err"
-               set commit_active 0
                set ui_status_value {Commit failed.}
                unlock_index
                return
@@ -878,6 +880,21 @@ proc commit_stage3 {fd_wt curHEAD msg} {
                catch {exec git rerere}
        }
 
+       # -- Run the post-commit hook.
+       #
+       set pchook [file join $gitdir hooks post-commit]
+       if {$tcl_platform(platform) eq {windows} && [file isfile $pchook]} {
+               set pchook [list sh -c [concat \
+                       "if test -x \"$pchook\";" \
+                       "then exec \"$pchook\";" \
+                       "fi"]]
+       } elseif {![file executable $pchook]} {
+               set pchook {}
+       }
+       if {$pchook ne {}} {
+               catch {exec $pchook &}
+       }
+
        $ui_comm delete 0.0 end
        $ui_comm edit modified false
        $ui_comm edit reset
@@ -886,7 +903,6 @@ proc commit_stage3 {fd_wt curHEAD msg} {
 
        # -- Update status without invoking any git commands.
        #
-       set commit_active 0
        set commit_type normal
        set HEAD $cmt_id
        set PARENT $cmt_id
@@ -900,7 +916,7 @@ proc commit_stage3 {fd_wt curHEAD msg} {
                D? {set m _[string index $m 1]}
                }
 
-               if {$m == {__}} {
+               if {$m eq {__}} {
                        unset file_states($path)
                } else {
                        lset file_states($path) 0 $m
@@ -934,7 +950,7 @@ proc pull_remote {remote branch} {
        # -- Our in memory state should match the repository.
        #
        repository_state curHEAD cur_type
-       if {$commit_type != $cur_type || $HEAD != $curHEAD} {
+       if {$commit_type ne $cur_type || $HEAD ne $curHEAD} {
                error_popup {Last scanned state does not match repository state.
 
 Its highly likely that another Git program modified the
@@ -963,7 +979,7 @@ Commit or throw away all changes before starting a pull operation.
        set w [new_console "pull $remote $branch" \
                "Pulling new changes from branch $branch in $remote"]
        set cmd [list git pull]
-       if {$repo_config(gui.pullsummary) == {false}} {
+       if {$repo_config(gui.pullsummary) eq {false}} {
                lappend cmd --no-summary
        }
        lappend cmd $remote
@@ -1053,15 +1069,15 @@ proc merge_state {path new_state} {
                set icon [lindex $info 1]
        }
 
-       if {$s0 == {_}} {
+       if {$s0 eq {_}} {
                set s0 [string index $state 0]
-       } elseif {$s0 == {*}} {
+       } elseif {$s0 eq {*}} {
                set s0 _
        }
 
-       if {$s1 == {_}} {
+       if {$s1 eq {_}} {
                set s1 [string index $state 1]
-       } elseif {$s1 == {*}} {
+       } elseif {$s1 eq {*}} {
                set s1 _
        }
 
@@ -1081,7 +1097,7 @@ proc display_file {path state} {
        set old_w [mapcol $old_m $path]
        set new_icon [mapicon $new_m $path]
 
-       if {$new_w != $old_w} {
+       if {$new_w ne $old_w} {
                set lno [lsearch -sorted $file_lists($old_w) $path]
                if {$lno >= 0} {
                        incr lno
@@ -1101,7 +1117,7 @@ proc display_file {path state} {
                        -image $new_icon
                $new_w insert $lno.1 "[escape_path $path]\n"
                $new_w conf -state disabled
-       } elseif {$new_icon != [mapicon $old_m $path]} {
+       } elseif {$new_icon ne [mapicon $old_m $path]} {
                $new_w conf -state normal
                $new_w image conf [lindex $s 1] -image $new_icon
                $new_w conf -state disabled
@@ -1137,11 +1153,13 @@ proc display_all_files {} {
 }
 
 proc update_index {pathList} {
-       global update_index_cp ui_status_value
+       global update_index_cp update_index_rsd ui_status_value
 
        if {![lock_index update]} return
 
        set update_index_cp 0
+       set update_index_rsd 0
+       set pathList [lsort $pathList]
        set totalCnt [llength $pathList]
        set batch [expr {int($totalCnt * .01) + 1}]
        if {$batch > 25} {set batch 25}
@@ -1153,7 +1171,11 @@ proc update_index {pathList} {
                $totalCnt \
                0.0]
        set fd [open "| git update-index --add --remove -z --stdin" w]
-       fconfigure $fd -blocking 0 -translation binary
+       fconfigure $fd \
+               -blocking 0 \
+               -buffering full \
+               -buffersize 512 \
+               -translation binary
        fileevent $fd writable [list \
                write_update_index \
                $fd \
@@ -1164,13 +1186,17 @@ proc update_index {pathList} {
 }
 
 proc write_update_index {fd pathList totalCnt batch} {
-       global update_index_cp ui_status_value
+       global update_index_cp update_index_rsd ui_status_value
        global file_states ui_fname_value
 
        if {$update_index_cp >= $totalCnt} {
                close $fd
                unlock_index
-               set ui_status_value {Ready.}
+               if {$update_index_rsd} {
+                       reshow_diff
+               } else {
+                       set ui_status_value {Ready.}
+               }
                return
        }
 
@@ -1193,8 +1219,8 @@ proc write_update_index {fd pathList totalCnt batch} {
                puts -nonewline $fd $path
                puts -nonewline $fd "\0"
                display_file $path $new
-               if {$ui_fname_value == $path} {
-                       show_diff $path
+               if {$ui_fname_value eq $path} {
+                       set update_index_rsd 1
                }
        }
 
@@ -1246,8 +1272,8 @@ proc populate_pull_menu {m} {
 
        foreach remote $all_remotes {
                set rb {}
-               if {[array get repo_config remote.$remote.url] != {}} {
-                       if {[array get repo_config remote.$remote.fetch] != {}} {
+               if {[array get repo_config remote.$remote.url] ne {}} {
+                       if {[array get repo_config remote.$remote.fetch] ne {}} {
                                regexp {^([^:]+):} \
                                        [lindex $repo_config(remote.$remote.fetch) 0] \
                                        line rb
@@ -1266,7 +1292,7 @@ proc populate_pull_menu {m} {
 
                set rb_short $rb
                regsub ^refs/heads/ $rb {} rb_short
-               if {$rb_short != {}} {
+               if {$rb_short ne {}} {
                        $m add command \
                                -label "Branch $rb_short from $remote..." \
                                -command [list pull_remote $remote $rb] \
@@ -1378,7 +1404,7 @@ foreach i {
        if {$max_status_desc < [string length [lindex $i 3]]} {
                set max_status_desc [string length [lindex $i 3]]
        }
-       if {[lindex $i 1] == {i}} {
+       if {[lindex $i 1] eq {i}} {
                set all_cols([lindex $i 0]) $ui_index
        } else {
                set all_cols([lindex $i 0]) $ui_other
@@ -1394,8 +1420,8 @@ unset filemask i
 
 proc is_MacOSX {} {
        global tcl_platform tk_library
-       if {$tcl_platform(platform) == {unix}
-               && $tcl_platform(os) == {Darwin}
+       if {$tcl_platform(platform) eq {unix}
+               && $tcl_platform(os) eq {Darwin}
                && [string match /Library/Frameworks/* $tk_library]} {
                return 1
        }
@@ -1537,7 +1563,7 @@ proc console_exec {w cmd {after {}}} {
        # -- Windows tosses the enviroment when we exec our child.
        #    But most users need that so we have to relogin. :-(
        #
-       if {$tcl_platform(platform) == {windows}} {
+       if {$tcl_platform(platform) eq {windows}} {
                set cmd [list sh --login -c "cd \"[pwd]\" && [join $cmd { }]"]
        }
 
@@ -1555,7 +1581,7 @@ proc console_read {w fd after} {
        global console_cr console_data
 
        set buf [read $fd]
-       if {$buf != {}} {
+       if {$buf ne {}} {
                if {![winfo exists $w]} {console_init $w}
                $w.m.t conf -state normal
                set c 0
@@ -1599,7 +1625,7 @@ proc console_read {w fd after} {
                }
                array unset console_cr $w
                array unset console_data $w
-               if {$after != {}} {
+               if {$after ne {}} {
                        uplevel #0 $after $ok
                }
                return
@@ -1618,12 +1644,12 @@ proc do_gitk {} {
 
        set ui_status_value $starting_gitk_msg
        after 10000 {
-               if {$ui_status_value == $starting_gitk_msg} {
+               if {$ui_status_value eq $starting_gitk_msg} {
                        set ui_status_value {Ready.}
                }
        }
 
-       if {$tcl_platform(platform) == {windows}} {
+       if {$tcl_platform(platform) eq {windows}} {
                exec sh -c gitk &
        } else {
                exec gitk &
@@ -1650,13 +1676,13 @@ proc do_quit {} {
        #
        set save [file join $gitdir GITGUI_MSG]
        set msg [string trim [$ui_comm get 0.0 end]]
-       if {[$ui_comm edit modified] && $msg != {}} {
+       if {[$ui_comm edit modified] && $msg ne {}} {
                catch {
                        set fd [open $save w]
                        puts $fd [string trim [$ui_comm get 0.0 end]]
                        close $fd
                }
-       } elseif {$msg == {} && [file exists $save]} {
+       } elseif {$msg eq {} && [file exists $save]} {
                file delete $save
        }
 
@@ -1669,7 +1695,7 @@ proc do_quit {} {
        if {[catch {set rc_geometry $repo_config(gui.geometry)}]} {
                set rc_geometry {}
        }
-       if {$cfg_geometry != $rc_geometry} {
+       if {$cfg_geometry ne $rc_geometry} {
                catch {exec git repo-config gui.geometry $cfg_geometry}
        }
 
@@ -1696,7 +1722,7 @@ proc do_include_all {} {
                _D {lappend pathList $path}
                }
        }
-       if {$pathList == {}} {
+       if {$pathList eq {}} {
                unlock_index
        } else {
                update_index $pathList
@@ -1708,7 +1734,7 @@ set GIT_COMMITTER_IDENT {}
 proc do_signoff {} {
        global ui_comm GIT_COMMITTER_IDENT
 
-       if {$GIT_COMMITTER_IDENT == {}} {
+       if {$GIT_COMMITTER_IDENT eq {}} {
                if {[catch {set me [exec git var GIT_COMMITTER_IDENT]} err]} {
                        error_popup "Unable to obtain your identity:\n\n$err"
                        return
@@ -1722,9 +1748,9 @@ proc do_signoff {} {
 
        set sob "Signed-off-by: $GIT_COMMITTER_IDENT"
        set last [$ui_comm get {end -1c linestart} {end -1c}]
-       if {$last != $sob} {
+       if {$last ne $sob} {
                $ui_comm edit separator
-               if {$last != {}
+               if {$last ne {}
                        && ![regexp {^[A-Z][A-Za-z]*-[A-Za-z-]+: *} $last]} {
                        $ui_comm insert end "\n"
                }
@@ -1747,12 +1773,18 @@ proc do_options {} {
        global repo_config global_config
        global repo_config_new global_config_new
 
-       load_config 1
        array unset repo_config_new
        array unset global_config_new
        foreach name [array names repo_config] {
                set repo_config_new($name) $repo_config($name)
        }
+       load_config 1
+       foreach name [array names repo_config] {
+               switch -- $name {
+               gui.diffcontext {continue}
+               }
+               set repo_config_new($name) $repo_config($name)
+       }
        foreach name [array names global_config] {
                set global_config_new($name) $global_config($name)
        }
@@ -1793,18 +1825,36 @@ proc do_options {} {
        pack $w.global -side right -fill both -expand 1 -pady 5 -padx 5
 
        foreach option {
-               {pullsummary {Show Pull Summary}}
-               {trustmtime {Trust File Modification Timestamps}}
+               {b pullsummary {Show Pull Summary}}
+               {b trustmtime  {Trust File Modification Timestamps}}
+               {i diffcontext {Number of Diff Context Lines}}
                } {
-               set name [lindex $option 0]
-               set text [lindex $option 1]
+               set type [lindex $option 0]
+               set name [lindex $option 1]
+               set text [lindex $option 2]
                foreach f {repo global} {
-                       checkbutton $w.$f.$name -text $text \
-                               -variable ${f}_config_new(gui.$name) \
-                               -onvalue true \
-                               -offvalue false \
-                               -font font_ui
-                       pack $w.$f.$name -side top -anchor w
+                       switch $type {
+                       b {
+                               checkbutton $w.$f.$name -text $text \
+                                       -variable ${f}_config_new(gui.$name) \
+                                       -onvalue true \
+                                       -offvalue false \
+                                       -font font_ui
+                               pack $w.$f.$name -side top -anchor w
+                       }
+                       i {
+                               frame $w.$f.$name
+                               label $w.$f.$name.l -text "$text:" -font font_ui
+                               pack $w.$f.$name.l -side left -anchor w -fill x
+                               spinbox $w.$f.$name.v \
+                                       -textvariable ${f}_config_new(gui.$name) \
+                                       -from 1 -to 99 -increment 1 \
+                                       -width 3 \
+                                       -font font_ui
+                               pack $w.$f.$name.v -side right -anchor e
+                               pack $w.$f.$name -side top -anchor w -fill x
+                       }
+                       }
                }
        }
 
@@ -1870,6 +1920,7 @@ proc do_save_config {w} {
        if {[catch {save_config} err]} {
                error_popup "Failed to completely save options:\n\n$err"
        }
+       reshow_diff
        destroy $w
 }
 
@@ -1882,7 +1933,7 @@ proc click {w x y shift wx wy} {
        set lno [lindex $pos 0]
        set col [lindex $pos 1]
        set path [lindex $file_lists($w) [expr $lno - 1]]
-       if {$path == {}} return
+       if {$path eq {}} return
 
        if {$col > 0 && $shift == 1} {
                show_diff $path $w $lno
@@ -1896,7 +1947,7 @@ proc unclick {w x y} {
        set lno [lindex $pos 0]
        set col [lindex $pos 1]
        set path [lindex $file_lists($w) [expr $lno - 1]]
-       if {$path == {}} return
+       if {$path eq {}} return
 
        if {$col == 0} {
                update_index [list $path]
@@ -1921,7 +1972,7 @@ font create font_diffbold
 
 set M1B M1
 set M1T M1
-if {$tcl_platform(platform) == {windows}} {
+if {$tcl_platform(platform) eq {windows}} {
        set M1B Control
        set M1T Ctrl
 } elseif {[is_MacOSX]} {
@@ -1951,6 +2002,7 @@ proc apply_config {} {
 
 set default_config(gui.trustmtime) false
 set default_config(gui.pullsummary) true
+set default_config(gui.diffcontext) 5
 set default_config(gui.fontui) [font configure font_ui]
 set default_config(gui.fontdiff) [font configure font_diff]
 set font_descs {
@@ -2300,6 +2352,21 @@ $ui_diff.ctxm add command -label "Decrease Font Size" \
 $ui_diff.ctxm add command -label "Increase Font Size" \
        -font font_ui \
        -command {incr_font_size font_diff 1}
+$ui_diff.ctxm add separator
+$ui_diff.ctxm add command -label "Show Less Context" \
+       -font font_ui \
+       -command {if {$ui_fname_value ne {}
+               && $repo_config(gui.diffcontext) >= 2} {
+               incr repo_config(gui.diffcontext) -1
+               reshow_diff
+       }}
+$ui_diff.ctxm add command -label "Show More Context" \
+       -font font_ui \
+       -command {if {$ui_fname_value ne {}} {
+               incr repo_config(gui.diffcontext)
+               reshow_diff
+       }}
+$ui_diff.ctxm add separator
 $ui_diff.ctxm add command -label {Options...} \
        -font font_ui \
        -command do_options