]> asedeno.scripts.mit.edu Git - git.git/blobdiff - git-gui.sh
git-gui: update po/it.po
[git.git] / git-gui.sh
index 743b7d41968c3c68f7e31756208d15e60a5b4cca..14b2d9aacd1d28084f195365b434747df2ddc95d 100755 (executable)
@@ -6,11 +6,12 @@
        echo 'git-gui version @@GITGUI_VERSION@@'; \
        exit; \
  fi; \
        echo 'git-gui version @@GITGUI_VERSION@@'; \
        exit; \
  fi; \
- exec wish "$0" -- "$@"
+ argv0=$0; \
+ exec wish "$argv0" -- "$@"
 
 set appvers {@@GITGUI_VERSION@@}
 
 set appvers {@@GITGUI_VERSION@@}
-set copyright {
-Copyright © 2006, 2007 Shawn Pearce, et. al.
+set copyright [encoding convertfrom utf-8 {
+Copyright Â© 2006, 2007 Shawn Pearce, et. al.
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -24,7 +25,7 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA}
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA}]
 
 ######################################################################
 ##
 
 ######################################################################
 ##
@@ -37,11 +38,31 @@ if {[catch {package require Tcl 8.4} err]
        tk_messageBox \
                -icon error \
                -type ok \
        tk_messageBox \
                -icon error \
                -type ok \
-               -title "git-gui: fatal error" \
+               -title [mc "git-gui: fatal error"] \
                -message $err
        exit 1
 }
 
                -message $err
        exit 1
 }
 
+catch {rename send {}} ; # What an evil concept...
+
+######################################################################
+##
+## locate our library
+
+set oguilib {@@GITGUI_LIBDIR@@}
+set oguirel {@@GITGUI_RELATIVE@@}
+if {$oguirel eq {1}} {
+       set oguilib [file dirname [file dirname [file normalize $argv0]]]
+       set oguilib [file join $oguilib share git-gui lib]
+       set oguimsg [file join $oguilib msgs]
+} elseif {[string match @@* $oguirel]} {
+       set oguilib [file join [file dirname [file normalize $argv0]] lib]
+       set oguimsg [file join [file dirname [file normalize $argv0]] po]
+} else {
+       set oguimsg [file join $oguilib msgs]
+}
+unset oguirel
+
 ######################################################################
 ##
 ## enable verbose loading?
 ######################################################################
 ##
 ## enable verbose loading?
@@ -60,17 +81,55 @@ if {![catch {set _verbose $env(GITGUI_VERBOSE)}]} {
        }
 }
 
        }
 }
 
+######################################################################
+##
+## Internationalization (i18n) through msgcat and gettext. See
+## http://www.gnu.org/software/gettext/manual/html_node/Tcl.html
+
+package require msgcat
+
+proc _mc_trim {fmt} {
+       set cmk [string first @@ $fmt]
+       if {$cmk > 0} {
+               return [string range $fmt 0 [expr {$cmk - 1}]]
+       }
+       return $fmt
+}
+
+proc mc {en_fmt args} {
+       set fmt [_mc_trim [::msgcat::mc $en_fmt]]
+       if {[catch {set msg [eval [list format $fmt] $args]} err]} {
+               set msg [eval [list format [_mc_trim $en_fmt]] $args]
+       }
+       return $msg
+}
+
+proc strcat {args} {
+       return [join $args {}]
+}
+
+::msgcat::mcload $oguimsg
+unset oguimsg
+
 ######################################################################
 ##
 ## read only globals
 
 ######################################################################
 ##
 ## read only globals
 
-set _appname [lindex [file split $argv0] end]
+set _appname {Git Gui}
 set _gitdir {}
 set _gitexec {}
 set _reponame {}
 set _iscygwin {}
 set _search_path {}
 
 set _gitdir {}
 set _gitexec {}
 set _reponame {}
 set _iscygwin {}
 set _search_path {}
 
+set _trace [lsearch -exact $argv --trace]
+if {$_trace >= 0} {
+       set argv [lreplace $argv $_trace $_trace]
+       set _trace 1
+} else {
+       set _trace 0
+}
+
 proc appname {} {
        global _appname
        return $_appname
 proc appname {} {
        global _appname
        return $_appname
@@ -161,6 +220,7 @@ proc disable_option {option} {
 
 proc is_many_config {name} {
        switch -glob -- $name {
 
 proc is_many_config {name} {
        switch -glob -- $name {
+       gui.recentrepo -
        remote.*.fetch -
        remote.*.push
                {return 1}
        remote.*.fetch -
        remote.*.push
                {return 1}
@@ -189,55 +249,25 @@ proc get_config {name} {
        }
 }
 
        }
 }
 
-proc load_config {include_global} {
-       global repo_config global_config default_config
-
-       array unset global_config
-       if {$include_global} {
-               catch {
-                       set fd_rc [git_read config --global --list]
-                       while {[gets $fd_rc line] >= 0} {
-                               if {[regexp {^([^=]+)=(.*)$} $line line name value]} {
-                                       if {[is_many_config $name]} {
-                                               lappend global_config($name) $value
-                                       } else {
-                                               set global_config($name) $value
-                                       }
-                               }
-                       }
-                       close $fd_rc
-               }
-       }
-
-       array unset repo_config
-       catch {
-               set fd_rc [git_read config --list]
-               while {[gets $fd_rc line] >= 0} {
-                       if {[regexp {^([^=]+)=(.*)$} $line line name value]} {
-                               if {[is_many_config $name]} {
-                                       lappend repo_config($name) $value
-                               } else {
-                                       set repo_config($name) $value
-                               }
-                       }
-               }
-               close $fd_rc
-       }
+######################################################################
+##
+## handy utils
 
 
-       foreach name [array names default_config] {
-               if {[catch {set v $global_config($name)}]} {
-                       set global_config($name) $default_config($name)
+proc _trace_exec {cmd} {
+       if {!$::_trace} return
+       set d {}
+       foreach v $cmd {
+               if {$d ne {}} {
+                       append d { }
                }
                }
-               if {[catch {set v $repo_config($name)}]} {
-                       set repo_config($name) $default_config($name)
+               if {[regexp {[ \t\r\n'"$?*]} $v]} {
+                       set v [sq $v]
                }
                }
+               append d $v
        }
        }
+       puts stderr $d
 }
 
 }
 
-######################################################################
-##
-## handy utils
-
 proc _git_cmd {name} {
        global _git_cmd_path
 
 proc _git_cmd {name} {
        global _git_cmd_path
 
@@ -261,7 +291,7 @@ proc _git_cmd {name} {
                        set s [gets $f]
                        close $f
 
                        set s [gets $f]
                        close $f
 
-                       switch -glob -- $s {
+                       switch -glob -- [lindex $s 0] {
                        #!*sh     { set i sh     }
                        #!*perl   { set i perl   }
                        #!*python { set i python }
                        #!*sh     { set i sh     }
                        #!*perl   { set i perl   }
                        #!*python { set i python }
@@ -275,7 +305,7 @@ proc _git_cmd {name} {
                        if {$interp eq {}} {
                                error "git-$name requires $i (not in PATH)"
                        }
                        if {$interp eq {}} {
                                error "git-$name requires $i (not in PATH)"
                        }
-                       set v [list $interp $p]
+                       set v [concat [list $interp] [lrange $s 1 end] [list $p]]
                } else {
                        # Assume it is builtin to git somehow and we
                        # aren't actually able to see a file for it.
                } else {
                        # Assume it is builtin to git somehow and we
                        # aren't actually able to see a file for it.
@@ -287,11 +317,11 @@ proc _git_cmd {name} {
        return $v
 }
 
        return $v
 }
 
-proc _which {what} {
+proc _which {what args} {
        global env _search_exe _search_path
 
        if {$_search_path eq {}} {
        global env _search_exe _search_path
 
        if {$_search_path eq {}} {
-               if {[is_Cygwin]} {
+               if {[is_Cygwin] && [regexp {^(/|\.:)} $env(PATH)]} {
                        set _search_path [split [exec cygpath \
                                --windows \
                                --path \
                        set _search_path [split [exec cygpath \
                                --windows \
                                --path \
@@ -299,6 +329,9 @@ proc _which {what} {
                                $env(PATH)] {;}]
                        set _search_exe .exe
                } elseif {[is_Windows]} {
                                $env(PATH)] {;}]
                        set _search_exe .exe
                } elseif {[is_Windows]} {
+                       set gitguidir [file dirname [info script]]
+                       regsub -all ";" $gitguidir "\\;" gitguidir
+                       set env(PATH) "$gitguidir;$env(PATH)"
                        set _search_path [split $env(PATH) {;}]
                        set _search_exe .exe
                } else {
                        set _search_path [split $env(PATH) {;}]
                        set _search_exe .exe
                } else {
@@ -307,8 +340,14 @@ proc _which {what} {
                }
        }
 
                }
        }
 
+       if {[is_Windows] && [lsearch -exact $args -script] >= 0} {
+               set suffix {}
+       } else {
+               set suffix $_search_exe
+       }
+
        foreach p $_search_path {
        foreach p $_search_path {
-               set p [file join $p $what$_search_exe]
+               set p [file join $p $what$suffix]
                if {[file exists $p]} {
                        return [file normalize $p]
                }
                if {[file exists $p]} {
                        return [file normalize $p]
                }
@@ -329,7 +368,7 @@ proc _lappend_nice {cmd_var} {
 }
 
 proc git {args} {
 }
 
 proc git {args} {
-       set opt [list exec]
+       set opt [list]
 
        while {1} {
                switch -- [lindex $args 0] {
 
        while {1} {
                switch -- [lindex $args 0] {
@@ -349,12 +388,18 @@ proc git {args} {
        set cmdp [_git_cmd [lindex $args 0]]
        set args [lrange $args 1 end]
 
        set cmdp [_git_cmd [lindex $args 0]]
        set args [lrange $args 1 end]
 
-       return [eval $opt $cmdp $args]
+       _trace_exec [concat $opt $cmdp $args]
+       set result [eval exec $opt $cmdp $args]
+       if {$::_trace} {
+               puts stderr "< $result"
+       }
+       return $result
 }
 
 proc _open_stdout_stderr {cmd} {
 }
 
 proc _open_stdout_stderr {cmd} {
+       _trace_exec $cmd
        if {[catch {
        if {[catch {
-                       set fd [open $cmd r]
+                       set fd [open [concat [list | ] $cmd] r]
                } err]} {
                if {   [lindex $cmd end] eq {2>@1}
                    && $err eq {can not find channel named "1"}
                } err]} {
                if {   [lindex $cmd end] eq {2>@1}
                    && $err eq {can not find channel named "1"}
@@ -365,6 +410,7 @@ proc _open_stdout_stderr {cmd} {
                        # to try to start it a second time.
                        #
                        set fd [open [concat \
                        # to try to start it a second time.
                        #
                        set fd [open [concat \
+                               [list | ] \
                                [lrange $cmd 0 end-1] \
                                [list |& cat] \
                                ] r]
                                [lrange $cmd 0 end-1] \
                                [list |& cat] \
                                ] r]
@@ -377,7 +423,7 @@ proc _open_stdout_stderr {cmd} {
 }
 
 proc git_read {args} {
 }
 
 proc git_read {args} {
-       set opt [list |]
+       set opt [list]
 
        while {1} {
                switch -- [lindex $args 0] {
 
        while {1} {
                switch -- [lindex $args 0] {
@@ -405,7 +451,7 @@ proc git_read {args} {
 }
 
 proc git_write {args} {
 }
 
 proc git_write {args} {
-       set opt [list |]
+       set opt [list]
 
        while {1} {
                switch -- [lindex $args 0] {
 
        while {1} {
                switch -- [lindex $args 0] {
@@ -425,7 +471,50 @@ proc git_write {args} {
        set cmdp [_git_cmd [lindex $args 0]]
        set args [lrange $args 1 end]
 
        set cmdp [_git_cmd [lindex $args 0]]
        set args [lrange $args 1 end]
 
-       return [open [concat $opt $cmdp $args] w]
+       _trace_exec [concat $opt $cmdp $args]
+       return [open [concat [list | ] $opt $cmdp $args] w]
+}
+
+proc githook_read {hook_name args} {
+       set pchook [gitdir hooks $hook_name]
+       lappend args 2>@1
+
+       # On Windows [file executable] might lie so we need to ask
+       # the shell if the hook is executable.  Yes that's annoying.
+       #
+       if {[is_Windows]} {
+               upvar #0 _sh interp
+               if {![info exists interp]} {
+                       set interp [_which sh]
+               }
+               if {$interp eq {}} {
+                       error "hook execution requires sh (not in PATH)"
+               }
+
+               set scr {if test -x "$1";then exec "$@";fi}
+               set sh_c [list $interp -c $scr $interp $pchook]
+               return [_open_stdout_stderr [concat $sh_c $args]]
+       }
+
+       if {[file executable $pchook]} {
+               return [_open_stdout_stderr [concat [list $pchook] $args]]
+       }
+
+       return {}
+}
+
+proc kill_file_process {fd} {
+       set process [pid $fd]
+
+       catch {
+               if {[is_Windows]} {
+                       # Use a Cygwin-specific flag to allow killing
+                       # native Windows processes
+                       exec kill -f $process
+               } else {
+                       exec kill $process
+               }
+       }
 }
 
 proc sq {value} {
 }
 
 proc sq {value} {
@@ -467,6 +556,125 @@ proc tk_optionMenu {w varName args} {
        return $m
 }
 
        return $m
 }
 
+proc rmsel_tag {text} {
+       $text tag conf sel \
+               -background [$text cget -background] \
+               -foreground [$text cget -foreground] \
+               -borderwidth 0
+       $text tag conf in_sel -background lightgray
+       bind $text <Motion> break
+       return $text
+}
+
+set root_exists 0
+bind . <Visibility> {
+       bind . <Visibility> {}
+       set root_exists 1
+}
+
+if {[is_Windows]} {
+       wm iconbitmap . -default $oguilib/git-gui.ico
+}
+
+######################################################################
+##
+## config defaults
+
+set cursor_ptr arrow
+font create font_diff -family Courier -size 10
+font create font_ui
+catch {
+       label .dummy
+       eval font configure font_ui [font actual [.dummy cget -font]]
+       destroy .dummy
+}
+
+font create font_uiitalic
+font create font_uibold
+font create font_diffbold
+font create font_diffitalic
+
+foreach class {Button Checkbutton Entry Label
+               Labelframe Listbox Menu Message
+               Radiobutton Spinbox Text} {
+       option add *$class.font font_ui
+}
+unset class
+
+if {[is_Windows] || [is_MacOSX]} {
+       option add *Menu.tearOff 0
+}
+
+if {[is_MacOSX]} {
+       set M1B M1
+       set M1T Cmd
+} else {
+       set M1B Control
+       set M1T Ctrl
+}
+
+proc bind_button3 {w cmd} {
+       bind $w <Any-Button-3> $cmd
+       if {[is_MacOSX]} {
+               # Mac OS X sends Button-2 on right click through three-button mouse,
+               # or through trackpad right-clicking (two-finger touch + click).
+               bind $w <Any-Button-2> $cmd
+               bind $w <Control-Button-1> $cmd
+       }
+}
+
+proc apply_config {} {
+       global repo_config font_descs
+
+       foreach option $font_descs {
+               set name [lindex $option 0]
+               set font [lindex $option 1]
+               if {[catch {
+                       set need_weight 1
+                       foreach {cn cv} $repo_config(gui.$name) {
+                               if {$cn eq {-weight}} {
+                                       set need_weight 0
+                               }
+                               font configure $font $cn $cv
+                       }
+                       if {$need_weight} {
+                               font configure $font -weight normal
+                       }
+                       } err]} {
+                       error_popup [strcat [mc "Invalid font specified in %s:" "gui.$name"] "\n\n$err"]
+               }
+               foreach {cn cv} [font configure $font] {
+                       font configure ${font}bold $cn $cv
+                       font configure ${font}italic $cn $cv
+               }
+               font configure ${font}bold -weight bold
+               font configure ${font}italic -slant italic
+       }
+}
+
+set default_config(branch.autosetupmerge) true
+set default_config(merge.diffstat) true
+set default_config(merge.summary) false
+set default_config(merge.verbosity) 2
+set default_config(user.name) {}
+set default_config(user.email) {}
+
+set default_config(gui.matchtrackingbranch) false
+set default_config(gui.pruneduringfetch) false
+set default_config(gui.trustmtime) false
+set default_config(gui.fastcopyblame) false
+set default_config(gui.copyblamethreshold) 40
+set default_config(gui.diffcontext) 5
+set default_config(gui.commitmsgwidth) 75
+set default_config(gui.newbranchtemplate) {}
+set default_config(gui.spellingdictionary) {}
+set default_config(gui.fontui) [font configure font_ui]
+set default_config(gui.fontdiff) [font configure font_diff]
+set font_descs {
+       {fontui   font_ui   {mc "Main Font"}}
+       {fontdiff font_diff {mc "Diff/Console Font"}}
+}
+
 ######################################################################
 ##
 ## find git
 ######################################################################
 ##
 ## find git
@@ -474,7 +682,11 @@ proc tk_optionMenu {w varName args} {
 set _git  [_which git]
 if {$_git eq {}} {
        catch {wm withdraw .}
 set _git  [_which git]
 if {$_git eq {}} {
        catch {wm withdraw .}
-       error_popup "Cannot find git in PATH."
+       tk_messageBox \
+               -icon error \
+               -type ok \
+               -title [mc "git-gui: fatal error"] \
+               -message [mc "Cannot find git in PATH."]
        exit 1
 }
 
        exit 1
 }
 
@@ -487,7 +699,7 @@ if {[catch {set _git_version [git --version]} err]} {
        tk_messageBox \
                -icon error \
                -type ok \
        tk_messageBox \
                -icon error \
                -type ok \
-               -title "git-gui: fatal error" \
+               -title [mc "git-gui: fatal error"] \
                -message "Cannot determine Git version:
 
 $err
                -message "Cannot determine Git version:
 
 $err
@@ -500,16 +712,17 @@ if {![regsub {^git version } $_git_version {} _git_version]} {
        tk_messageBox \
                -icon error \
                -type ok \
        tk_messageBox \
                -icon error \
                -type ok \
-               -title "git-gui: fatal error" \
-               -message "Cannot parse Git version string:\n\n$_git_version"
+               -title [mc "git-gui: fatal error"] \
+               -message [strcat [mc "Cannot parse Git version string:"] "\n\n$_git_version"]
        exit 1
 }
 
 set _real_git_version $_git_version
        exit 1
 }
 
 set _real_git_version $_git_version
-regsub -- {-dirty$} $_git_version {} _git_version
+regsub -- {[\-\.]dirty$} $_git_version {} _git_version
 regsub {\.[0-9]+\.g[0-9a-f]+$} $_git_version {} _git_version
 regsub {\.rc[0-9]+$} $_git_version {} _git_version
 regsub {\.GIT$} $_git_version {} _git_version
 regsub {\.[0-9]+\.g[0-9a-f]+$} $_git_version {} _git_version
 regsub {\.rc[0-9]+$} $_git_version {} _git_version
 regsub {\.GIT$} $_git_version {} _git_version
+regsub {\.[a-zA-Z]+\.[0-9]+$} $_git_version {} _git_version
 
 if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} {
        catch {wm withdraw .}
 
 if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} {
        catch {wm withdraw .}
@@ -518,14 +731,14 @@ if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} {
                -type yesno \
                -default no \
                -title "[appname]: warning" \
                -type yesno \
                -default no \
                -title "[appname]: warning" \
-               -message "Git version cannot be determined.
+                -message [mc "Git version cannot be determined.
 
 
-$_git claims it is version '$_real_git_version'.
+%s claims it is version '%s'.
 
 
-[appname] requires at least Git 1.5.0 or later.
+%s requires at least Git 1.5.0 or later.
 
 
-Assume '$_real_git_version' is version 1.5.0?
-"] eq {yes}} {
+Assume '%s' is version 1.5.0?
+" $_git $_real_git_version [appname] $_real_git_version]] eq {yes}} {
                set _git_version 1.5.0
        } else {
                exit 1
                set _git_version 1.5.0
        } else {
                exit 1
@@ -582,7 +795,7 @@ if {[git-version < 1.5]} {
        tk_messageBox \
                -icon error \
                -type ok \
        tk_messageBox \
                -icon error \
                -type ok \
-               -title "git-gui: fatal error" \
+               -title [mc "git-gui: fatal error"] \
                -message "[appname] requires Git 1.5.0 or later.
 
 You are using [git-version]:
                -message "[appname] requires Git 1.5.0 or later.
 
 You are using [git-version]:
@@ -595,22 +808,13 @@ You are using [git-version]:
 ##
 ## configure our library
 
 ##
 ## configure our library
 
-set oguilib {@@GITGUI_LIBDIR@@}
-set oguirel {@@GITGUI_RELATIVE@@}
-if {$oguirel eq {1}} {
-       set oguilib [file dirname [file dirname [file normalize $argv0]]]
-       set oguilib [file join $oguilib share git-gui lib]
-} elseif {[string match @@* $oguirel]} {
-       set oguilib [file join [file dirname [file normalize $argv0]] lib]
-}
-
 set idx [file join $oguilib tclIndex]
 if {[catch {set fd [open $idx r]} err]} {
        catch {wm withdraw .}
        tk_messageBox \
                -icon error \
                -type ok \
 set idx [file join $oguilib tclIndex]
 if {[catch {set fd [open $idx r]} err]} {
        catch {wm withdraw .}
        tk_messageBox \
                -icon error \
                -type ok \
-               -title "git-gui: fatal error" \
+               -title [mc "git-gui: fatal error"] \
                -message $err
        exit 1
 }
                -message $err
        exit 1
 }
@@ -637,13 +841,78 @@ if {$idx ne {}} {
 } else {
        set auto_path [concat [list $oguilib] $auto_path]
 }
 } else {
        set auto_path [concat [list $oguilib] $auto_path]
 }
-unset -nocomplain oguirel idx fd
+unset -nocomplain idx fd
+
+######################################################################
+##
+## config file parsing
+
+git-version proc _parse_config {arr_name args} {
+       >= 1.5.3 {
+               upvar $arr_name arr
+               array unset arr
+               set buf {}
+               catch {
+                       set fd_rc [eval \
+                               [list git_read config] \
+                               $args \
+                               [list --null --list]]
+                       fconfigure $fd_rc -translation binary
+                       set buf [read $fd_rc]
+                       close $fd_rc
+               }
+               foreach line [split $buf "\0"] {
+                       if {[regexp {^([^\n]+)\n(.*)$} $line line name value]} {
+                               if {[is_many_config $name]} {
+                                       lappend arr($name) $value
+                               } else {
+                                       set arr($name) $value
+                               }
+                       }
+               }
+       }
+       default {
+               upvar $arr_name arr
+               array unset arr
+               catch {
+                       set fd_rc [eval [list git_read config --list] $args]
+                       while {[gets $fd_rc line] >= 0} {
+                               if {[regexp {^([^=]+)=(.*)$} $line line name value]} {
+                                       if {[is_many_config $name]} {
+                                               lappend arr($name) $value
+                                       } else {
+                                               set arr($name) $value
+                                       }
+                               }
+                       }
+                       close $fd_rc
+               }
+       }
+}
+
+proc load_config {include_global} {
+       global repo_config global_config default_config
+
+       if {$include_global} {
+               _parse_config global_config --global
+       }
+       _parse_config repo_config
+
+       foreach name [array names default_config] {
+               if {[catch {set v $global_config($name)}]} {
+                       set global_config($name) $default_config($name)
+               }
+               if {[catch {set v $repo_config($name)}]} {
+                       set repo_config($name) $default_config($name)
+               }
+       }
+}
 
 ######################################################################
 ##
 ## feature option selection
 
 
 ######################################################################
 ##
 ## feature option selection
 
-if {[regexp {^git-(.+)$} [appname] _junk subcommand]} {
+if {[regexp {^git-(.+)$} [file tail $argv0] _junk subcommand]} {
        unset _junk
 } else {
        set subcommand gui
        unset _junk
 } else {
        set subcommand gui
@@ -691,27 +960,35 @@ if {[catch {
                set _gitdir [git rev-parse --git-dir]
                set _prefix [git rev-parse --show-prefix]
        } err]} {
                set _gitdir [git rev-parse --git-dir]
                set _prefix [git rev-parse --show-prefix]
        } err]} {
-       catch {wm withdraw .}
-       error_popup "Cannot find the git directory:\n\n$err"
-       exit 1
+       load_config 1
+       apply_config
+       choose_repository::pick
 }
 if {![file isdirectory $_gitdir] && [is_Cygwin]} {
 }
 if {![file isdirectory $_gitdir] && [is_Cygwin]} {
-       catch {set _gitdir [exec cygpath --unix $_gitdir]}
+       catch {set _gitdir [exec cygpath --windows $_gitdir]}
 }
 if {![file isdirectory $_gitdir]} {
        catch {wm withdraw .}
 }
 if {![file isdirectory $_gitdir]} {
        catch {wm withdraw .}
-       error_popup "Git directory not found:\n\n$_gitdir"
+       error_popup [strcat [mc "Git directory not found:"] "\n\n$_gitdir"]
        exit 1
 }
        exit 1
 }
-if {![is_enabled bare]} {
+if {$_prefix ne {}} {
+       regsub -all {[^/]+/} $_prefix ../ cdup
+       if {[catch {cd $cdup} err]} {
+               catch {wm withdraw .}
+               error_popup [strcat [mc "Cannot move to top of working directory:"] "\n\n$err"]
+               exit 1
+       }
+       unset cdup
+} elseif {![is_enabled bare]} {
        if {[lindex [file split $_gitdir] end] ne {.git}} {
                catch {wm withdraw .}
        if {[lindex [file split $_gitdir] end] ne {.git}} {
                catch {wm withdraw .}
-               error_popup "Cannot use funny .git directory:\n\n$_gitdir"
+               error_popup [strcat [mc "Cannot use funny .git directory:"] "\n\n$_gitdir"]
                exit 1
        }
        if {[catch {cd [file dirname $_gitdir]} err]} {
                catch {wm withdraw .}
                exit 1
        }
        if {[catch {cd [file dirname $_gitdir]} err]} {
                catch {wm withdraw .}
-               error_popup "No working directory [file dirname $_gitdir]:\n\n$err"
+               error_popup [strcat [mc "No working directory"] " [file dirname $_gitdir]:\n\n$err"]
                exit 1
        }
 }
                exit 1
        }
 }
@@ -858,7 +1135,7 @@ proc rescan {after {honor_trustmtime 1}} {
                rescan_stage2 {} $after
        } else {
                set rescan_active 1
                rescan_stage2 {} $after
        } else {
                set rescan_active 1
-               ui_status {Refreshing file status...}
+               ui_status [mc "Refreshing file status..."]
                set fd_rf [git_read update-index \
                        -q \
                        --unmerged \
                set fd_rf [git_read update-index \
                        -q \
                        --unmerged \
@@ -871,6 +1148,26 @@ proc rescan {after {honor_trustmtime 1}} {
        }
 }
 
        }
 }
 
+if {[is_Cygwin]} {
+       set is_git_info_exclude {}
+       proc have_info_exclude {} {
+               global is_git_info_exclude
+
+               if {$is_git_info_exclude eq {}} {
+                       if {[catch {exec test -f [gitdir info exclude]}]} {
+                               set is_git_info_exclude 0
+                       } else {
+                               set is_git_info_exclude 1
+                       }
+               }
+               return $is_git_info_exclude
+       }
+} else {
+       proc have_info_exclude {} {
+               return [file readable [gitdir info exclude]]
+       }
+}
+
 proc rescan_stage2 {fd after} {
        global rescan_active buf_rdi buf_rdf buf_rlo
 
 proc rescan_stage2 {fd after} {
        global rescan_active buf_rdi buf_rdf buf_rlo
 
@@ -881,9 +1178,8 @@ proc rescan_stage2 {fd after} {
        }
 
        set ls_others [list --exclude-per-directory=.gitignore]
        }
 
        set ls_others [list --exclude-per-directory=.gitignore]
-       set info_exclude [gitdir info exclude]
-       if {[file readable $info_exclude]} {
-               lappend ls_others "--exclude-from=$info_exclude"
+       if {[have_info_exclude]} {
+               lappend ls_others "--exclude-from=[gitdir info exclude]"
        }
        set user_exclude [get_config core.excludesfile]
        if {$user_exclude ne {} && [file readable $user_exclude]} {
        }
        set user_exclude [get_config core.excludesfile]
        if {$user_exclude ne {} && [file readable $user_exclude]} {
@@ -895,7 +1191,7 @@ proc rescan_stage2 {fd after} {
        set buf_rlo {}
 
        set rescan_active 3
        set buf_rlo {}
 
        set rescan_active 3
-       ui_status {Scanning for modified files ...}
+       ui_status [mc "Scanning for modified files ..."]
        set fd_di [git_read diff-index --cached -z [PARENT]]
        set fd_df [git_read diff-files -z]
        set fd_lo [eval git_read ls-files --others -z $ls_others]
        set fd_di [git_read diff-index --cached -z [PARENT]]
        set fd_df [git_read diff-files -z]
        set fd_lo [eval git_read ls-files --others -z $ls_others]
@@ -1000,7 +1296,11 @@ proc read_ls_others {fd after} {
        set pck [split $buf_rlo "\0"]
        set buf_rlo [lindex $pck end]
        foreach p [lrange $pck 0 end-1] {
        set pck [split $buf_rlo "\0"]
        set buf_rlo [lindex $pck end]
        foreach p [lrange $pck 0 end-1] {
-               merge_state [encoding convertfrom $p] ?O
+               set p [encoding convertfrom $p]
+               if {[string index $p end] eq {/}} {
+                       set p [string range $p 0 end-1]
+               }
+               merge_state $p ?O
        }
        rescan_done $fd buf_rlo $after
 }
        }
        rescan_done $fd buf_rlo $after
 }
@@ -1057,11 +1357,17 @@ proc mapdesc {state path} {
 }
 
 proc ui_status {msg} {
 }
 
 proc ui_status {msg} {
-       $::main_status show $msg
+       global main_status
+       if {[info exists main_status]} {
+               $main_status show $msg
+       }
 }
 
 proc ui_ready {{test {}}} {
 }
 
 proc ui_ready {{test {}}} {
-       $::main_status show {Ready.} $test
+       global main_status
+       if {[info exists main_status]} {
+               $main_status show [mc "Ready."] $test
+       }
 }
 
 proc escape_path {path} {
 }
 
 proc escape_path {path} {
@@ -1326,31 +1632,32 @@ set all_icons(O$ui_workdir) file_plain
 
 set max_status_desc 0
 foreach i {
 
 set max_status_desc 0
 foreach i {
-               {__ "Unmodified"}
-
-               {_M "Modified, not staged"}
-               {M_ "Staged for commit"}
-               {MM "Portions staged for commit"}
-               {MD "Staged for commit, missing"}
-
-               {_O "Untracked, not staged"}
-               {A_ "Staged for commit"}
-               {AM "Portions staged for commit"}
-               {AD "Staged for commit, missing"}
-
-               {_D "Missing"}
-               {D_ "Staged for removal"}
-               {DO "Staged for removal, still present"}
-
-               {U_ "Requires merge resolution"}
-               {UU "Requires merge resolution"}
-               {UM "Requires merge resolution"}
-               {UD "Requires merge resolution"}
+               {__ {mc "Unmodified"}}
+
+               {_M {mc "Modified, not staged"}}
+               {M_ {mc "Staged for commit"}}
+               {MM {mc "Portions staged for commit"}}
+               {MD {mc "Staged for commit, missing"}}
+
+               {_O {mc "Untracked, not staged"}}
+               {A_ {mc "Staged for commit"}}
+               {AM {mc "Portions staged for commit"}}
+               {AD {mc "Staged for commit, missing"}}
+
+               {_D {mc "Missing"}}
+               {D_ {mc "Staged for removal"}}
+               {DO {mc "Staged for removal, still present"}}
+
+               {U_ {mc "Requires merge resolution"}}
+               {UU {mc "Requires merge resolution"}}
+               {UM {mc "Requires merge resolution"}}
+               {UD {mc "Requires merge resolution"}}
        } {
        } {
-       if {$max_status_desc < [string length [lindex $i 1]]} {
-               set max_status_desc [string length [lindex $i 1]]
+       set text [eval [lindex $i 1]]
+       if {$max_status_desc < [string length $text]} {
+               set max_status_desc [string length $text]
        }
        }
-       set all_descs([lindex $i 0]) [lindex $i 1]
+       set all_descs([lindex $i 0]) $text
 }
 unset i
 
 }
 unset i
 
@@ -1358,16 +1665,6 @@ unset i
 ##
 ## util
 
 ##
 ## util
 
-proc bind_button3 {w cmd} {
-       bind $w <Any-Button-3> $cmd
-       if {[is_MacOSX]} {
-               # Mac OS X sends Button-2 on right click through three-button mouse,
-               # or through trackpad right-clicking (two-finger touch + click).
-               bind $w <Any-Button-2> $cmd
-               bind $w <Control-Button-1> $cmd
-       }
-}
-
 proc scrollbar2many {list mode args} {
        foreach w $list {eval $w $mode $args}
 }
 proc scrollbar2many {list mode args} {
        foreach w $list {eval $w $mode $args}
 }
@@ -1389,18 +1686,38 @@ proc incr_font_size {font {amt 1}} {
 ##
 ## ui commands
 
 ##
 ## ui commands
 
-set starting_gitk_msg {Starting gitk... please wait...}
+set starting_gitk_msg [mc "Starting gitk... please wait..."]
 
 proc do_gitk {revs} {
        # -- Always start gitk through whatever we were loaded with.  This
        #    lets us bypass using shell process on Windows systems.
        #
 
 proc do_gitk {revs} {
        # -- Always start gitk through whatever we were loaded with.  This
        #    lets us bypass using shell process on Windows systems.
        #
-       set exe [file join [file dirname $::_git] gitk]
+       set exe [_which gitk -script]
        set cmd [list [info nameofexecutable] $exe]
        set cmd [list [info nameofexecutable] $exe]
-       if {! [file exists $exe]} {
-               error_popup "Unable to start gitk:\n\n$exe does not exist"
+       if {$exe eq {}} {
+               error_popup [mc "Couldn't find gitk in PATH"]
        } else {
        } else {
+               global env
+
+               if {[info exists env(GIT_DIR)]} {
+                       set old_GIT_DIR $env(GIT_DIR)
+               } else {
+                       set old_GIT_DIR {}
+               }
+
+               set pwd [pwd]
+               cd [file dirname [gitdir]]
+               set env(GIT_DIR) [file tail [gitdir]]
+
                eval exec $cmd $revs &
                eval exec $cmd $revs &
+
+               if {$old_GIT_DIR eq {}} {
+                       unset env(GIT_DIR)
+               } else {
+                       set env(GIT_DIR) $old_GIT_DIR
+               }
+               cd $pwd
+
                ui_status $::starting_gitk_msg
                after 10000 {
                        ui_ready $starting_gitk_msg
                ui_status $::starting_gitk_msg
                after 10000 {
                        ui_ready $starting_gitk_msg
@@ -1413,6 +1730,7 @@ set is_quitting 0
 proc do_quit {} {
        global ui_comm is_quitting repo_config commit_type
        global GITGUI_BCK_exists GITGUI_BCK_i
 proc do_quit {} {
        global ui_comm is_quitting repo_config commit_type
        global GITGUI_BCK_exists GITGUI_BCK_i
+       global ui_comm_spell
 
        if {$is_quitting} return
        set is_quitting 1
 
        if {$is_quitting} return
        set is_quitting 1
@@ -1440,6 +1758,12 @@ proc do_quit {} {
                        }
                }
 
                        }
                }
 
+               # -- Cancel our spellchecker if its running.
+               #
+               if {[info exists ui_comm_spell]} {
+                       $ui_comm_spell stop
+               }
+
                # -- Remove our editor backup, its not needed.
                #
                after cancel $GITGUI_BCK_i
                # -- Remove our editor backup, its not needed.
                #
                after cancel $GITGUI_BCK_i
@@ -1451,8 +1775,8 @@ proc do_quit {} {
                #
                set cfg_geometry [list]
                lappend cfg_geometry [wm geometry .]
                #
                set cfg_geometry [list]
                lappend cfg_geometry [wm geometry .]
-               lappend cfg_geometry [lindex [.vpane sash coord 0] 1]
-               lappend cfg_geometry [lindex [.vpane.files sash coord 0] 0]
+               lappend cfg_geometry [lindex [.vpane sash coord 0] 0]
+               lappend cfg_geometry [lindex [.vpane.files sash coord 0] 1]
                if {[catch {set rc_geometry $repo_config(gui.geometry)}]} {
                        set rc_geometry {}
                }
                if {[catch {set rc_geometry $repo_config(gui.geometry)}]} {
                        set rc_geometry {}
                }
@@ -1472,6 +1796,11 @@ proc do_commit {} {
        commit_tree
 }
 
        commit_tree
 }
 
+proc next_diff {} {
+       global next_diff_p next_diff_w next_diff_i
+       show_diff $next_diff_p $next_diff_w $next_diff_i
+}
+
 proc toggle_or_diff {w x y} {
        global file_states file_lists current_diff_path ui_index ui_workdir
        global last_clicked selected_paths
 proc toggle_or_diff {w x y} {
        global file_states file_lists current_diff_path ui_index ui_workdir
        global last_clicked selected_paths
@@ -1490,12 +1819,34 @@ proc toggle_or_diff {w x y} {
        $ui_index tag remove in_sel 0.0 end
        $ui_workdir tag remove in_sel 0.0 end
 
        $ui_index tag remove in_sel 0.0 end
        $ui_workdir tag remove in_sel 0.0 end
 
-       if {$col == 0} {
-               if {$current_diff_path eq $path} {
+       if {$col == 0 && $y > 1} {
+               set i [expr {$lno-1}]
+               set ll [expr {[llength $file_lists($w)]-1}]
+
+               if {$i == $ll && $i == 0} {
                        set after {reshow_diff;}
                } else {
                        set after {reshow_diff;}
                } else {
-                       set after {}
+                       global next_diff_p next_diff_w next_diff_i
+
+                       set next_diff_w $w
+
+                       if {$i < $ll} {
+                               set i [expr {$i + 1}]
+                               set next_diff_i $i
+                       } else {
+                               set next_diff_i $i
+                               set i [expr {$i - 1}]
+                       }
+
+                       set next_diff_p [lindex $file_lists($w) $i]
+
+                       if {$next_diff_p ne {} && $current_diff_path ne {}} {
+                               set after {next_diff;}
+                       } else {
+                               set after {}
+                       }
                }
                }
+
                if {$w eq $ui_index} {
                        update_indexinfo \
                                "Unstaging [short_path $path] from commit" \
                if {$w eq $ui_index} {
                        update_indexinfo \
                                "Unstaging [short_path $path] from commit" \
@@ -1567,106 +1918,44 @@ proc add_range_to_selection {w x y} {
        $w tag add in_sel $begin.0 [expr {$end + 1}].0
 }
 
        $w tag add in_sel $begin.0 [expr {$end + 1}].0
 }
 
-######################################################################
-##
-## config defaults
-
-set cursor_ptr arrow
-font create font_diff -family Courier -size 10
-font create font_ui
-catch {
-       label .dummy
-       eval font configure font_ui [font actual [.dummy cget -font]]
-       destroy .dummy
-}
-
-font create font_uiitalic
-font create font_uibold
-font create font_diffbold
-font create font_diffitalic
-
-foreach class {Button Checkbutton Entry Label
-               Labelframe Listbox Menu Message
-               Radiobutton Spinbox Text} {
-       option add *$class.font font_ui
-}
-unset class
-
-if {[is_Windows] || [is_MacOSX]} {
-       option add *Menu.tearOff 0
-}
-
-if {[is_MacOSX]} {
-       set M1B M1
-       set M1T Cmd
-} else {
-       set M1B Control
-       set M1T Ctrl
-}
-
-proc apply_config {} {
-       global repo_config font_descs
-
-       foreach option $font_descs {
-               set name [lindex $option 0]
-               set font [lindex $option 1]
-               if {[catch {
-                       foreach {cn cv} $repo_config(gui.$name) {
-                               font configure $font $cn $cv
-                       }
-                       } err]} {
-                       error_popup "Invalid font specified in gui.$name:\n\n$err"
-               }
-               foreach {cn cv} [font configure $font] {
-                       font configure ${font}bold $cn $cv
-                       font configure ${font}italic $cn $cv
-               }
-               font configure ${font}bold -weight bold
-               font configure ${font}italic -slant italic
+proc show_more_context {} {
+       global repo_config
+       if {$repo_config(gui.diffcontext) < 99} {
+               incr repo_config(gui.diffcontext)
+               reshow_diff
        }
 }
 
        }
 }
 
-set default_config(merge.diffstat) true
-set default_config(merge.summary) false
-set default_config(merge.verbosity) 2
-set default_config(user.name) {}
-set default_config(user.email) {}
-
-set default_config(gui.matchtrackingbranch) false
-set default_config(gui.pruneduringfetch) false
-set default_config(gui.trustmtime) false
-set default_config(gui.diffcontext) 5
-set default_config(gui.newbranchtemplate) {}
-set default_config(gui.fontui) [font configure font_ui]
-set default_config(gui.fontdiff) [font configure font_diff]
-set font_descs {
-       {fontui   font_ui   {Main Font}}
-       {fontdiff font_diff {Diff/Console Font}}
+proc show_less_context {} {
+       global repo_config
+       if {$repo_config(gui.diffcontext) >= 1} {
+               incr repo_config(gui.diffcontext) -1
+               reshow_diff
+       }
 }
 }
-load_config 0
-apply_config
 
 ######################################################################
 ##
 ## ui construction
 
 
 ######################################################################
 ##
 ## ui construction
 
+load_config 0
+apply_config
 set ui_comm {}
 
 # -- Menu Bar
 #
 menu .mbar -tearoff 0
 set ui_comm {}
 
 # -- Menu Bar
 #
 menu .mbar -tearoff 0
-.mbar add cascade -label Repository -menu .mbar.repository
-.mbar add cascade -label Edit -menu .mbar.edit
+.mbar add cascade -label [mc Repository] -menu .mbar.repository
+.mbar add cascade -label [mc Edit] -menu .mbar.edit
 if {[is_enabled branch]} {
 if {[is_enabled branch]} {
-       .mbar add cascade -label Branch -menu .mbar.branch
+       .mbar add cascade -label [mc Branch] -menu .mbar.branch
 }
 if {[is_enabled multicommit] || [is_enabled singlecommit]} {
 }
 if {[is_enabled multicommit] || [is_enabled singlecommit]} {
-       .mbar add cascade -label Commit -menu .mbar.commit
+       .mbar add cascade -label [mc Commit@@noun] -menu .mbar.commit
 }
 if {[is_enabled transport]} {
 }
 if {[is_enabled transport]} {
-       .mbar add cascade -label Merge -menu .mbar.merge
-       .mbar add cascade -label Fetch -menu .mbar.fetch
-       .mbar add cascade -label Push -menu .mbar.push
+       .mbar add cascade -label [mc Merge] -menu .mbar.merge
+       .mbar add cascade -label [mc Remote] -menu .mbar.remote
 }
 . configure -menu .mbar
 
 }
 . configure -menu .mbar
 
@@ -1675,87 +1964,91 @@ if {[is_enabled transport]} {
 menu .mbar.repository
 
 .mbar.repository add command \
 menu .mbar.repository
 
 .mbar.repository add command \
-       -label {Browse Current Branch's Files} \
+       -label [mc "Browse Current Branch's Files"] \
        -command {browser::new $current_branch}
 set ui_browse_current [.mbar.repository index last]
 .mbar.repository add command \
        -command {browser::new $current_branch}
 set ui_browse_current [.mbar.repository index last]
 .mbar.repository add command \
-       -label {Browse Branch Files...} \
+       -label [mc "Browse Branch Files..."] \
        -command browser_open::dialog
 .mbar.repository add separator
 
 .mbar.repository add command \
        -command browser_open::dialog
 .mbar.repository add separator
 
 .mbar.repository add command \
-       -label {Visualize Current Branch's History} \
+       -label [mc "Visualize Current Branch's History"] \
        -command {do_gitk $current_branch}
 set ui_visualize_current [.mbar.repository index last]
 .mbar.repository add command \
        -command {do_gitk $current_branch}
 set ui_visualize_current [.mbar.repository index last]
 .mbar.repository add command \
-       -label {Visualize All Branch History} \
+       -label [mc "Visualize All Branch History"] \
        -command {do_gitk --all}
 .mbar.repository add separator
 
 proc current_branch_write {args} {
        global current_branch
        .mbar.repository entryconf $::ui_browse_current \
        -command {do_gitk --all}
 .mbar.repository add separator
 
 proc current_branch_write {args} {
        global current_branch
        .mbar.repository entryconf $::ui_browse_current \
-               -label "Browse $current_branch's Files"
+               -label [mc "Browse %s's Files" $current_branch]
        .mbar.repository entryconf $::ui_visualize_current \
        .mbar.repository entryconf $::ui_visualize_current \
-               -label "Visualize $current_branch's History"
+               -label [mc "Visualize %s's History" $current_branch]
 }
 trace add variable current_branch write current_branch_write
 
 if {[is_enabled multicommit]} {
 }
 trace add variable current_branch write current_branch_write
 
 if {[is_enabled multicommit]} {
-       .mbar.repository add command -label {Database Statistics} \
+       .mbar.repository add command -label [mc "Database Statistics"] \
                -command do_stats
 
                -command do_stats
 
-       .mbar.repository add command -label {Compress Database} \
+       .mbar.repository add command -label [mc "Compress Database"] \
                -command do_gc
 
                -command do_gc
 
-       .mbar.repository add command -label {Verify Database} \
+       .mbar.repository add command -label [mc "Verify Database"] \
                -command do_fsck_objects
 
        .mbar.repository add separator
 
        if {[is_Cygwin]} {
                .mbar.repository add command \
                -command do_fsck_objects
 
        .mbar.repository add separator
 
        if {[is_Cygwin]} {
                .mbar.repository add command \
-                       -label {Create Desktop Icon} \
+                       -label [mc "Create Desktop Icon"] \
                        -command do_cygwin_shortcut
        } elseif {[is_Windows]} {
                .mbar.repository add command \
                        -command do_cygwin_shortcut
        } elseif {[is_Windows]} {
                .mbar.repository add command \
-                       -label {Create Desktop Icon} \
+                       -label [mc "Create Desktop Icon"] \
                        -command do_windows_shortcut
        } elseif {[is_MacOSX]} {
                .mbar.repository add command \
                        -command do_windows_shortcut
        } elseif {[is_MacOSX]} {
                .mbar.repository add command \
-                       -label {Create Desktop Icon} \
+                       -label [mc "Create Desktop Icon"] \
                        -command do_macosx_app
        }
 }
 
                        -command do_macosx_app
        }
 }
 
-.mbar.repository add command -label Quit \
-       -command do_quit \
-       -accelerator $M1T-Q
+if {[is_MacOSX]} {
+       proc ::tk::mac::Quit {args} { do_quit }
+} else {
+       .mbar.repository add command -label [mc Quit] \
+               -command do_quit \
+               -accelerator $M1T-Q
+}
 
 # -- Edit Menu
 #
 menu .mbar.edit
 
 # -- Edit Menu
 #
 menu .mbar.edit
-.mbar.edit add command -label Undo \
+.mbar.edit add command -label [mc Undo] \
        -command {catch {[focus] edit undo}} \
        -accelerator $M1T-Z
        -command {catch {[focus] edit undo}} \
        -accelerator $M1T-Z
-.mbar.edit add command -label Redo \
+.mbar.edit add command -label [mc Redo] \
        -command {catch {[focus] edit redo}} \
        -accelerator $M1T-Y
 .mbar.edit add separator
        -command {catch {[focus] edit redo}} \
        -accelerator $M1T-Y
 .mbar.edit add separator
-.mbar.edit add command -label Cut \
+.mbar.edit add command -label [mc Cut] \
        -command {catch {tk_textCut [focus]}} \
        -accelerator $M1T-X
        -command {catch {tk_textCut [focus]}} \
        -accelerator $M1T-X
-.mbar.edit add command -label Copy \
+.mbar.edit add command -label [mc Copy] \
        -command {catch {tk_textCopy [focus]}} \
        -accelerator $M1T-C
        -command {catch {tk_textCopy [focus]}} \
        -accelerator $M1T-C
-.mbar.edit add command -label Paste \
+.mbar.edit add command -label [mc Paste] \
        -command {catch {tk_textPaste [focus]; [focus] see insert}} \
        -accelerator $M1T-V
        -command {catch {tk_textPaste [focus]; [focus] see insert}} \
        -accelerator $M1T-V
-.mbar.edit add command -label Delete \
+.mbar.edit add command -label [mc Delete] \
        -command {catch {[focus] delete sel.first sel.last}} \
        -accelerator Del
 .mbar.edit add separator
        -command {catch {[focus] delete sel.first sel.last}} \
        -accelerator Del
 .mbar.edit add separator
-.mbar.edit add command -label {Select All} \
+.mbar.edit add command -label [mc "Select All"] \
        -command {catch {[focus] tag add sel 0.0 end}} \
        -accelerator $M1T-A
 
        -command {catch {[focus] tag add sel 0.0 end}} \
        -accelerator $M1T-A
 
@@ -1764,29 +2057,29 @@ menu .mbar.edit
 if {[is_enabled branch]} {
        menu .mbar.branch
 
 if {[is_enabled branch]} {
        menu .mbar.branch
 
-       .mbar.branch add command -label {Create...} \
+       .mbar.branch add command -label [mc "Create..."] \
                -command branch_create::dialog \
                -accelerator $M1T-N
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
 
                -command branch_create::dialog \
                -accelerator $M1T-N
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
 
-       .mbar.branch add command -label {Checkout...} \
+       .mbar.branch add command -label [mc "Checkout..."] \
                -command branch_checkout::dialog \
                -accelerator $M1T-O
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
 
                -command branch_checkout::dialog \
                -accelerator $M1T-O
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
 
-       .mbar.branch add command -label {Rename...} \
+       .mbar.branch add command -label [mc "Rename..."] \
                -command branch_rename::dialog
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
 
                -command branch_rename::dialog
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
 
-       .mbar.branch add command -label {Delete...} \
+       .mbar.branch add command -label [mc "Delete..."] \
                -command branch_delete::dialog
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
 
                -command branch_delete::dialog
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
 
-       .mbar.branch add command -label {Reset...} \
+       .mbar.branch add command -label [mc "Reset..."] \
                -command merge::reset_hard
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
                -command merge::reset_hard
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
@@ -1798,7 +2091,7 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {
        menu .mbar.commit
 
        .mbar.commit add radiobutton \
        menu .mbar.commit
 
        .mbar.commit add radiobutton \
-               -label {New Commit} \
+               -label [mc "New Commit"] \
                -command do_select_commit_type \
                -variable selected_commit_type \
                -value new
                -command do_select_commit_type \
                -variable selected_commit_type \
                -value new
@@ -1806,7 +2099,7 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
 
        .mbar.commit add radiobutton \
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
 
        .mbar.commit add radiobutton \
-               -label {Amend Last Commit} \
+               -label [mc "Amend Last Commit"] \
                -command do_select_commit_type \
                -variable selected_commit_type \
                -value amend
                -command do_select_commit_type \
                -variable selected_commit_type \
                -value amend
@@ -1815,40 +2108,51 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {
 
        .mbar.commit add separator
 
 
        .mbar.commit add separator
 
-       .mbar.commit add command -label Rescan \
+       .mbar.commit add command -label [mc Rescan] \
                -command do_rescan \
                -accelerator F5
        lappend disable_on_lock \
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
 
                -command do_rescan \
                -accelerator F5
        lappend disable_on_lock \
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
 
-       .mbar.commit add command -label {Stage To Commit} \
-               -command do_add_selection
+       .mbar.commit add command -label [mc "Stage To Commit"] \
+               -command do_add_selection \
+               -accelerator $M1T-T
        lappend disable_on_lock \
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
 
        lappend disable_on_lock \
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
 
-       .mbar.commit add command -label {Stage Changed Files To Commit} \
+       .mbar.commit add command -label [mc "Stage Changed Files To Commit"] \
                -command do_add_all \
                -accelerator $M1T-I
        lappend disable_on_lock \
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
 
                -command do_add_all \
                -accelerator $M1T-I
        lappend disable_on_lock \
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
 
-       .mbar.commit add command -label {Unstage From Commit} \
+       .mbar.commit add command -label [mc "Unstage From Commit"] \
                -command do_unstage_selection
        lappend disable_on_lock \
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
 
                -command do_unstage_selection
        lappend disable_on_lock \
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
 
-       .mbar.commit add command -label {Revert Changes} \
+       .mbar.commit add command -label [mc "Revert Changes"] \
                -command do_revert_selection
        lappend disable_on_lock \
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
 
        .mbar.commit add separator
 
                -command do_revert_selection
        lappend disable_on_lock \
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
 
        .mbar.commit add separator
 
-       .mbar.commit add command -label {Sign Off} \
+       .mbar.commit add command -label [mc "Show Less Context"] \
+               -command show_less_context \
+               -accelerator $M1T-\-
+
+       .mbar.commit add command -label [mc "Show More Context"] \
+               -command show_more_context \
+               -accelerator $M1T-=
+
+       .mbar.commit add separator
+
+       .mbar.commit add command -label [mc "Sign Off"] \
                -command do_signoff \
                -accelerator $M1T-S
 
                -command do_signoff \
                -accelerator $M1T-S
 
-       .mbar.commit add command -label Commit \
+       .mbar.commit add command -label [mc Commit@@verb] \
                -command do_commit \
                -accelerator $M1T-Return
        lappend disable_on_lock \
                -command do_commit \
                -accelerator $M1T-Return
        lappend disable_on_lock \
@@ -1859,12 +2163,12 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {
 #
 if {[is_enabled branch]} {
        menu .mbar.merge
 #
 if {[is_enabled branch]} {
        menu .mbar.merge
-       .mbar.merge add command -label {Local Merge...} \
+       .mbar.merge add command -label [mc "Local Merge..."] \
                -command merge::dialog \
                -accelerator $M1T-M
        lappend disable_on_lock \
                [list .mbar.merge entryconf [.mbar.merge index last] -state]
                -command merge::dialog \
                -accelerator $M1T-M
        lappend disable_on_lock \
                [list .mbar.merge entryconf [.mbar.merge index last] -state]
-       .mbar.merge add command -label {Abort Merge...} \
+       .mbar.merge add command -label [mc "Abort Merge..."] \
                -command merge::reset_hard
        lappend disable_on_lock \
                [list .mbar.merge entryconf [.mbar.merge index last] -state]
                -command merge::reset_hard
        lappend disable_on_lock \
                [list .mbar.merge entryconf [.mbar.merge index last] -state]
@@ -1873,13 +2177,14 @@ if {[is_enabled branch]} {
 # -- Transport Menu
 #
 if {[is_enabled transport]} {
 # -- Transport Menu
 #
 if {[is_enabled transport]} {
-       menu .mbar.fetch
+       menu .mbar.remote
 
 
-       menu .mbar.push
-       .mbar.push add command -label {Push...} \
+       .mbar.remote add command \
+               -label [mc "Push..."] \
                -command do_push_anywhere \
                -accelerator $M1T-P
                -command do_push_anywhere \
                -accelerator $M1T-P
-       .mbar.push add command -label {Delete...} \
+       .mbar.remote add command \
+               -label [mc "Delete..."] \
                -command remote_branch_delete::dialog
 }
 
                -command remote_branch_delete::dialog
 }
 
@@ -1889,25 +2194,29 @@ if {[is_MacOSX]} {
        .mbar add cascade -label Apple -menu .mbar.apple
        menu .mbar.apple
 
        .mbar add cascade -label Apple -menu .mbar.apple
        menu .mbar.apple
 
-       .mbar.apple add command -label "About [appname]" \
+       .mbar.apple add command -label [mc "About %s" [appname]] \
                -command do_about
                -command do_about
-       .mbar.apple add command -label "Options..." \
-               -command do_options
+       .mbar.apple add separator
+       .mbar.apple add command \
+               -label [mc "Preferences..."] \
+               -command do_options \
+               -accelerator $M1T-,
+       bind . <$M1B-,> do_options
 } else {
        # -- Edit Menu
        #
        .mbar.edit add separator
 } else {
        # -- Edit Menu
        #
        .mbar.edit add separator
-       .mbar.edit add command -label {Options...} \
+       .mbar.edit add command -label [mc "Options..."] \
                -command do_options
 }
 
 # -- Help Menu
 #
                -command do_options
 }
 
 # -- Help Menu
 #
-.mbar add cascade -label Help -menu .mbar.help
+.mbar add cascade -label [mc Help] -menu .mbar.help
 menu .mbar.help
 
 if {![is_MacOSX]} {
 menu .mbar.help
 
 if {![is_MacOSX]} {
-       .mbar.help add command -label "About [appname]" \
+       .mbar.help add command -label [mc "About %s" [appname]] \
                -command do_about
 }
 
                -command do_about
 }
 
@@ -1944,17 +2253,11 @@ if {[file isfile $doc_path]} {
 }
 
 if {$browser ne {}} {
 }
 
 if {$browser ne {}} {
-       .mbar.help add command -label {Online Documentation} \
+       .mbar.help add command -label [mc "Online Documentation"] \
                -command [list exec $browser $doc_url &]
 }
 unset browser doc_path doc_url
 
                -command [list exec $browser $doc_url &]
 }
 unset browser doc_path doc_url
 
-set root_exists 0
-bind . <Visibility> {
-       bind . <Visibility> {}
-       set root_exists 1
-}
-
 # -- Standard bindings
 #
 wm protocol . WM_DELETE_WINDOW do_quit
 # -- Standard bindings
 #
 wm protocol . WM_DELETE_WINDOW do_quit
@@ -2034,7 +2337,7 @@ blame {
        }
        blame   {
                if {$head eq {} && ![file exists $path]} {
        }
        blame   {
                if {$head eq {} && ![file exists $path]} {
-                       puts stderr "fatal: cannot stat path $path: No such file or directory"
+                       puts stderr [mc "fatal: cannot stat path %s: No such file or directory" $path]
                        exit 1
                }
                blame::new $head $path
                        exit 1
                }
                blame::new $head $path
@@ -2046,7 +2349,8 @@ citool -
 gui {
        if {[llength $argv] != 0} {
                puts -nonewline stderr "usage: $argv0"
 gui {
        if {[llength $argv] != 0} {
                puts -nonewline stderr "usage: $argv0"
-               if {$subcommand ne {gui} && [appname] ne "git-$subcommand"} {
+               if {$subcommand ne {gui}
+                       && [file tail $argv0] ne "git-$subcommand"} {
                        puts -nonewline stderr " $subcommand"
                }
                puts stderr {}
                        puts -nonewline stderr " $subcommand"
                }
                puts stderr {}
@@ -2066,7 +2370,7 @@ frame .branch \
        -borderwidth 1 \
        -relief sunken
 label .branch.l1 \
        -borderwidth 1 \
        -relief sunken
 label .branch.l1 \
-       -text {Current Branch:} \
+       -text [mc "Current Branch:"] \
        -anchor w \
        -justify left
 label .branch.cb \
        -anchor w \
        -justify left
 label .branch.cb \
@@ -2079,17 +2383,18 @@ pack .branch -side top -fill x
 
 # -- Main Window Layout
 #
 
 # -- Main Window Layout
 #
-panedwindow .vpane -orient vertical
-panedwindow .vpane.files -orient horizontal
+panedwindow .vpane -orient horizontal
+panedwindow .vpane.files -orient vertical
 .vpane add .vpane.files -sticky nsew -height 100 -width 200
 pack .vpane -anchor n -side top -fill both -expand 1
 
 # -- Index File List
 #
 frame .vpane.files.index -height 100 -width 200
 .vpane add .vpane.files -sticky nsew -height 100 -width 200
 pack .vpane -anchor n -side top -fill both -expand 1
 
 # -- Index File List
 #
 frame .vpane.files.index -height 100 -width 200
-label .vpane.files.index.title -text {Staged Changes (Will Be Committed)} \
-       -background lightgreen
-text $ui_index -background white -borderwidth 0 \
+label .vpane.files.index.title -text [mc "Staged Changes (Will Commit)"] \
+       -background lightgreen -foreground black
+text $ui_index -background white -foreground black \
+       -borderwidth 0 \
        -width 20 -height 10 \
        -wrap none \
        -cursor $cursor_ptr \
        -width 20 -height 10 \
        -wrap none \
        -cursor $cursor_ptr \
@@ -2102,14 +2407,14 @@ pack .vpane.files.index.title -side top -fill x
 pack .vpane.files.index.sx -side bottom -fill x
 pack .vpane.files.index.sy -side right -fill y
 pack $ui_index -side left -fill both -expand 1
 pack .vpane.files.index.sx -side bottom -fill x
 pack .vpane.files.index.sy -side right -fill y
 pack $ui_index -side left -fill both -expand 1
-.vpane.files add .vpane.files.index -sticky nsew
 
 # -- Working Directory File List
 #
 frame .vpane.files.workdir -height 100 -width 200
 
 # -- Working Directory File List
 #
 frame .vpane.files.workdir -height 100 -width 200
-label .vpane.files.workdir.title -text {Unstaged Changes (Will Not Be Committed)} \
-       -background lightsalmon
-text $ui_workdir -background white -borderwidth 0 \
+label .vpane.files.workdir.title -text [mc "Unstaged Changes"] \
+       -background lightsalmon -foreground black
+text $ui_workdir -background white -foreground black \
+       -borderwidth 0 \
        -width 20 -height 10 \
        -wrap none \
        -cursor $cursor_ptr \
        -width 20 -height 10 \
        -wrap none \
        -cursor $cursor_ptr \
@@ -2122,11 +2427,13 @@ pack .vpane.files.workdir.title -side top -fill x
 pack .vpane.files.workdir.sx -side bottom -fill x
 pack .vpane.files.workdir.sy -side right -fill y
 pack $ui_workdir -side left -fill both -expand 1
 pack .vpane.files.workdir.sx -side bottom -fill x
 pack .vpane.files.workdir.sy -side right -fill y
 pack $ui_workdir -side left -fill both -expand 1
+
 .vpane.files add .vpane.files.workdir -sticky nsew
 .vpane.files add .vpane.files.workdir -sticky nsew
+.vpane.files add .vpane.files.index -sticky nsew
 
 foreach i [list $ui_index $ui_workdir] {
 
 foreach i [list $ui_index $ui_workdir] {
-       $i tag conf in_diff -background lightgray
-       $i tag conf in_sel  -background lightgray
+       rmsel_tag $i
+       $i tag conf in_diff -background [$i tag cget in_sel -background]
 }
 unset i
 
 }
 unset i
 
@@ -2135,8 +2442,8 @@ unset i
 frame .vpane.lower -height 300 -width 400
 frame .vpane.lower.commarea
 frame .vpane.lower.diff -relief sunken -borderwidth 1
 frame .vpane.lower -height 300 -width 400
 frame .vpane.lower.commarea
 frame .vpane.lower.diff -relief sunken -borderwidth 1
-pack .vpane.lower.commarea -side top -fill x
-pack .vpane.lower.diff -side bottom -fill both -expand 1
+pack .vpane.lower.diff -fill both -expand 1
+pack .vpane.lower.commarea -side bottom -fill x
 .vpane add .vpane.lower -sticky nsew
 
 # -- Commit Area Buttons
 .vpane add .vpane.lower -sticky nsew
 
 # -- Commit Area Buttons
@@ -2148,29 +2455,29 @@ label .vpane.lower.commarea.buttons.l -text {} \
 pack .vpane.lower.commarea.buttons.l -side top -fill x
 pack .vpane.lower.commarea.buttons -side left -fill y
 
 pack .vpane.lower.commarea.buttons.l -side top -fill x
 pack .vpane.lower.commarea.buttons -side left -fill y
 
-button .vpane.lower.commarea.buttons.rescan -text {Rescan} \
+button .vpane.lower.commarea.buttons.rescan -text [mc Rescan] \
        -command do_rescan
 pack .vpane.lower.commarea.buttons.rescan -side top -fill x
 lappend disable_on_lock \
        {.vpane.lower.commarea.buttons.rescan conf -state}
 
        -command do_rescan
 pack .vpane.lower.commarea.buttons.rescan -side top -fill x
 lappend disable_on_lock \
        {.vpane.lower.commarea.buttons.rescan conf -state}
 
-button .vpane.lower.commarea.buttons.incall -text {Stage Changed} \
+button .vpane.lower.commarea.buttons.incall -text [mc "Stage Changed"] \
        -command do_add_all
 pack .vpane.lower.commarea.buttons.incall -side top -fill x
 lappend disable_on_lock \
        {.vpane.lower.commarea.buttons.incall conf -state}
 
        -command do_add_all
 pack .vpane.lower.commarea.buttons.incall -side top -fill x
 lappend disable_on_lock \
        {.vpane.lower.commarea.buttons.incall conf -state}
 
-button .vpane.lower.commarea.buttons.signoff -text {Sign Off} \
+button .vpane.lower.commarea.buttons.signoff -text [mc "Sign Off"] \
        -command do_signoff
 pack .vpane.lower.commarea.buttons.signoff -side top -fill x
 
        -command do_signoff
 pack .vpane.lower.commarea.buttons.signoff -side top -fill x
 
-button .vpane.lower.commarea.buttons.commit -text {Commit} \
+button .vpane.lower.commarea.buttons.commit -text [mc Commit@@verb] \
        -command do_commit
 pack .vpane.lower.commarea.buttons.commit -side top -fill x
 lappend disable_on_lock \
        {.vpane.lower.commarea.buttons.commit conf -state}
 
        -command do_commit
 pack .vpane.lower.commarea.buttons.commit -side top -fill x
 lappend disable_on_lock \
        {.vpane.lower.commarea.buttons.commit conf -state}
 
-button .vpane.lower.commarea.buttons.push -text {Push} \
+button .vpane.lower.commarea.buttons.push -text [mc Push] \
        -command do_push_anywhere
 pack .vpane.lower.commarea.buttons.push -side top -fill x
 
        -command do_push_anywhere
 pack .vpane.lower.commarea.buttons.push -side top -fill x
 
@@ -2181,14 +2488,14 @@ frame .vpane.lower.commarea.buffer.header
 set ui_comm .vpane.lower.commarea.buffer.t
 set ui_coml .vpane.lower.commarea.buffer.header.l
 radiobutton .vpane.lower.commarea.buffer.header.new \
 set ui_comm .vpane.lower.commarea.buffer.t
 set ui_coml .vpane.lower.commarea.buffer.header.l
 radiobutton .vpane.lower.commarea.buffer.header.new \
-       -text {New Commit} \
+       -text [mc "New Commit"] \
        -command do_select_commit_type \
        -variable selected_commit_type \
        -value new
 lappend disable_on_lock \
        [list .vpane.lower.commarea.buffer.header.new conf -state]
 radiobutton .vpane.lower.commarea.buffer.header.amend \
        -command do_select_commit_type \
        -variable selected_commit_type \
        -value new
 lappend disable_on_lock \
        [list .vpane.lower.commarea.buffer.header.new conf -state]
 radiobutton .vpane.lower.commarea.buffer.header.amend \
-       -text {Amend Last Commit} \
+       -text [mc "Amend Last Commit"] \
        -command do_select_commit_type \
        -variable selected_commit_type \
        -value amend
        -command do_select_commit_type \
        -variable selected_commit_type \
        -value amend
@@ -2200,12 +2507,12 @@ label $ui_coml \
 proc trace_commit_type {varname args} {
        global ui_coml commit_type
        switch -glob -- $commit_type {
 proc trace_commit_type {varname args} {
        global ui_coml commit_type
        switch -glob -- $commit_type {
-       initial       {set txt {Initial Commit Message:}}
-       amend         {set txt {Amended Commit Message:}}
-       amend-initial {set txt {Amended Initial Commit Message:}}
-       amend-merge   {set txt {Amended Merge Commit Message:}}
-       merge         {set txt {Merge Commit Message:}}
-       *             {set txt {Commit Message:}}
+       initial       {set txt [mc "Initial Commit Message:"]}
+       amend         {set txt [mc "Amended Commit Message:"]}
+       amend-initial {set txt [mc "Amended Initial Commit Message:"]}
+       amend-merge   {set txt [mc "Amended Merge Commit Message:"]}
+       merge         {set txt [mc "Merge Commit Message:"]}
+       *             {set txt [mc "Commit Message:"]}
        }
        $ui_coml conf -text $txt
 }
        }
        $ui_coml conf -text $txt
 }
@@ -2214,12 +2521,13 @@ pack $ui_coml -side left -fill x
 pack .vpane.lower.commarea.buffer.header.amend -side right
 pack .vpane.lower.commarea.buffer.header.new -side right
 
 pack .vpane.lower.commarea.buffer.header.amend -side right
 pack .vpane.lower.commarea.buffer.header.new -side right
 
-text $ui_comm -background white -borderwidth 1 \
+text $ui_comm -background white -foreground black \
+       -borderwidth 1 \
        -undo true \
        -maxundo 20 \
        -autoseparators true \
        -relief sunken \
        -undo true \
        -maxundo 20 \
        -autoseparators true \
        -relief sunken \
-       -width 75 -height 9 -wrap none \
+       -width $repo_config(gui.commitmsgwidth) -height 9 -wrap none \
        -font font_diff \
        -yscrollcommand {.vpane.lower.commarea.buffer.sby set}
 scrollbar .vpane.lower.commarea.buffer.sby \
        -font font_diff \
        -yscrollcommand {.vpane.lower.commarea.buffer.sby set}
 scrollbar .vpane.lower.commarea.buffer.sby \
@@ -2234,23 +2542,23 @@ pack .vpane.lower.commarea.buffer -side left -fill y
 set ctxm .vpane.lower.commarea.buffer.ctxm
 menu $ctxm -tearoff 0
 $ctxm add command \
 set ctxm .vpane.lower.commarea.buffer.ctxm
 menu $ctxm -tearoff 0
 $ctxm add command \
-       -label {Cut} \
+       -label [mc Cut] \
        -command {tk_textCut $ui_comm}
 $ctxm add command \
        -command {tk_textCut $ui_comm}
 $ctxm add command \
-       -label {Copy} \
+       -label [mc Copy] \
        -command {tk_textCopy $ui_comm}
 $ctxm add command \
        -command {tk_textCopy $ui_comm}
 $ctxm add command \
-       -label {Paste} \
+       -label [mc Paste] \
        -command {tk_textPaste $ui_comm}
 $ctxm add command \
        -command {tk_textPaste $ui_comm}
 $ctxm add command \
-       -label {Delete} \
+       -label [mc Delete] \
        -command {$ui_comm delete sel.first sel.last}
 $ctxm add separator
 $ctxm add command \
        -command {$ui_comm delete sel.first sel.last}
 $ctxm add separator
 $ctxm add command \
-       -label {Select All} \
+       -label [mc "Select All"] \
        -command {focus $ui_comm;$ui_comm tag add sel 0.0 end}
 $ctxm add command \
        -command {focus $ui_comm;$ui_comm tag add sel 0.0 end}
 $ctxm add command \
-       -label {Copy All} \
+       -label [mc "Copy All"] \
        -command {
                $ui_comm tag add sel 0.0 end
                tk_textCopy $ui_comm
        -command {
                $ui_comm tag add sel 0.0 end
                tk_textCopy $ui_comm
@@ -2258,9 +2566,9 @@ $ctxm add command \
        }
 $ctxm add separator
 $ctxm add command \
        }
 $ctxm add separator
 $ctxm add command \
-       -label {Sign Off} \
+       -label [mc "Sign Off"] \
        -command do_signoff
        -command do_signoff
-bind_button3 $ui_comm "tk_popup $ctxm %X %Y"
+set ui_comm_ctxm $ctxm
 
 # -- Diff Header
 #
 
 # -- Diff Header
 #
@@ -2274,7 +2582,7 @@ proc trace_current_diff_path {varname args} {
        } else {
                set p $current_diff_path
                set s [mapdesc [lindex $file_states($p) 0] $p]
        } else {
                set p $current_diff_path
                set s [mapdesc [lindex $file_states($p) 0] $p]
-               set f {File:}
+               set f [mc "File:"]
                set p [escape_path $p]
                set o normal
        }
                set p [escape_path $p]
                set o normal
        }
@@ -2291,15 +2599,18 @@ trace add variable current_diff_path write trace_current_diff_path
 frame .vpane.lower.diff.header -background gold
 label .vpane.lower.diff.header.status \
        -background gold \
 frame .vpane.lower.diff.header -background gold
 label .vpane.lower.diff.header.status \
        -background gold \
+       -foreground black \
        -width $max_status_desc \
        -anchor w \
        -justify left
 label .vpane.lower.diff.header.file \
        -background gold \
        -width $max_status_desc \
        -anchor w \
        -justify left
 label .vpane.lower.diff.header.file \
        -background gold \
+       -foreground black \
        -anchor w \
        -justify left
 label .vpane.lower.diff.header.path \
        -background gold \
        -anchor w \
        -justify left
 label .vpane.lower.diff.header.path \
        -background gold \
+       -foreground black \
        -anchor w \
        -justify left
 pack .vpane.lower.diff.header.status -side left
        -anchor w \
        -justify left
 pack .vpane.lower.diff.header.status -side left
@@ -2308,7 +2619,7 @@ pack .vpane.lower.diff.header.path -fill x
 set ctxm .vpane.lower.diff.header.ctxm
 menu $ctxm -tearoff 0
 $ctxm add command \
 set ctxm .vpane.lower.diff.header.ctxm
 menu $ctxm -tearoff 0
 $ctxm add command \
-       -label {Copy} \
+       -label [mc Copy] \
        -command {
                clipboard clear
                clipboard append \
        -command {
                clipboard clear
                clipboard append \
@@ -2323,7 +2634,8 @@ bind_button3 .vpane.lower.diff.header.path "tk_popup $ctxm %X %Y"
 #
 frame .vpane.lower.diff.body
 set ui_diff .vpane.lower.diff.body.t
 #
 frame .vpane.lower.diff.body
 set ui_diff .vpane.lower.diff.body.t
-text $ui_diff -background white -borderwidth 0 \
+text $ui_diff -background white -foreground black \
+       -borderwidth 0 \
        -width 80 -height 15 -wrap none \
        -font font_diff \
        -xscrollcommand {.vpane.lower.diff.body.sbx set} \
        -width 80 -height 15 -wrap none \
        -font font_diff \
        -xscrollcommand {.vpane.lower.diff.body.sbx set} \
@@ -2376,19 +2688,39 @@ $ui_diff tag raise sel
 set ctxm .vpane.lower.diff.body.ctxm
 menu $ctxm -tearoff 0
 $ctxm add command \
 set ctxm .vpane.lower.diff.body.ctxm
 menu $ctxm -tearoff 0
 $ctxm add command \
-       -label {Refresh} \
+       -label [mc "Apply/Reverse Hunk"] \
+       -command {apply_hunk $cursorX $cursorY}
+set ui_diff_applyhunk [$ctxm index last]
+lappend diff_actions [list $ctxm entryconf $ui_diff_applyhunk -state]
+$ctxm add command \
+       -label [mc "Apply/Reverse Line"] \
+       -command {apply_line $cursorX $cursorY; do_rescan}
+set ui_diff_applyline [$ctxm index last]
+lappend diff_actions [list $ctxm entryconf $ui_diff_applyline -state]
+$ctxm add separator
+$ctxm add command \
+       -label [mc "Show Less Context"] \
+       -command show_less_context
+lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
+$ctxm add command \
+       -label [mc "Show More Context"] \
+       -command show_more_context
+lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
+$ctxm add separator
+$ctxm add command \
+       -label [mc Refresh] \
        -command reshow_diff
 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
 $ctxm add command \
        -command reshow_diff
 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
 $ctxm add command \
-       -label {Copy} \
+       -label [mc Copy] \
        -command {tk_textCopy $ui_diff}
 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
 $ctxm add command \
        -command {tk_textCopy $ui_diff}
 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
 $ctxm add command \
-       -label {Select All} \
+       -label [mc "Select All"] \
        -command {focus $ui_diff;$ui_diff tag add sel 0.0 end}
 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
 $ctxm add command \
        -command {focus $ui_diff;$ui_diff tag add sel 0.0 end}
 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
 $ctxm add command \
-       -label {Copy All} \
+       -label [mc "Copy All"] \
        -command {
                $ui_diff tag add sel 0.0 end
                tk_textCopy $ui_diff
        -command {
                $ui_diff tag add sel 0.0 end
                tk_textCopy $ui_diff
@@ -2397,58 +2729,37 @@ $ctxm add command \
 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
 $ctxm add separator
 $ctxm add command \
 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
 $ctxm add separator
 $ctxm add command \
-       -label {Apply/Reverse Hunk} \
-       -command {apply_hunk $cursorX $cursorY}
-set ui_diff_applyhunk [$ctxm index last]
-lappend diff_actions [list $ctxm entryconf $ui_diff_applyhunk -state]
-$ctxm add separator
-$ctxm add command \
-       -label {Decrease Font Size} \
+       -label [mc "Decrease Font Size"] \
        -command {incr_font_size font_diff -1}
 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
 $ctxm add command \
        -command {incr_font_size font_diff -1}
 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
 $ctxm add command \
-       -label {Increase Font Size} \
+       -label [mc "Increase Font Size"] \
        -command {incr_font_size font_diff 1}
 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
 $ctxm add separator
        -command {incr_font_size font_diff 1}
 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
 $ctxm add separator
-$ctxm add command \
-       -label {Show Less Context} \
-       -command {if {$repo_config(gui.diffcontext) >= 1} {
-               incr repo_config(gui.diffcontext) -1
-               reshow_diff
-       }}
-lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
-$ctxm add command \
-       -label {Show More Context} \
-       -command {if {$repo_config(gui.diffcontext) < 99} {
-               incr repo_config(gui.diffcontext)
-               reshow_diff
-       }}
-lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
-$ctxm add separator
-$ctxm add command -label {Options...} \
+$ctxm add command -label [mc "Options..."] \
        -command do_options
 proc popup_diff_menu {ctxm x y X Y} {
        global current_diff_path file_states
        set ::cursorX $x
        set ::cursorY $y
        if {$::ui_index eq $::current_diff_side} {
        -command do_options
 proc popup_diff_menu {ctxm x y X Y} {
        global current_diff_path file_states
        set ::cursorX $x
        set ::cursorY $y
        if {$::ui_index eq $::current_diff_side} {
-               set s normal
-               set l "Unstage Hunk From Commit"
+               set l [mc "Unstage Hunk From Commit"]
+               set t [mc "Unstage Line From Commit"]
        } else {
        } else {
-               if {$current_diff_path eq {}
-                       || ![info exists file_states($current_diff_path)]
-                       || {_O} eq [lindex $file_states($current_diff_path) 0]} {
-                       set s disabled
-               } else {
-                       set s normal
-               }
-               set l "Stage Hunk For Commit"
+               set l [mc "Stage Hunk For Commit"]
+               set t [mc "Stage Line For Commit"]
        }
        }
-       if {$::is_3way_diff} {
+       if {$::is_3way_diff
+               || $current_diff_path eq {}
+               || ![info exists file_states($current_diff_path)]
+               || {_O} eq [lindex $file_states($current_diff_path) 0]} {
                set s disabled
                set s disabled
+       } else {
+               set s normal
        }
        $ctxm entryconf $::ui_diff_applyhunk -state $s -label $l
        }
        $ctxm entryconf $::ui_diff_applyhunk -state $s -label $l
+       $ctxm entryconf $::ui_diff_applyline -state $s -label $t
        tk_popup $ctxm $X $Y
 }
 bind_button3 $ui_diff [list popup_diff_menu $ctxm %x %y %X %Y]
        tk_popup $ctxm $X $Y
 }
 bind_button3 $ui_diff [list popup_diff_menu $ctxm %x %y %X %Y]
@@ -2457,7 +2768,7 @@ bind_button3 $ui_diff [list popup_diff_menu $ctxm %x %y %X %Y]
 #
 set main_status [::status_bar::new .status]
 pack .status -anchor w -side bottom -fill x
 #
 set main_status [::status_bar::new .status]
 pack .status -anchor w -side bottom -fill x
-$main_status show {Initializing...}
+$main_status show [mc "Initializing..."]
 
 # -- Load geometry
 #
 
 # -- Load geometry
 #
@@ -2465,17 +2776,19 @@ catch {
 set gm $repo_config(gui.geometry)
 wm geometry . [lindex $gm 0]
 .vpane sash place 0 \
 set gm $repo_config(gui.geometry)
 wm geometry . [lindex $gm 0]
 .vpane sash place 0 \
-       [lindex [.vpane sash coord 0] 0] \
-       [lindex $gm 1]
+       [lindex $gm 1] \
+       [lindex [.vpane sash coord 0] 1]
 .vpane.files sash place 0 \
 .vpane.files sash place 0 \
-       [lindex $gm 2] \
-       [lindex [.vpane.files sash coord 0] 1]
+       [lindex [.vpane.files sash coord 0] 0] \
+       [lindex $gm 2]
 unset gm
 }
 
 # -- Key Bindings
 #
 bind $ui_comm <$M1B-Key-Return> {do_commit;break}
 unset gm
 }
 
 # -- Key Bindings
 #
 bind $ui_comm <$M1B-Key-Return> {do_commit;break}
+bind $ui_comm <$M1B-Key-t> {do_add_selection;break}
+bind $ui_comm <$M1B-Key-T> {do_add_selection;break}
 bind $ui_comm <$M1B-Key-i> {do_add_all;break}
 bind $ui_comm <$M1B-Key-I> {do_add_all;break}
 bind $ui_comm <$M1B-Key-x> {tk_textCut %W;break}
 bind $ui_comm <$M1B-Key-i> {do_add_all;break}
 bind $ui_comm <$M1B-Key-I> {do_add_all;break}
 bind $ui_comm <$M1B-Key-x> {tk_textCut %W;break}
@@ -2486,6 +2799,11 @@ bind $ui_comm <$M1B-Key-v> {tk_textPaste %W; %W see insert; break}
 bind $ui_comm <$M1B-Key-V> {tk_textPaste %W; %W see insert; break}
 bind $ui_comm <$M1B-Key-a> {%W tag add sel 0.0 end;break}
 bind $ui_comm <$M1B-Key-A> {%W tag add sel 0.0 end;break}
 bind $ui_comm <$M1B-Key-V> {tk_textPaste %W; %W see insert; break}
 bind $ui_comm <$M1B-Key-a> {%W tag add sel 0.0 end;break}
 bind $ui_comm <$M1B-Key-A> {%W tag add sel 0.0 end;break}
+bind $ui_comm <$M1B-Key-minus> {show_less_context;break}
+bind $ui_comm <$M1B-Key-KP_Subtract> {show_less_context;break}
+bind $ui_comm <$M1B-Key-equal> {show_more_context;break}
+bind $ui_comm <$M1B-Key-plus> {show_more_context;break}
+bind $ui_comm <$M1B-Key-KP_Add> {show_more_context;break}
 
 bind $ui_diff <$M1B-Key-x> {tk_textCopy %W;break}
 bind $ui_diff <$M1B-Key-X> {tk_textCopy %W;break}
 
 bind $ui_diff <$M1B-Key-x> {tk_textCopy %W;break}
 bind $ui_diff <$M1B-Key-X> {tk_textCopy %W;break}
@@ -2525,8 +2843,15 @@ bind .   <$M1B-Key-r> do_rescan
 bind .   <$M1B-Key-R> do_rescan
 bind .   <$M1B-Key-s> do_signoff
 bind .   <$M1B-Key-S> do_signoff
 bind .   <$M1B-Key-R> do_rescan
 bind .   <$M1B-Key-s> do_signoff
 bind .   <$M1B-Key-S> do_signoff
+bind .   <$M1B-Key-t> do_add_selection
+bind .   <$M1B-Key-T> do_add_selection
 bind .   <$M1B-Key-i> do_add_all
 bind .   <$M1B-Key-I> do_add_all
 bind .   <$M1B-Key-i> do_add_all
 bind .   <$M1B-Key-I> do_add_all
+bind .   <$M1B-Key-minus> {show_less_context;break}
+bind .   <$M1B-Key-KP_Subtract> {show_less_context;break}
+bind .   <$M1B-Key-equal> {show_more_context;break}
+bind .   <$M1B-Key-plus> {show_more_context;break}
+bind .   <$M1B-Key-KP_Add> {show_more_context;break}
 bind .   <$M1B-Key-Return> do_commit
 foreach i [list $ui_index $ui_workdir] {
        bind $i <Button-1>       "toggle_or_diff         $i %x %y; break"
 bind .   <$M1B-Key-Return> do_commit
 foreach i [list $ui_index $ui_workdir] {
        bind $i <Button-1>       "toggle_or_diff         $i %x %y; break"
@@ -2548,13 +2873,13 @@ focus -force $ui_comm
 if {[is_Cygwin]} {
        set ignored_env 0
        set suggest_user {}
 if {[is_Cygwin]} {
        set ignored_env 0
        set suggest_user {}
-       set msg "Possible environment issues exist.
+       set msg [mc "Possible environment issues exist.
 
 The following environment variables are probably
 going to be ignored by any Git subprocess run
 
 The following environment variables are probably
 going to be ignored by any Git subprocess run
-by [appname]:
+by %s:
 
 
-"
+" [appname]]
        foreach name [array names env] {
                switch -regexp -- $name {
                {^GIT_INDEX_FILE$} -
        foreach name [array names env] {
                switch -regexp -- $name {
                {^GIT_INDEX_FILE$} -
@@ -2578,18 +2903,18 @@ by [appname]:
                }
        }
        if {$ignored_env > 0} {
                }
        }
        if {$ignored_env > 0} {
-               append msg "
+               append msg [mc "
 This is due to a known issue with the
 This is due to a known issue with the
-Tcl binary distributed by Cygwin."
+Tcl binary distributed by Cygwin."]
 
                if {$suggest_user ne {}} {
 
                if {$suggest_user ne {}} {
-                       append msg "
+                       append msg [mc "
 
 
-A good replacement for $suggest_user
+A good replacement for %s
 is placing values for the user.name and
 user.email settings into your personal
 ~/.gitconfig file.
 is placing values for the user.name and
 user.email settings into your personal
 ~/.gitconfig file.
-"
+" $suggest_user]
                }
                warn_popup $msg
        }
                }
                warn_popup $msg
        }
@@ -2601,8 +2926,15 @@ user.email settings into your personal
 if {[is_enabled transport]} {
        load_all_remotes
 
 if {[is_enabled transport]} {
        load_all_remotes
 
-       populate_fetch_menu
+       set n [.mbar.remote index end]
        populate_push_menu
        populate_push_menu
+       populate_fetch_menu
+       set n [expr {[.mbar.remote index end] - $n}]
+       if {$n > 0} {
+               if {[.mbar.remote type 0] eq "tearoff"} { incr n }
+               .mbar.remote insert $n separator
+       }
+       unset n
 }
 
 if {[winfo exists $ui_comm]} {
 }
 
 if {[winfo exists $ui_comm]} {
@@ -2656,6 +2988,30 @@ if {[winfo exists $ui_comm]} {
        }
 
        backup_commit_buffer
        }
 
        backup_commit_buffer
+
+       # -- If the user has aspell available we can drive it
+       #    in pipe mode to spellcheck the commit message.
+       #
+       set spell_cmd [list |]
+       set spell_dict [get_config gui.spellingdictionary]
+       lappend spell_cmd aspell
+       if {$spell_dict ne {}} {
+               lappend spell_cmd --master=$spell_dict
+       }
+       lappend spell_cmd --mode=none
+       lappend spell_cmd --encoding=utf-8
+       lappend spell_cmd pipe
+       if {$spell_dict eq {none}
+        || [catch {set spell_fd [open $spell_cmd r+]} spell_err]} {
+               bind_button3 $ui_comm [list tk_popup $ui_comm_ctxm %X %Y]
+       } else {
+               set ui_comm_spell [spellcheck::init \
+                       $spell_fd \
+                       $ui_comm \
+                       $ui_comm_ctxm \
+               ]
+       }
+       unset -nocomplain spell_cmd spell_fd spell_err spell_dict
 }
 
 lock_index begin-read
 }
 
 lock_index begin-read