]> asedeno.scripts.mit.edu Git - git.git/blobdiff - git-gui.sh
git-gui: update Italian translation
[git.git] / git-gui.sh
index f12be315b1531754cd499756458ef3a42f23fa8f..3a58cd2c6b49b8734234c6fb5957c035df9787d4 100755 (executable)
@@ -1,10 +1,17 @@
 #!/bin/sh
 # Tcl ignores the next line -*- tcl -*- \
 #!/bin/sh
 # Tcl ignores the next line -*- tcl -*- \
-exec wish "$0" -- "$@"
-
-set appvers {@@GIT_VERSION@@}
-set copyright {
-Copyright © 2006, 2007 Shawn Pearce, Paul Mackerras.
+ if test "z$*" = zversion \
+ || test "z$*" = z--version; \
+ then \
+       echo 'git-gui version @@GITGUI_VERSION@@'; \
+       exit; \
+ fi; \
+ argv0=$0; \
+ exec wish "$argv0" -- "$@"
+
+set appvers {@@GITGUI_VERSION@@}
+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
@@ -18,15 +25,102 @@ 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}]
+
+######################################################################
+##
+## Tcl/Tk sanity check
+
+if {[catch {package require Tcl 8.4} err]
+ || [catch {package require Tk  8.4} err]
+} {
+       catch {wm withdraw .}
+       tk_messageBox \
+               -icon error \
+               -type ok \
+               -title [mc "git-gui: fatal error"] \
+               -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?
+
+if {![catch {set _verbose $env(GITGUI_VERBOSE)}]} {
+       unset _verbose
+       rename auto_load real__auto_load
+       proc auto_load {name args} {
+               puts stderr "auto_load $name"
+               return [uplevel 1 real__auto_load $name $args]
+       }
+       rename source real__source
+       proc source {name} {
+               puts stderr "source    $name"
+               uplevel 1 real__source $name
+       }
+}
+
+######################################################################
+##
+## 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 _gitdir {}
+set _gitexec {}
 set _reponame {}
 set _reponame {}
+set _iscygwin {}
+set _search_path {}
 
 proc appname {} {
        global _appname
 
 proc appname {} {
        global _appname
@@ -38,12 +132,78 @@ proc gitdir {args} {
        if {$args eq {}} {
                return $_gitdir
        }
        if {$args eq {}} {
                return $_gitdir
        }
-       return [eval [concat [list file join $_gitdir] $args]]
+       return [eval [list file join $_gitdir] $args]
+}
+
+proc gitexec {args} {
+       global _gitexec
+       if {$_gitexec eq {}} {
+               if {[catch {set _gitexec [git --exec-path]} err]} {
+                       error "Git not installed?\n\n$err"
+               }
+               if {[is_Cygwin]} {
+                       set _gitexec [exec cygpath \
+                               --windows \
+                               --absolute \
+                               $_gitexec]
+               } else {
+                       set _gitexec [file normalize $_gitexec]
+               }
+       }
+       if {$args eq {}} {
+               return $_gitexec
+       }
+       return [eval [list file join $_gitexec] $args]
 }
 
 proc reponame {} {
 }
 
 proc reponame {} {
-       global _reponame
-       return $_reponame
+       return $::_reponame
+}
+
+proc is_MacOSX {} {
+       if {[tk windowingsystem] eq {aqua}} {
+               return 1
+       }
+       return 0
+}
+
+proc is_Windows {} {
+       if {$::tcl_platform(platform) eq {windows}} {
+               return 1
+       }
+       return 0
+}
+
+proc is_Cygwin {} {
+       global _iscygwin
+       if {$_iscygwin eq {}} {
+               if {$::tcl_platform(platform) eq {windows}} {
+                       if {[catch {set p [exec cygpath --windir]} err]} {
+                               set _iscygwin 0
+                       } else {
+                               set _iscygwin 1
+                       }
+               } else {
+                       set _iscygwin 0
+               }
+       }
+       return $_iscygwin
+}
+
+proc is_enabled {option} {
+       global enabled_options
+       if {[catch {set on $enabled_options($option)}]} {return 0}
+       return $on
+}
+
+proc enable_option {option} {
+       global enabled_options
+       set enabled_options($option) 1
+}
+
+proc disable_option {option} {
+       global enabled_options
+       set enabled_options($option) 0
 }
 
 ######################################################################
 }
 
 ######################################################################
@@ -52,6 +212,7 @@ proc reponame {} {
 
 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}
@@ -60,192 +221,748 @@ proc is_many_config {name} {
        }
 }
 
        }
 }
 
-proc load_config {include_global} {
-       global repo_config global_config default_config
+proc is_config_true {name} {
+       global repo_config
+       if {[catch {set v $repo_config($name)}]} {
+               return 0
+       } elseif {$v eq {true} || $v eq {1} || $v eq {yes}} {
+               return 1
+       } else {
+               return 0
+       }
+}
 
 
-       array unset global_config
-       if {$include_global} {
-               catch {
-                       set fd_rc [open "| git repo-config --global --list" r]
-                       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
-                                       }
-                               }
+proc get_config {name} {
+       global repo_config
+       if {[catch {set v $repo_config($name)}]} {
+               return {}
+       } else {
+               return $v
+       }
+}
+
+######################################################################
+##
+## handy utils
+
+proc _git_cmd {name} {
+       global _git_cmd_path
+
+       if {[catch {set v $_git_cmd_path($name)}]} {
+               switch -- $name {
+                 version   -
+               --version   -
+               --exec-path { return [list $::_git $name] }
+               }
+
+               set p [gitexec git-$name$::_search_exe]
+               if {[file exists $p]} {
+                       set v [list $p]
+               } elseif {[is_Windows] && [file exists [gitexec git-$name]]} {
+                       # Try to determine what sort of magic will make
+                       # git-$name go and do its thing, because native
+                       # Tcl on Windows doesn't know it.
+                       #
+                       set p [gitexec git-$name]
+                       set f [open $p r]
+                       set s [gets $f]
+                       close $f
+
+                       switch -glob -- [lindex $s 0] {
+                       #!*sh     { set i sh     }
+                       #!*perl   { set i perl   }
+                       #!*python { set i python }
+                       default   { error "git-$name is not supported: $s" }
                        }
                        }
-                       close $fd_rc
+
+                       upvar #0 _$i interp
+                       if {![info exists interp]} {
+                               set interp [_which $i]
+                       }
+                       if {$interp eq {}} {
+                               error "git-$name requires $i (not in PATH)"
+                       }
+                       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.
+                       #
+                       set v [list $::_git $name]
+               }
+               set _git_cmd_path($name) $v
+       }
+       return $v
+}
+
+proc _which {what} {
+       global env _search_exe _search_path
+
+       if {$_search_path eq {}} {
+               if {[is_Cygwin] && [regexp {^(/|\.:)} $env(PATH)]} {
+                       set _search_path [split [exec cygpath \
+                               --windows \
+                               --path \
+                               --absolute \
+                               $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 {}
                }
        }
 
                }
        }
 
-       array unset repo_config
-       catch {
-               set fd_rc [open "| git repo-config --list" r]
-               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
-                               }
-                       }
+       foreach p $_search_path {
+               set p [file join $p $what$_search_exe]
+               if {[file exists $p]} {
+                       return [file normalize $p]
                }
                }
-               close $fd_rc
        }
        }
+       return {}
+}
 
 
-       foreach name [array names default_config] {
-               if {[catch {set v $global_config($name)}]} {
-                       set global_config($name) $default_config($name)
+proc _lappend_nice {cmd_var} {
+       global _nice
+       upvar $cmd_var cmd
+
+       if {![info exists _nice]} {
+               set _nice [_which nice]
+       }
+       if {$_nice ne {}} {
+               lappend cmd $_nice
+       }
+}
+
+proc git {args} {
+       set opt [list exec]
+
+       while {1} {
+               switch -- [lindex $args 0] {
+               --nice {
+                       _lappend_nice opt
                }
                }
-               if {[catch {set v $repo_config($name)}]} {
-                       set repo_config($name) $default_config($name)
+
+               default {
+                       break
                }
                }
+
+               }
+
+               set args [lrange $args 1 end]
        }
        }
-}
 
 
-proc save_config {} {
-       global default_config font_descs
-       global repo_config global_config
-       global repo_config_new global_config_new
+       set cmdp [_git_cmd [lindex $args 0]]
+       set args [lrange $args 1 end]
 
 
-       foreach option $font_descs {
-               set name [lindex $option 0]
-               set font [lindex $option 1]
-               font configure $font \
-                       -family $global_config_new(gui.$font^^family) \
-                       -size $global_config_new(gui.$font^^size)
-               font configure ${font}bold \
-                       -family $global_config_new(gui.$font^^family) \
-                       -size $global_config_new(gui.$font^^size)
-               set global_config_new(gui.$name) [font configure $font]
-               unset global_config_new(gui.$font^^family)
-               unset global_config_new(gui.$font^^size)
+       return [eval $opt $cmdp $args]
+}
+
+proc _open_stdout_stderr {cmd} {
+       if {[catch {
+                       set fd [open $cmd r]
+               } err]} {
+               if {   [lindex $cmd end] eq {2>@1}
+                   && $err eq {can not find channel named "1"}
+                       } {
+                       # Older versions of Tcl 8.4 don't have this 2>@1 IO
+                       # redirect operator.  Fallback to |& cat for those.
+                       # The command was not actually started, so its safe
+                       # to try to start it a second time.
+                       #
+                       set fd [open [concat \
+                               [lrange $cmd 0 end-1] \
+                               [list |& cat] \
+                               ] r]
+               } else {
+                       error $err
+               }
        }
        }
+       fconfigure $fd -eofchar {}
+       return $fd
+}
 
 
-       foreach name [array names default_config] {
-               set value $global_config_new($name)
-               if {$value ne $global_config($name)} {
-                       if {$value eq $default_config($name)} {
-                               catch {exec git repo-config --global --unset $name}
-                       } else {
-                               regsub -all "\[{}\]" $value {"} value
-                               exec git repo-config --global $name $value
-                       }
-                       set global_config($name) $value
-                       if {$value eq $repo_config($name)} {
-                               catch {exec git repo-config --unset $name}
-                               set repo_config($name) $value
-                       }
+proc git_read {args} {
+       set opt [list |]
+
+       while {1} {
+               switch -- [lindex $args 0] {
+               --nice {
+                       _lappend_nice opt
                }
                }
+
+               --stderr {
+                       lappend args 2>@1
+               }
+
+               default {
+                       break
+               }
+
+               }
+
+               set args [lrange $args 1 end]
        }
 
        }
 
-       foreach name [array names default_config] {
-               set value $repo_config_new($name)
-               if {$value ne $repo_config($name)} {
-                       if {$value eq $global_config($name)} {
-                               catch {exec git repo-config --unset $name}
-                       } else {
-                               regsub -all "\[{}\]" $value {"} value
-                               exec git repo-config $name $value
-                       }
-                       set repo_config($name) $value
+       set cmdp [_git_cmd [lindex $args 0]]
+       set args [lrange $args 1 end]
+
+       return [_open_stdout_stderr [concat $opt $cmdp $args]]
+}
+
+proc git_write {args} {
+       set opt [list |]
+
+       while {1} {
+               switch -- [lindex $args 0] {
+               --nice {
+                       _lappend_nice opt
                }
                }
+
+               default {
+                       break
+               }
+
+               }
+
+               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]
 }
 
 }
 
-proc error_popup {msg} {
-       set title [appname]
-       if {[reponame] ne {}} {
-               append title " ([reponame])"
+proc githook_read {hook_name args} {
+       set pchook [gitdir hooks $hook_name]
+       lappend args 2>@1
+
+       # On Cygwin [file executable] might lie so we need to ask
+       # the shell if the hook is executable.  Yes that's annoying.
+       #
+       if {[is_Cygwin]} {
+               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]]
        }
        }
-       set cmd [list tk_messageBox \
-               -icon error \
-               -type ok \
-               -title "$title: error" \
-               -message $msg]
-       if {[winfo ismapped .]} {
-               lappend cmd -parent .
+
+       if {[file executable $pchook]} {
+               return [_open_stdout_stderr [concat [list | $pchook] $args]]
        }
        }
-       eval $cmd
+
+       return {}
+}
+
+proc sq {value} {
+       regsub -all ' $value "'\\''" value
+       return "'$value'"
 }
 
 }
 
-proc warn_popup {msg} {
-       set title [appname]
-       if {[reponame] ne {}} {
-               append title " ([reponame])"
+proc load_current_branch {} {
+       global current_branch is_detached
+
+       set fd [open [gitdir HEAD] r]
+       if {[gets $fd ref] < 1} {
+               set ref {}
        }
        }
-       set cmd [list tk_messageBox \
-               -icon warning \
-               -type ok \
-               -title "$title: warning" \
-               -message $msg]
-       if {[winfo ismapped .]} {
-               lappend cmd -parent .
+       close $fd
+
+       set pfx {ref: refs/heads/}
+       set len [string length $pfx]
+       if {[string equal -length $len $pfx $ref]} {
+               # We're on a branch.  It might not exist.  But
+               # HEAD looks good enough to be a branch.
+               #
+               set current_branch [string range $ref $len end]
+               set is_detached 0
+       } else {
+               # Assume this is a detached head.
+               #
+               set current_branch HEAD
+               set is_detached 1
        }
        }
-       eval $cmd
 }
 
 }
 
-proc info_popup {msg} {
-       set title [appname]
-       if {[reponame] ne {}} {
-               append title " ([reponame])"
+auto_load tk_optionMenu
+rename tk_optionMenu real__tkOptionMenu
+proc tk_optionMenu {w varName args} {
+       set m [eval real__tkOptionMenu $w $varName $args]
+       $m configure -font font_ui
+       $w configure -font font_ui
+       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
        }
        }
-       tk_messageBox \
-               -parent . \
-               -icon info \
-               -type ok \
-               -title $title \
-               -message $msg
 }
 
 }
 
-proc ask_popup {msg} {
-       set title [appname]
-       if {[reponame] ne {}} {
-               append title " ([reponame])"
+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
        }
        }
-       return [tk_messageBox \
-               -parent . \
-               -icon question \
-               -type yesno \
-               -title $title \
-               -message $msg]
+}
+
+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.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"}}
 }
 
 ######################################################################
 ##
 }
 
 ######################################################################
 ##
-## repository setup
+## find git
 
 
-if {   [catch {set _gitdir $env(GIT_DIR)}]
-       && [catch {set _gitdir [exec git rev-parse --git-dir]} err]} {
+set _git  [_which git]
+if {$_git eq {}} {
        catch {wm withdraw .}
        catch {wm withdraw .}
-       error_popup "Cannot find the git directory:\n\n$err"
+       tk_messageBox \
+               -icon error \
+               -type ok \
+               -title [mc "git-gui: fatal error"] \
+               -message [mc "Cannot find git in PATH."]
        exit 1
 }
        exit 1
 }
-if {![file isdirectory $_gitdir]} {
+
+######################################################################
+##
+## version check
+
+if {[catch {set _git_version [git --version]} err]} {
        catch {wm withdraw .}
        catch {wm withdraw .}
-       error_popup "Git directory not found:\n\n$_gitdir"
+       tk_messageBox \
+               -icon error \
+               -type ok \
+               -title [mc "git-gui: fatal error"] \
+               -message "Cannot determine Git version:
+
+$err
+
+[appname] requires Git 1.5.0 or later."
        exit 1
 }
        exit 1
 }
-if {[lindex [file split $_gitdir] end] ne {.git}} {
+if {![regsub {^git version } $_git_version {} _git_version]} {
        catch {wm withdraw .}
        catch {wm withdraw .}
-       error_popup "Cannot use funny .git directory:\n\n$gitdir"
+       tk_messageBox \
+               -icon error \
+               -type ok \
+               -title [mc "git-gui: fatal error"] \
+               -message [strcat [mc "Cannot parse Git version string:"] "\n\n$_git_version"]
        exit 1
 }
        exit 1
 }
-if {[catch {cd [file dirname $_gitdir]} err]} {
+
+set _real_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 {\.[a-zA-Z]+\.[0-9]+$} $_git_version {} _git_version
+
+if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} {
        catch {wm withdraw .}
        catch {wm withdraw .}
-       error_popup "No working directory [file dirname $_gitdir]:\n\n$err"
+       if {[tk_messageBox \
+               -icon warning \
+               -type yesno \
+               -default no \
+               -title "[appname]: warning" \
+                -message [mc "Git version cannot be determined.
+
+%s claims it is version '%s'.
+
+%s requires at least Git 1.5.0 or later.
+
+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
+       }
+}
+unset _real_git_version
+
+proc git-version {args} {
+       global _git_version
+
+       switch [llength $args] {
+       0 {
+               return $_git_version
+       }
+
+       2 {
+               set op [lindex $args 0]
+               set vr [lindex $args 1]
+               set cm [package vcompare $_git_version $vr]
+               return [expr $cm $op 0]
+       }
+
+       4 {
+               set type [lindex $args 0]
+               set name [lindex $args 1]
+               set parm [lindex $args 2]
+               set body [lindex $args 3]
+
+               if {($type ne {proc} && $type ne {method})} {
+                       error "Invalid arguments to git-version"
+               }
+               if {[llength $body] < 2 || [lindex $body end-1] ne {default}} {
+                       error "Last arm of $type $name must be default"
+               }
+
+               foreach {op vr cb} [lrange $body 0 end-2] {
+                       if {[git-version $op $vr]} {
+                               return [uplevel [list $type $name $parm $cb]]
+                       }
+               }
+
+               return [uplevel [list $type $name $parm [lindex $body end]]]
+       }
+
+       default {
+               error "git-version >= x"
+       }
+
+       }
+}
+
+if {[git-version < 1.5]} {
+       catch {wm withdraw .}
+       tk_messageBox \
+               -icon error \
+               -type ok \
+               -title [mc "git-gui: fatal error"] \
+               -message "[appname] requires Git 1.5.0 or later.
+
+You are using [git-version]:
+
+[git --version]"
+       exit 1
+}
+
+######################################################################
+##
+## configure our library
+
+set idx [file join $oguilib tclIndex]
+if {[catch {set fd [open $idx r]} err]} {
+       catch {wm withdraw .}
+       tk_messageBox \
+               -icon error \
+               -type ok \
+               -title [mc "git-gui: fatal error"] \
+               -message $err
+       exit 1
+}
+if {[gets $fd] eq {# Autogenerated by git-gui Makefile}} {
+       set idx [list]
+       while {[gets $fd n] >= 0} {
+               if {$n ne {} && ![string match #* $n]} {
+                       lappend idx $n
+               }
+       }
+} else {
+       set idx {}
+}
+close $fd
+
+if {$idx ne {}} {
+       set loaded [list]
+       foreach p $idx {
+               if {[lsearch -exact $loaded $p] >= 0} continue
+               source [file join $oguilib $p]
+               lappend loaded $p
+       }
+       unset loaded p
+} else {
+       set auto_path [concat [list $oguilib] $auto_path]
+}
+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
+
+if {[regexp {^git-(.+)$} [file tail $argv0] _junk subcommand]} {
+       unset _junk
+} else {
+       set subcommand gui
+}
+if {$subcommand eq {gui.sh}} {
+       set subcommand gui
+}
+if {$subcommand eq {gui} && [llength $argv] > 0} {
+       set subcommand [lindex $argv 0]
+       set argv [lrange $argv 1 end]
+}
+
+enable_option multicommit
+enable_option branch
+enable_option transport
+disable_option bare
+
+switch -- $subcommand {
+browser -
+blame {
+       enable_option bare
+
+       disable_option multicommit
+       disable_option branch
+       disable_option transport
+}
+citool {
+       enable_option singlecommit
+
+       disable_option multicommit
+       disable_option branch
+       disable_option transport
+}
+}
+
+######################################################################
+##
+## repository setup
+
+if {[catch {
+               set _gitdir $env(GIT_DIR)
+               set _prefix {}
+               }]
+       && [catch {
+               set _gitdir [git rev-parse --git-dir]
+               set _prefix [git rev-parse --show-prefix]
+       } err]} {
+       load_config 1
+       apply_config
+       choose_repository::pick
+}
+if {![file isdirectory $_gitdir] && [is_Cygwin]} {
+       catch {set _gitdir [exec cygpath --windows $_gitdir]}
+}
+if {![file isdirectory $_gitdir]} {
+       catch {wm withdraw .}
+       error_popup [strcat [mc "Git directory not found:"] "\n\n$_gitdir"]
        exit 1
 }
        exit 1
 }
-set _reponame [lindex [file split \
-       [file normalize [file dirname $_gitdir]]] \
-       end]
+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 .}
+               error_popup [strcat [mc "Cannot use funny .git directory:"] "\n\n$_gitdir"]
+               exit 1
+       }
+       if {[catch {cd [file dirname $_gitdir]} err]} {
+               catch {wm withdraw .}
+               error_popup [strcat [mc "No working directory"] " [file dirname $_gitdir]:\n\n$err"]
+               exit 1
+       }
+}
+set _reponame [file split [file normalize $_gitdir]]
+if {[lindex $_reponame end] eq {.git}} {
+       set _reponame [lindex $_reponame end-1]
+} else {
+       set _reponame [lindex $_reponame end]
+}
+
+######################################################################
+##
+## global init
+
+set current_diff_path {}
+set current_diff_side {}
+set diff_actions [list]
 
 
-set single_commit 0
-if {[appname] eq {git-citool}} {
-       set single_commit 1
-}
+set HEAD {}
+set PARENT {}
+set MERGE_HEAD [list]
+set commit_type {}
+set empty_tree {}
+set current_branch {}
+set is_detached 0
+set current_diff_path {}
+set is_3way_diff 0
+set selected_commit_type new
 
 ######################################################################
 ##
 
 ######################################################################
 ##
@@ -293,16 +1010,8 @@ proc repository_state {ctvar hdvar mhvar} {
 
        set mh [list]
 
 
        set mh [list]
 
-       if {[catch {set current_branch [exec git symbolic-ref HEAD]}]} {
-               set current_branch {}
-       } else {
-               regsub ^refs/((heads|tags|remotes)/)? \
-                       $current_branch \
-                       {} \
-                       current_branch
-       }
-
-       if {[catch {set hd [exec git rev-parse --verify HEAD]}]} {
+       load_current_branch
+       if {[catch {set hd [git rev-parse --verify HEAD]}]} {
                set hd {}
                set ct initial
                return
                set hd {}
                set ct initial
                return
@@ -330,14 +1039,14 @@ proc PARENT {} {
                return $p
        }
        if {$empty_tree eq {}} {
                return $p
        }
        if {$empty_tree eq {}} {
-               set empty_tree [exec git mktree << {}]
+               set empty_tree [git mktree << {}]
        }
        return $empty_tree
 }
 
        }
        return $empty_tree
 }
 
-proc rescan {after} {
+proc rescan {after {honor_trustmtime 1}} {
        global HEAD PARENT MERGE_HEAD commit_type
        global HEAD PARENT MERGE_HEAD commit_type
-       global ui_index ui_workdir ui_status_value ui_comm
+       global ui_index ui_workdir ui_comm
        global rescan_active file_states
        global repo_config
 
        global rescan_active file_states
        global repo_config
 
@@ -356,9 +1065,11 @@ proc rescan {after} {
 
        array unset file_states
 
 
        array unset file_states
 
-       if {![$ui_comm edit modified]
-               || [string trim [$ui_comm get 0.0 end]] eq {}} {
-               if {[load_message GITGUI_MSG]} {
+       if {!$::GITGUI_BCK_exists &&
+               (![$ui_comm edit modified]
+               || [string trim [$ui_comm get 0.0 end]] eq {})} {
+               if {[string match amend* $commit_type]} {
+               } elseif {[load_message GITGUI_MSG]} {
                } elseif {[load_message MERGE_MSG]} {
                } elseif {[load_message SQUASH_MSG]} {
                }
                } elseif {[load_message MERGE_MSG]} {
                } elseif {[load_message SQUASH_MSG]} {
                }
@@ -366,25 +1077,53 @@ proc rescan {after} {
                $ui_comm edit modified false
        }
 
                $ui_comm edit modified false
        }
 
-       if {$repo_config(gui.trustmtime) eq {true}} {
+       if {$honor_trustmtime && $repo_config(gui.trustmtime) eq {true}} {
                rescan_stage2 {} $after
        } else {
                set rescan_active 1
                rescan_stage2 {} $after
        } else {
                set rescan_active 1
-               set ui_status_value {Refreshing file status...}
-               set cmd [list git update-index]
-               lappend cmd -q
-               lappend cmd --unmerged
-               lappend cmd --ignore-missing
-               lappend cmd --refresh
-               set fd_rf [open "| $cmd" r]
+               ui_status [mc "Refreshing file status..."]
+               set fd_rf [git_read update-index \
+                       -q \
+                       --unmerged \
+                       --ignore-missing \
+                       --refresh \
+                       ]
                fconfigure $fd_rf -blocking 0 -translation binary
                fileevent $fd_rf readable \
                        [list rescan_stage2 $fd_rf $after]
        }
 }
 
                fconfigure $fd_rf -blocking 0 -translation binary
                fileevent $fd_rf readable \
                        [list rescan_stage2 $fd_rf $after]
        }
 }
 
+if {[is_Cygwin]} {
+       set is_git_info_link {}
+       set is_git_info_exclude {}
+       proc have_info_exclude {} {
+               global is_git_info_link is_git_info_exclude
+
+               if {$is_git_info_link eq {}} {
+                       set is_git_info_link [file isfile [gitdir info.lnk]]
+               }
+
+               if {$is_git_info_link} {
+                       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 {
+                       return [file readable [gitdir info exclude]]
+               }
+       }
+} else {
+       proc have_info_exclude {} {
+               return [file readable [gitdir info exclude]]
+       }
+}
+
 proc rescan_stage2 {fd after} {
 proc rescan_stage2 {fd after} {
-       global ui_status_value
        global rescan_active buf_rdi buf_rdf buf_rlo
 
        if {$fd ne {}} {
        global rescan_active buf_rdi buf_rdf buf_rlo
 
        if {$fd ne {}} {
@@ -393,11 +1132,13 @@ proc rescan_stage2 {fd after} {
                close $fd
        }
 
                close $fd
        }
 
-       set ls_others [list | git ls-files --others -z \
-               --exclude-per-directory=.gitignore]
-       set info_exclude [gitdir info exclude]
-       if {[file readable $info_exclude]} {
-               lappend ls_others "--exclude-from=$info_exclude"
+       set ls_others [list --exclude-per-directory=.gitignore]
+       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]} {
+               lappend ls_others "--exclude-from=$user_exclude"
        }
 
        set buf_rdi {}
        }
 
        set buf_rdi {}
@@ -405,14 +1146,14 @@ proc rescan_stage2 {fd after} {
        set buf_rlo {}
 
        set rescan_active 3
        set buf_rlo {}
 
        set rescan_active 3
-       set ui_status_value {Scanning for modified files ...}
-       set fd_di [open "| git diff-index --cached -z [PARENT]" r]
-       set fd_df [open "| git diff-files -z" r]
-       set fd_lo [open $ls_others r]
-
-       fconfigure $fd_di -blocking 0 -translation binary
-       fconfigure $fd_df -blocking 0 -translation binary
-       fconfigure $fd_lo -blocking 0 -translation binary
+       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]
+
+       fconfigure $fd_di -blocking 0 -translation binary -encoding binary
+       fconfigure $fd_df -blocking 0 -translation binary -encoding binary
+       fconfigure $fd_lo -blocking 0 -translation binary -encoding binary
        fileevent $fd_di readable [list read_diff_index $fd_di $after]
        fileevent $fd_df readable [list read_diff_files $fd_df $after]
        fileevent $fd_lo readable [list read_ls_others $fd_lo $after]
        fileevent $fd_di readable [list read_diff_index $fd_di $after]
        fileevent $fd_df readable [list read_diff_files $fd_df $after]
        fileevent $fd_lo readable [list read_ls_others $fd_lo $after]
@@ -426,8 +1167,10 @@ proc load_message {file} {
                if {[catch {set fd [open $f r]}]} {
                        return 0
                }
                if {[catch {set fd [open $f r]}]} {
                        return 0
                }
+               fconfigure $fd -eofchar {}
                set content [string trim [read $fd]]
                close $fd
                set content [string trim [read $fd]]
                close $fd
+               regsub -all -line {[ \r\t]+$} $content {} content
                $ui_comm delete 0.0 end
                $ui_comm insert end $content
                return 1
                $ui_comm delete 0.0 end
                $ui_comm insert end $content
                return 1
@@ -450,8 +1193,9 @@ proc read_diff_index {fd after} {
 
                incr c
                set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }]
 
                incr c
                set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }]
+               set p [string range $buf_rdi $z1 [expr {$z2 - 1}]]
                merge_state \
                merge_state \
-                       [string range $buf_rdi $z1 [expr {$z2 - 1}]] \
+                       [encoding convertfrom $p] \
                        [lindex $i 4]? \
                        [list [lindex $i 0] [lindex $i 2]] \
                        [list]
                        [lindex $i 4]? \
                        [list [lindex $i 0] [lindex $i 2]] \
                        [list]
@@ -482,8 +1226,9 @@ proc read_diff_files {fd after} {
 
                incr c
                set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }]
 
                incr c
                set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }]
+               set p [string range $buf_rdf $z1 [expr {$z2 - 1}]]
                merge_state \
                merge_state \
-                       [string range $buf_rdf $z1 [expr {$z2 - 1}]] \
+                       [encoding convertfrom $p] \
                        ?[lindex $i 4] \
                        [list] \
                        [list [lindex $i 0] [lindex $i 2]]
                        ?[lindex $i 4] \
                        [list] \
                        [list [lindex $i 0] [lindex $i 2]]
@@ -492,726 +1237,56 @@ proc read_diff_files {fd after} {
        }
        if {$c < $n} {
                set buf_rdf [string range $buf_rdf $c end]
        }
        if {$c < $n} {
                set buf_rdf [string range $buf_rdf $c end]
-       } else {
-               set buf_rdf {}
-       }
-
-       rescan_done $fd buf_rdf $after
-}
-
-proc read_ls_others {fd after} {
-       global buf_rlo
-
-       append buf_rlo [read $fd]
-       set pck [split $buf_rlo "\0"]
-       set buf_rlo [lindex $pck end]
-       foreach p [lrange $pck 0 end-1] {
-               merge_state $p ?O
-       }
-       rescan_done $fd buf_rlo $after
-}
-
-proc rescan_done {fd buf after} {
-       global rescan_active
-       global file_states repo_config
-       upvar $buf to_clear
-
-       if {![eof $fd]} return
-       set to_clear {}
-       close $fd
-       if {[incr rescan_active -1] > 0} return
-
-       prune_selection
-       unlock_index
-       display_all_files
-       reshow_diff
-       uplevel #0 $after
-}
-
-proc prune_selection {} {
-       global file_states selected_paths
-
-       foreach path [array names selected_paths] {
-               if {[catch {set still_here $file_states($path)}]} {
-                       unset selected_paths($path)
-               }
-       }
-}
-
-######################################################################
-##
-## diff
-
-proc clear_diff {} {
-       global ui_diff current_diff_path ui_index ui_workdir
-
-       $ui_diff conf -state normal
-       $ui_diff delete 0.0 end
-       $ui_diff conf -state disabled
-
-       set current_diff_path {}
-
-       $ui_index tag remove in_diff 0.0 end
-       $ui_workdir tag remove in_diff 0.0 end
-}
-
-proc reshow_diff {} {
-       global ui_status_value file_states file_lists
-       global current_diff_path current_diff_side
-
-       set p $current_diff_path
-       if {$p eq {}
-               || $current_diff_side eq {}
-               || [catch {set s $file_states($p)}]
-               || [lsearch -sorted $file_lists($current_diff_side) $p] == -1} {
-               clear_diff
-       } else {
-               show_diff $p $current_diff_side
-       }
-}
-
-proc handle_empty_diff {} {
-       global current_diff_path file_states file_lists
-
-       set path $current_diff_path
-       set s $file_states($path)
-       if {[lindex $s 0] ne {_M}} return
-
-       info_popup "No differences detected.
-
-[short_path $path] has no changes.
-
-The modification date of this file was updated
-by another application and you currently have
-the Trust File Modification Timestamps option
-enabled, so Git did not automatically detect
-that there are no content differences in this
-file.
-
-This file will now be removed from the modified
-files list, to prevent possible confusion.
-"
-       if {[catch {exec git update-index -- $path} err]} {
-               error_popup "Failed to refresh index:\n\n$err"
-       }
-
-       clear_diff
-       display_file $path __
-}
-
-proc show_diff {path w {lno {}}} {
-       global file_states file_lists
-       global is_3way_diff diff_active repo_config
-       global ui_diff ui_status_value ui_index ui_workdir
-       global current_diff_path current_diff_side
-
-       if {$diff_active || ![lock_index read]} return
-
-       clear_diff
-       if {$w eq {} || $lno == {}} {
-               foreach w [array names file_lists] {
-                       set lno [lsearch -sorted $file_lists($w) $path]
-                       if {$lno >= 0} {
-                               incr lno
-                               break
-                       }
-               }
-       }
-       if {$w ne {} && $lno >= 1} {
-               $w tag add in_diff $lno.0 [expr {$lno + 1}].0
-       }
-
-       set s $file_states($path)
-       set m [lindex $s 0]
-       set is_3way_diff 0
-       set diff_active 1
-       set current_diff_path $path
-       set current_diff_side $w
-       set ui_status_value "Loading diff of [escape_path $path]..."
-
-       # - Git won't give us the diff, there's nothing to compare to!
-       #
-       if {$m eq {_O}} {
-               if {[catch {
-                               set fd [open $path r]
-                               set content [read $fd]
-                               close $fd
-                       } err ]} {
-                       set diff_active 0
-                       unlock_index
-                       set ui_status_value "Unable to display [escape_path $path]"
-                       error_popup "Error loading file:\n\n$err"
-                       return
-               }
-               $ui_diff conf -state normal
-               $ui_diff insert end $content
-               $ui_diff conf -state disabled
-               set diff_active 0
-               unlock_index
-               set ui_status_value {Ready.}
-               return
-       }
-
-       set cmd [list | git]
-       if {$w eq $ui_index} {
-               lappend cmd diff-index
-               lappend cmd --cached
-       } elseif {$w eq $ui_workdir} {
-               if {[string index $m 0] eq {U}} {
-                       lappend cmd diff
-               } else {
-                       lappend cmd diff-files
-               }
-       }
-
-       lappend cmd -p
-       lappend cmd --no-color
-       if {$repo_config(gui.diffcontext) > 0} {
-               lappend cmd "-U$repo_config(gui.diffcontext)"
-       }
-       if {$w eq $ui_index} {
-               lappend cmd [PARENT]
-       }
-       lappend cmd --
-       lappend cmd $path
-
-       if {[catch {set fd [open $cmd r]} err]} {
-               set diff_active 0
-               unlock_index
-               set ui_status_value "Unable to display [escape_path $path]"
-               error_popup "Error loading diff:\n\n$err"
-               return
-       }
-
-       fconfigure $fd -blocking 0 -translation auto
-       fileevent $fd readable [list read_diff $fd]
-}
-
-proc read_diff {fd} {
-       global ui_diff ui_status_value is_3way_diff diff_active
-       global repo_config
-
-       $ui_diff conf -state normal
-       while {[gets $fd line] >= 0} {
-               # -- Cleanup uninteresting diff header lines.
-               #
-               if {[string match {diff --git *}      $line]} continue
-               if {[string match {diff --cc *}       $line]} continue
-               if {[string match {diff --combined *} $line]} continue
-               if {[string match {--- *}             $line]} continue
-               if {[string match {+++ *}             $line]} continue
-               if {$line eq {deleted file mode 120000}} {
-                       set line "deleted symlink"
-               }
-
-               # -- Automatically detect if this is a 3 way diff.
-               #
-               if {[string match {@@@ *} $line]} {set is_3way_diff 1}
-
-               if {[string match {index *} $line]} {
-                       set tags {}
-               } elseif {$is_3way_diff} {
-                       set op [string range $line 0 1]
-                       switch -- $op {
-                       {  } {set tags {}}
-                       {@@} {set tags d_@}
-                       { +} {set tags d_s+}
-                       { -} {set tags d_s-}
-                       {+ } {set tags d_+s}
-                       {- } {set tags d_-s}
-                       {--} {set tags d_--}
-                       {++} {
-                               if {[regexp {^\+\+([<>]{7} |={7})} $line _g op]} {
-                                       set line [string replace $line 0 1 {  }]
-                                       set tags d$op
-                               } else {
-                                       set tags d_++
-                               }
-                       }
-                       default {
-                               puts "error: Unhandled 3 way diff marker: {$op}"
-                               set tags {}
-                       }
-                       }
-               } else {
-                       set op [string index $line 0]
-                       switch -- $op {
-                       { } {set tags {}}
-                       {@} {set tags d_@}
-                       {-} {set tags d_-}
-                       {+} {
-                               if {[regexp {^\+([<>]{7} |={7})} $line _g op]} {
-                                       set line [string replace $line 0 0 { }]
-                                       set tags d$op
-                               } else {
-                                       set tags d_+
-                               }
-                       }
-                       default {
-                               puts "error: Unhandled 2 way diff marker: {$op}"
-                               set tags {}
-                       }
-                       }
-               }
-               $ui_diff insert end $line $tags
-               $ui_diff insert end "\n" $tags
-       }
-       $ui_diff conf -state disabled
-
-       if {[eof $fd]} {
-               close $fd
-               set diff_active 0
-               unlock_index
-               set ui_status_value {Ready.}
-
-               if {$repo_config(gui.trustmtime) eq {true}
-                       && [$ui_diff index end] eq {2.0}} {
-                       handle_empty_diff
-               }
-       }
-}
-
-######################################################################
-##
-## commit
-
-proc load_last_commit {} {
-       global HEAD PARENT MERGE_HEAD commit_type ui_comm
-
-       if {[llength $PARENT] == 0} {
-               error_popup {There is nothing to amend.
-
-You are about to create the initial commit.
-There is no commit before this to amend.
-}
-               return
-       }
-
-       repository_state curType curHEAD curMERGE_HEAD
-       if {$curType eq {merge}} {
-               error_popup {Cannot amend while merging.
-
-You are currently in the middle of a merge that
-has not been fully completed.  You cannot amend
-the prior commit unless you first abort the
-current merge activity.
-}
-               return
-       }
-
-       set msg {}
-       set parents [list]
-       if {[catch {
-                       set fd [open "| git cat-file commit $curHEAD" r]
-                       while {[gets $fd line] > 0} {
-                               if {[string match {parent *} $line]} {
-                                       lappend parents [string range $line 7 end]
-                               }
-                       }
-                       set msg [string trim [read $fd]]
-                       close $fd
-               } err]} {
-               error_popup "Error loading commit data for amend:\n\n$err"
-               return
-       }
-
-       set HEAD $curHEAD
-       set PARENT $parents
-       set MERGE_HEAD [list]
-       switch -- [llength $parents] {
-       0       {set commit_type amend-initial}
-       1       {set commit_type amend}
-       default {set commit_type amend-merge}
-       }
-
-       $ui_comm delete 0.0 end
-       $ui_comm insert end $msg
-       $ui_comm edit reset
-       $ui_comm edit modified false
-       rescan {set ui_status_value {Ready.}}
-}
-
-proc create_new_commit {} {
-       global commit_type ui_comm
-
-       set commit_type normal
-       $ui_comm delete 0.0 end
-       $ui_comm edit reset
-       $ui_comm edit modified false
-       rescan {set ui_status_value {Ready.}}
-}
-
-set GIT_COMMITTER_IDENT {}
-
-proc committer_ident {} {
-       global GIT_COMMITTER_IDENT
-
-       if {$GIT_COMMITTER_IDENT eq {}} {
-               if {[catch {set me [exec git var GIT_COMMITTER_IDENT]} err]} {
-                       error_popup "Unable to obtain your identity:\n\n$err"
-                       return {}
-               }
-               if {![regexp {^(.*) [0-9]+ [-+0-9]+$} \
-                       $me me GIT_COMMITTER_IDENT]} {
-                       error_popup "Invalid GIT_COMMITTER_IDENT:\n\n$me"
-                       return {}
-               }
-       }
-
-       return $GIT_COMMITTER_IDENT
-}
-
-proc commit_tree {} {
-       global HEAD commit_type file_states ui_comm repo_config
-       global ui_status_value pch_error
-
-       if {![lock_index update]} return
-       if {[committer_ident] eq {}} return
-
-       # -- Our in memory state should match the repository.
-       #
-       repository_state curType curHEAD curMERGE_HEAD
-       if {[string match amend* $commit_type]
-               && $curType eq {normal}
-               && $curHEAD eq $HEAD} {
-       } elseif {$commit_type ne $curType || $HEAD ne $curHEAD} {
-               info_popup {Last scanned state does not match repository state.
-
-Another Git program has modified this repository
-since the last scan.  A rescan must be performed
-before another commit can be created.
-
-The rescan will be automatically started now.
-}
-               unlock_index
-               rescan {set ui_status_value {Ready.}}
-               return
-       }
-
-       # -- At least one file should differ in the index.
-       #
-       set files_ready 0
-       foreach path [array names file_states] {
-               switch -glob -- [lindex $file_states($path) 0] {
-               _? {continue}
-               A? -
-               D? -
-               M? {set files_ready 1}
-               U? {
-                       error_popup "Unmerged files cannot be committed.
-
-File [short_path $path] has merge conflicts.
-You must resolve them and add the file before committing.
-"
-                       unlock_index
-                       return
-               }
-               default {
-                       error_popup "Unknown file state [lindex $s 0] detected.
-
-File [short_path $path] cannot be committed by this program.
-"
-               }
-               }
-       }
-       if {!$files_ready} {
-               error_popup {No changes to commit.
-
-You must add at least 1 file before you can commit.
-}
-               unlock_index
-               return
-       }
-
-       # -- A message is required.
-       #
-       set msg [string trim [$ui_comm get 1.0 end]]
-       if {$msg eq {}} {
-               error_popup {Please supply a commit message.
-
-A good commit message has the following format:
-
-- First line: Describe in one sentance what you did.
-- Second line: Blank
-- Remaining lines: Describe why this change is good.
-}
-               unlock_index
-               return
-       }
-
-       # -- Run the pre-commit hook.
-       #
-       set pchook [gitdir hooks pre-commit]
-
-       # On Cygwin [file executable] might lie so we need to ask
-       # the shell if the hook is executable.  Yes that's annoying.
-       #
-       if {[is_Windows] && [file isfile $pchook]} {
-               set pchook [list sh -c [concat \
-                       "if test -x \"$pchook\";" \
-                       "then exec \"$pchook\" 2>&1;" \
-                       "fi"]]
-       } elseif {[file executable $pchook]} {
-               set pchook [list $pchook |& cat]
-       } else {
-               commit_writetree $curHEAD $msg
-               return
-       }
-
-       set ui_status_value {Calling pre-commit hook...}
-       set pch_error {}
-       set fd_ph [open "| $pchook" r]
-       fconfigure $fd_ph -blocking 0 -translation binary
-       fileevent $fd_ph readable \
-               [list commit_prehook_wait $fd_ph $curHEAD $msg]
-}
-
-proc commit_prehook_wait {fd_ph curHEAD msg} {
-       global pch_error ui_status_value
-
-       append pch_error [read $fd_ph]
-       fconfigure $fd_ph -blocking 1
-       if {[eof $fd_ph]} {
-               if {[catch {close $fd_ph}]} {
-                       set ui_status_value {Commit declined by pre-commit hook.}
-                       hook_failed_popup pre-commit $pch_error
-                       unlock_index
-               } else {
-                       commit_writetree $curHEAD $msg
-               }
-               set pch_error {}
-               return
-       }
-       fconfigure $fd_ph -blocking 0
-}
-
-proc commit_writetree {curHEAD msg} {
-       global ui_status_value
-
-       set ui_status_value {Committing changes...}
-       set fd_wt [open "| git write-tree" r]
-       fileevent $fd_wt readable \
-               [list commit_committree $fd_wt $curHEAD $msg]
-}
-
-proc commit_committree {fd_wt curHEAD msg} {
-       global HEAD PARENT MERGE_HEAD commit_type
-       global single_commit
-       global ui_status_value ui_comm selected_commit_type
-       global file_states selected_paths rescan_active
-
-       gets $fd_wt tree_id
-       if {$tree_id eq {} || [catch {close $fd_wt} err]} {
-               error_popup "write-tree failed:\n\n$err"
-               set ui_status_value {Commit failed.}
-               unlock_index
-               return
-       }
-
-       # -- Create the commit.
-       #
-       set cmd [list git commit-tree $tree_id]
-       set parents [concat $PARENT $MERGE_HEAD]
-       if {[llength $parents] > 0} {
-               foreach p $parents {
-                       lappend cmd -p $p
-               }
-       } else {
-               # git commit-tree writes to stderr during initial commit.
-               lappend cmd 2>/dev/null
-       }
-       lappend cmd << $msg
-       if {[catch {set cmt_id [eval exec $cmd]} err]} {
-               error_popup "commit-tree failed:\n\n$err"
-               set ui_status_value {Commit failed.}
-               unlock_index
-               return
-       }
-
-       # -- Update the HEAD ref.
-       #
-       set reflogm commit
-       if {$commit_type ne {normal}} {
-               append reflogm " ($commit_type)"
-       }
-       set i [string first "\n" $msg]
-       if {$i >= 0} {
-               append reflogm {: } [string range $msg 0 [expr {$i - 1}]]
-       } else {
-               append reflogm {: } $msg
-       }
-       set cmd [list git update-ref -m $reflogm HEAD $cmt_id $curHEAD]
-       if {[catch {eval exec $cmd} err]} {
-               error_popup "update-ref failed:\n\n$err"
-               set ui_status_value {Commit failed.}
-               unlock_index
-               return
-       }
-
-       # -- Cleanup after ourselves.
-       #
-       catch {file delete [gitdir MERGE_HEAD]}
-       catch {file delete [gitdir MERGE_MSG]}
-       catch {file delete [gitdir SQUASH_MSG]}
-       catch {file delete [gitdir GITGUI_MSG]}
-
-       # -- Let rerere do its thing.
-       #
-       if {[file isdirectory [gitdir rr-cache]]} {
-               catch {exec git rerere}
-       }
-
-       # -- Run the post-commit hook.
-       #
-       set pchook [gitdir hooks post-commit]
-       if {[is_Windows] && [file isfile $pchook]} {
-               set pchook [list sh -c [concat \
-                       "if test -x \"$pchook\";" \
-                       "then exec \"$pchook\";" \
-                       "fi"]]
-       } elseif {![file executable $pchook]} {
-               set pchook {}
-       }
-       if {$pchook ne {}} {
-               catch {exec $pchook &}
+       } else {
+               set buf_rdf {}
        }
 
        }
 
-       $ui_comm delete 0.0 end
-       $ui_comm edit reset
-       $ui_comm edit modified false
-
-       if {$single_commit} do_quit
+       rescan_done $fd buf_rdf $after
+}
 
 
-       # -- Update in memory status
-       #
-       set selected_commit_type new
-       set commit_type normal
-       set HEAD $cmt_id
-       set PARENT $cmt_id
-       set MERGE_HEAD [list]
+proc read_ls_others {fd after} {
+       global buf_rlo
 
 
-       foreach path [array names file_states] {
-               set s $file_states($path)
-               set m [lindex $s 0]
-               switch -glob -- $m {
-               _O -
-               _M -
-               _D {continue}
-               __ -
-               A_ -
-               M_ -
-               D_ {
-                       unset file_states($path)
-                       catch {unset selected_paths($path)}
-               }
-               DO {
-                       set file_states($path) [list _O [lindex $s 1] {} {}]
-               }
-               AM -
-               AD -
-               MM -
-               MD {
-                       set file_states($path) [list \
-                               _[string index $m 1] \
-                               [lindex $s 1] \
-                               [lindex $s 3] \
-                               {}]
-               }
+       append buf_rlo [read $fd]
+       set pck [split $buf_rlo "\0"]
+       set buf_rlo [lindex $pck end]
+       foreach p [lrange $pck 0 end-1] {
+               set p [encoding convertfrom $p]
+               if {[string index $p end] eq {/}} {
+                       set p [string range $p 0 end-1]
                }
                }
+               merge_state $p ?O
        }
        }
-
-       display_all_files
-       unlock_index
-       reshow_diff
-       set ui_status_value \
-               "Changes committed as [string range $cmt_id 0 7]."
-}
-
-######################################################################
-##
-## fetch pull push
-
-proc fetch_from {remote} {
-       set w [new_console "fetch $remote" \
-               "Fetching new changes from $remote"]
-       set cmd [list git fetch]
-       lappend cmd $remote
-       console_exec $w $cmd
-}
-
-proc pull_remote {remote branch} {
-       global HEAD commit_type file_states repo_config
-
-       if {![lock_index update]} return
-
-       # -- Our in memory state should match the repository.
-       #
-       repository_state curType curHEAD curMERGE_HEAD
-       if {$commit_type ne $curType || $HEAD ne $curHEAD} {
-               info_popup {Last scanned state does not match repository state.
-
-Another Git program has modified this repository
-since the last scan.  A rescan must be performed
-before a pull operation can be started.
-
-The rescan will be automatically started now.
+       rescan_done $fd buf_rlo $after
 }
 }
-               unlock_index
-               rescan {set ui_status_value {Ready.}}
-               return
-       }
 
 
-       # -- No differences should exist before a pull.
-       #
-       if {[array size file_states] != 0} {
-               error_popup {Uncommitted but modified files are present.
-
-You should not perform a pull with unmodified
-files in your working directory as Git will be
-unable to recover from an incorrect merge.
+proc rescan_done {fd buf after} {
+       global rescan_active current_diff_path
+       global file_states repo_config
+       upvar $buf to_clear
 
 
-You should commit or revert all changes before
-starting a pull operation.
-}
-               unlock_index
-               return
-       }
+       if {![eof $fd]} return
+       set to_clear {}
+       close $fd
+       if {[incr rescan_active -1] > 0} return
 
 
-       set w [new_console "pull $remote $branch" \
-               "Pulling new changes from branch $branch in $remote"]
-       set cmd [list git pull]
-       if {$repo_config(gui.pullsummary) eq {false}} {
-               lappend cmd --no-summary
-       }
-       lappend cmd $remote
-       lappend cmd $branch
-       console_exec $w $cmd [list post_pull_remote $remote $branch]
+       prune_selection
+       unlock_index
+       display_all_files
+       if {$current_diff_path ne {}} reshow_diff
+       uplevel #0 $after
 }
 
 }
 
-proc post_pull_remote {remote branch success} {
-       global HEAD PARENT MERGE_HEAD commit_type selected_commit_type
-       global ui_status_value
+proc prune_selection {} {
+       global file_states selected_paths
 
 
-       unlock_index
-       if {$success} {
-               repository_state commit_type HEAD MERGE_HEAD
-               set PARENT $HEAD
-               set selected_commit_type new
-               set ui_status_value "Pulling $branch from $remote complete."
-       } else {
-               rescan [list set ui_status_value \
-                       "Conflicts detected while pulling $branch from $remote."]
+       foreach path [array names selected_paths] {
+               if {[catch {set still_here $file_states($path)}]} {
+                       unset selected_paths($path)
+               }
        }
 }
 
        }
 }
 
-proc push_to {remote} {
-       set w [new_console "push $remote" \
-               "Pushing changes to $remote"]
-       set cmd [list git push]
-       lappend cmd $remote
-       console_exec $w $cmd
-}
-
 ######################################################################
 ##
 ## ui helpers
 ######################################################################
 ##
 ## ui helpers
@@ -1236,7 +1311,22 @@ proc mapdesc {state path} {
        return $r
 }
 
        return $r
 }
 
+proc ui_status {msg} {
+       global main_status
+       if {[info exists main_status]} {
+               $main_status show $msg
+       }
+}
+
+proc ui_ready {{test {}}} {
+       global main_status
+       if {[info exists main_status]} {
+               $main_status show [mc "Ready."] $test
+       }
+}
+
 proc escape_path {path} {
 proc escape_path {path} {
+       regsub -all {\\} $path "\\\\" path
        regsub -all "\n" $path "\\n" path
        return $path
 }
        regsub -all "\n" $path "\\n" path
        return $path
 }
@@ -1287,7 +1377,7 @@ proc display_file_helper {w path icon_name old_m new_m} {
        global file_lists
 
        if {$new_m eq {_}} {
        global file_lists
 
        if {$new_m eq {_}} {
-               set lno [lsearch -sorted $file_lists($w) $path]
+               set lno [lsearch -sorted -exact $file_lists($w) $path]
                if {$lno >= 0} {
                        set file_lists($w) [lreplace $file_lists($w) $lno $lno]
                        incr lno
                if {$lno >= 0} {
                        set file_lists($w) [lreplace $file_lists($w) $lno $lno]
                        incr lno
@@ -1298,7 +1388,7 @@ proc display_file_helper {w path icon_name old_m new_m} {
        } elseif {$old_m eq {_} && $new_m ne {_}} {
                lappend file_lists($w) $path
                set file_lists($w) [lsort -unique $file_lists($w)]
        } elseif {$old_m eq {_} && $new_m ne {_}} {
                lappend file_lists($w) $path
                set file_lists($w) [lsort -unique $file_lists($w)]
-               set lno [lsearch -sorted $file_lists($w) $path]
+               set lno [lsearch -sorted -exact $file_lists($w) $path]
                incr lno
                $w conf -state normal
                $w image create $lno.0 \
                incr lno
                $w conf -state normal
                $w image create $lno.0 \
@@ -1345,875 +1435,63 @@ proc display_file {path state} {
        }
        display_file_helper     $ui_workdir $path $icon_name $o $n
 
        }
        display_file_helper     $ui_workdir $path $icon_name $o $n
 
-       if {$new_m eq {__}} {
-               unset file_states($path)
-               catch {unset selected_paths($path)}
-       }
-}
-
-proc display_all_files_helper {w path icon_name m} {
-       global file_lists
-
-       lappend file_lists($w) $path
-       set lno [expr {[lindex [split [$w index end] .] 0] - 1}]
-       $w image create end \
-               -align center -padx 5 -pady 1 \
-               -name $icon_name \
-               -image [mapicon $w $m $path]
-       $w insert end "[escape_path $path]\n"
-}
-
-proc display_all_files {} {
-       global ui_index ui_workdir
-       global file_states file_lists
-       global last_clicked
-
-       $ui_index conf -state normal
-       $ui_workdir conf -state normal
-
-       $ui_index delete 0.0 end
-       $ui_workdir delete 0.0 end
-       set last_clicked {}
-
-       set file_lists($ui_index) [list]
-       set file_lists($ui_workdir) [list]
-
-       foreach path [lsort [array names file_states]] {
-               set s $file_states($path)
-               set m [lindex $s 0]
-               set icon_name [lindex $s 1]
-
-               set s [string index $m 0]
-               if {$s ne {U} && $s ne {_}} {
-                       display_all_files_helper $ui_index $path \
-                               $icon_name $s
-               }
-
-               if {[string index $m 0] eq {U}} {
-                       set s U
-               } else {
-                       set s [string index $m 1]
-               }
-               if {$s ne {_}} {
-                       display_all_files_helper $ui_workdir $path \
-                               $icon_name $s
-               }
-       }
-
-       $ui_index conf -state disabled
-       $ui_workdir conf -state disabled
-}
-
-proc update_indexinfo {msg pathList after} {
-       global update_index_cp ui_status_value
-
-       if {![lock_index update]} return
-
-       set update_index_cp 0
-       set pathList [lsort $pathList]
-       set totalCnt [llength $pathList]
-       set batch [expr {int($totalCnt * .01) + 1}]
-       if {$batch > 25} {set batch 25}
-
-       set ui_status_value [format \
-               "$msg... %i/%i files (%.2f%%)" \
-               $update_index_cp \
-               $totalCnt \
-               0.0]
-       set fd [open "| git update-index -z --index-info" w]
-       fconfigure $fd \
-               -blocking 0 \
-               -buffering full \
-               -buffersize 512 \
-               -translation binary
-       fileevent $fd writable [list \
-               write_update_indexinfo \
-               $fd \
-               $pathList \
-               $totalCnt \
-               $batch \
-               $msg \
-               $after \
-               ]
-}
-
-proc write_update_indexinfo {fd pathList totalCnt batch msg after} {
-       global update_index_cp ui_status_value
-       global file_states current_diff_path
-
-       if {$update_index_cp >= $totalCnt} {
-               close $fd
-               unlock_index
-               uplevel #0 $after
-               return
-       }
-
-       for {set i $batch} \
-               {$update_index_cp < $totalCnt && $i > 0} \
-               {incr i -1} {
-               set path [lindex $pathList $update_index_cp]
-               incr update_index_cp
-
-               set s $file_states($path)
-               switch -glob -- [lindex $s 0] {
-               A? {set new _O}
-               M? {set new _M}
-               D_ {set new _D}
-               D? {set new _?}
-               ?? {continue}
-               }
-               set info [lindex $s 2]
-               if {$info eq {}} continue
-
-               puts -nonewline $fd "$info\t$path\0"
-               display_file $path $new
-       }
-
-       set ui_status_value [format \
-               "$msg... %i/%i files (%.2f%%)" \
-               $update_index_cp \
-               $totalCnt \
-               [expr {100.0 * $update_index_cp / $totalCnt}]]
-}
-
-proc update_index {msg pathList after} {
-       global update_index_cp ui_status_value
-
-       if {![lock_index update]} return
-
-       set update_index_cp 0
-       set pathList [lsort $pathList]
-       set totalCnt [llength $pathList]
-       set batch [expr {int($totalCnt * .01) + 1}]
-       if {$batch > 25} {set batch 25}
-
-       set ui_status_value [format \
-               "$msg... %i/%i files (%.2f%%)" \
-               $update_index_cp \
-               $totalCnt \
-               0.0]
-       set fd [open "| git update-index --add --remove -z --stdin" w]
-       fconfigure $fd \
-               -blocking 0 \
-               -buffering full \
-               -buffersize 512 \
-               -translation binary
-       fileevent $fd writable [list \
-               write_update_index \
-               $fd \
-               $pathList \
-               $totalCnt \
-               $batch \
-               $msg \
-               $after \
-               ]
-}
-
-proc write_update_index {fd pathList totalCnt batch msg after} {
-       global update_index_cp ui_status_value
-       global file_states current_diff_path
-
-       if {$update_index_cp >= $totalCnt} {
-               close $fd
-               unlock_index
-               uplevel #0 $after
-               return
-       }
-
-       for {set i $batch} \
-               {$update_index_cp < $totalCnt && $i > 0} \
-               {incr i -1} {
-               set path [lindex $pathList $update_index_cp]
-               incr update_index_cp
-
-               switch -glob -- [lindex $file_states($path) 0] {
-               AD {set new __}
-               ?D {set new D_}
-               _O -
-               AM {set new A_}
-               U? {
-                       if {[file exists $path]} {
-                               set new M_
-                       } else {
-                               set new D_
-                       }
-               }
-               ?M {set new M_}
-               ?? {continue}
-               }
-               puts -nonewline $fd "$path\0"
-               display_file $path $new
-       }
-
-       set ui_status_value [format \
-               "$msg... %i/%i files (%.2f%%)" \
-               $update_index_cp \
-               $totalCnt \
-               [expr {100.0 * $update_index_cp / $totalCnt}]]
-}
-
-proc checkout_index {msg pathList after} {
-       global update_index_cp ui_status_value
-
-       if {![lock_index update]} return
-
-       set update_index_cp 0
-       set pathList [lsort $pathList]
-       set totalCnt [llength $pathList]
-       set batch [expr {int($totalCnt * .01) + 1}]
-       if {$batch > 25} {set batch 25}
-
-       set ui_status_value [format \
-               "$msg... %i/%i files (%.2f%%)" \
-               $update_index_cp \
-               $totalCnt \
-               0.0]
-       set cmd [list git checkout-index]
-       lappend cmd --index
-       lappend cmd --quiet
-       lappend cmd --force
-       lappend cmd -z
-       lappend cmd --stdin
-       set fd [open "| $cmd " w]
-       fconfigure $fd \
-               -blocking 0 \
-               -buffering full \
-               -buffersize 512 \
-               -translation binary
-       fileevent $fd writable [list \
-               write_checkout_index \
-               $fd \
-               $pathList \
-               $totalCnt \
-               $batch \
-               $msg \
-               $after \
-               ]
-}
-
-proc write_checkout_index {fd pathList totalCnt batch msg after} {
-       global update_index_cp ui_status_value
-       global file_states current_diff_path
-
-       if {$update_index_cp >= $totalCnt} {
-               close $fd
-               unlock_index
-               uplevel #0 $after
-               return
-       }
-
-       for {set i $batch} \
-               {$update_index_cp < $totalCnt && $i > 0} \
-               {incr i -1} {
-               set path [lindex $pathList $update_index_cp]
-               incr update_index_cp
-               switch -glob -- [lindex $file_states($path) 0] {
-               U? {continue}
-               ?M -
-               ?D {
-                       puts -nonewline $fd "$path\0"
-                       display_file $path ?_
-               }
-               }
-       }
-
-       set ui_status_value [format \
-               "$msg... %i/%i files (%.2f%%)" \
-               $update_index_cp \
-               $totalCnt \
-               [expr {100.0 * $update_index_cp / $totalCnt}]]
-}
-
-######################################################################
-##
-## branch management
-
-proc load_all_heads {} {
-       global all_heads tracking_branches
-
-       set all_heads [list]
-       set cmd [list git for-each-ref]
-       lappend cmd --format=%(refname)
-       lappend cmd refs/heads
-       set fd [open "| $cmd" r]
-       while {[gets $fd line] > 0} {
-               if {![catch {set info $tracking_branches($line)}]} continue
-               if {![regsub ^refs/heads/ $line {} name]} continue
-               lappend all_heads $name
-       }
-       close $fd
-
-       set all_heads [lsort $all_heads]
-}
-
-proc populate_branch_menu {} {
-       global all_heads disable_on_lock
-
-       set m .mbar.branch
-       set last [$m index last]
-       for {set i 0} {$i <= $last} {incr i} {
-               if {[$m type $i] eq {separator}} {
-                       $m delete $i last
-                       set new_dol [list]
-                       foreach a $disable_on_lock {
-                               if {[lindex $a 0] ne $m || [lindex $a 2] < $i} {
-                                       lappend new_dol $a
-                               }
-                       }
-                       set disable_on_lock $new_dol
-                       break
-               }
-       }
-
-       $m add separator
-       foreach b $all_heads {
-               $m add radiobutton \
-                       -label $b \
-                       -command [list switch_branch $b] \
-                       -variable current_branch \
-                       -value $b \
-                       -font font_ui
-               lappend disable_on_lock \
-                       [list $m entryconf [$m index last] -state]
-       }
-}
-
-proc do_create_branch_action {w} {
-       global all_heads null_sha1
-       global create_branch_checkout create_branch_revtype
-       global create_branch_head create_branch_trackinghead
-
-       set newbranch [string trim [$w.desc.name.t get 0.0 end]]
-       if {![catch {exec git show-ref --verify -- "refs/heads/$newbranch"}]} {
-               tk_messageBox \
-                       -icon error \
-                       -type ok \
-                       -title [wm title $w] \
-                       -parent $w \
-                       -message "Branch '$newbranch' already exists."
-               focus $w.desc.name.t
-               return
-       }
-       if {[catch {exec git check-ref-format "heads/$newbranch"}]} {
-               tk_messageBox \
-                       -icon error \
-                       -type ok \
-                       -title [wm title $w] \
-                       -parent $w \
-                       -message "We do not like '$newbranch' as a branch name."
-               focus $w.desc.name.t
-               return
-       }
-
-       set rev {}
-       switch -- $create_branch_revtype {
-       head {set rev $create_branch_head}
-       tracking {set rev $create_branch_trackinghead}
-       expression {set rev [string trim [$w.from.exp.t get 0.0 end]]}
-       }
-       if {[catch {set cmt [exec git rev-parse --verify "${rev}^0"]}]} {
-               tk_messageBox \
-                       -icon error \
-                       -type ok \
-                       -title [wm title $w] \
-                       -parent $w \
-                       -message "Invalid starting revision: $rev"
-               return
-       }
-       set cmd [list git update-ref]
-       lappend cmd -m
-       lappend cmd "branch: Created from $rev"
-       lappend cmd "refs/heads/$newbranch"
-       lappend cmd $cmt
-       lappend cmd $null_sha1
-       if {[catch {eval exec $cmd} err]} {
-               tk_messageBox \
-                       -icon error \
-                       -type ok \
-                       -title [wm title $w] \
-                       -parent $w \
-                       -message "Failed to create '$newbranch'.\n\n$err"
-               return
-       }
-
-       lappend all_heads $newbranch
-       set all_heads [lsort $all_heads]
-       populate_branch_menu
-       destroy $w
-       if {$create_branch_checkout} {
-               switch_branch $newbranch
-       }
-}
-
-proc do_create_branch {} {
-       global all_heads current_branch tracking_branches
-       global create_branch_checkout create_branch_revtype
-       global create_branch_head create_branch_trackinghead
-
-       set create_branch_checkout 1
-       set create_branch_revtype head
-       set create_branch_head $current_branch
-       set create_branch_trackinghead {}
-
-       set w .branch_editor
-       toplevel $w
-       wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
-
-       label $w.header -text {Create New Branch} \
-               -font font_uibold
-       pack $w.header -side top -fill x
-
-       frame $w.buttons
-       button $w.buttons.create -text Create \
-               -font font_ui \
-               -default active \
-               -command [list do_create_branch_action $w]
-       pack $w.buttons.create -side right
-       button $w.buttons.cancel -text {Cancel} \
-               -font font_ui \
-               -command [list destroy $w]
-       pack $w.buttons.cancel -side right -padx 5
-       pack $w.buttons -side bottom -fill x -pady 10 -padx 10
-
-       labelframe $w.desc \
-               -text {Branch Description} \
-               -font font_ui
-       frame $w.desc.name
-       label $w.desc.name.l -text {Name:} -font font_ui
-       text $w.desc.name.t \
-               -borderwidth 1 \
-               -relief sunken \
-               -height 1 \
-               -width 40 \
-               -font font_ui
-       bind $w.desc.name.t <Shift-Key-Tab> "focus $w.postActions.checkout;break"
-       bind $w.desc.name.t <Key-Tab> "focus $w.from.exp.t;break"
-       bind $w.desc.name.t <Key-Return> "do_create_branch_action $w;break"
-       bind $w.desc.name.t <Key> {
-               if {{%K} ne {BackSpace}
-                       && {%K} ne {Tab}
-                       && {%K} ne {Escape}
-                       && {%K} ne {Return}} {
-                       if {%k <= 32} break
-                       if {[string first %A {~^:?*[}] >= 0} break
-               }
-       }
-       pack $w.desc.name.l -side left -padx 5
-       pack $w.desc.name.t -side left -fill x -expand 1
-       pack $w.desc.name -padx 5 -fill x -expand 1
-       pack $w.desc -anchor nw -fill x -pady 5 -padx 5
-
-       set all_trackings [list]
-       foreach b [array names tracking_branches] {
-               regsub ^refs/(heads|remotes)/ $b {} b
-               lappend all_trackings $b
-       }
-       set all_trackings [lsort -unique $all_trackings]
-       if {$all_trackings ne {}} {
-               set create_branch_trackinghead [lindex $all_trackings 0]
-       }
-
-       labelframe $w.from \
-               -text {Starting Revision} \
-               -font font_ui
-       frame $w.from.head
-       radiobutton $w.from.head.r \
-               -text {Local Branch:} \
-               -value head \
-               -variable create_branch_revtype \
-               -font font_ui
-       eval tk_optionMenu $w.from.head.m create_branch_head $all_heads
-       pack $w.from.head.r -side left
-       pack $w.from.head.m -side left
-       frame $w.from.tracking
-       radiobutton $w.from.tracking.r \
-               -text {Tracking Branch:} \
-               -value tracking \
-               -variable create_branch_revtype \
-               -font font_ui
-       eval tk_optionMenu $w.from.tracking.m \
-               create_branch_trackinghead \
-               $all_trackings
-       pack $w.from.tracking.r -side left
-       pack $w.from.tracking.m -side left
-       frame $w.from.exp
-       radiobutton $w.from.exp.r \
-               -text {Revision Expression:} \
-               -value expression \
-               -variable create_branch_revtype \
-               -font font_ui
-       text $w.from.exp.t \
-               -borderwidth 1 \
-               -relief sunken \
-               -height 1 \
-               -width 50 \
-               -font font_ui
-       bind $w.from.exp.t <Shift-Key-Tab> "focus $w.desc.name.t;break"
-       bind $w.from.exp.t <Key-Tab> "focus $w.postActions.checkout;break"
-       bind $w.from.exp.t <Key-Return> "do_create_branch_action $w;break"
-       pack $w.from.exp.r -side left
-       pack $w.from.exp.t -side left -fill x -expand 1
-       pack $w.from.head -padx 5 -fill x -expand 1
-       pack $w.from.tracking -padx 5 -fill x -expand 1
-       pack $w.from.exp -padx 5 -fill x -expand 1
-       pack $w.from -anchor nw -fill x -pady 5 -padx 5
-
-       labelframe $w.postActions \
-               -text {Post Creation Actions} \
-               -font font_ui
-       checkbutton $w.postActions.checkout \
-               -text {Checkout after creation} \
-               -variable create_branch_checkout \
-               -font font_ui
-       pack $w.postActions.checkout -anchor nw
-       pack $w.postActions -anchor nw -fill x -pady 5 -padx 5
-
-       bind $w <Visibility> "grab $w; focus $w.desc.name.t"
-       bind $w <Key-Escape> "destroy $w"
-       bind $w <Key-Return> "do_create_branch_action $w;break"
-       wm title $w "[appname] ([reponame]): Create Branch"
-       tkwait window $w
-}
-
-proc do_delete_branch_action {w} {
-       global all_heads
-       global delete_branch_checkhead delete_branch_head
-
-       set to_delete [list]
-       set not_merged [list]
-       foreach i [$w.list.l curselection] {
-               set b [$w.list.l get $i]
-               if {[catch {set o [exec git rev-parse --verify $b]}]} continue
-               if {$delete_branch_checkhead} {
-                       if {$b eq $delete_branch_head} continue
-                       if {[catch {set m [exec git merge-base $o $delete_branch_head]}]} continue
-                       if {$o ne $m} {
-                               lappend not_merged $b
-                               continue
-                       }
-               }
-               lappend to_delete [list $b $o]
-       }
-       if {$not_merged ne {}} {
-               set msg "The following branches are not completely merged into $delete_branch_head:
-
- - [join $not_merged "\n - "]"
-               tk_messageBox \
-                       -icon info \
-                       -type ok \
-                       -title [wm title $w] \
-                       -parent $w \
-                       -message $msg
-       }
-       if {$to_delete eq {}} return
-       if {!$delete_branch_checkhead} {
-               set msg {Recovering deleted branches is difficult.
-
-Delete the selected branches?}
-               if {[tk_messageBox \
-                       -icon warning \
-                       -type yesno \
-                       -title [wm title $w] \
-                       -parent $w \
-                       -message $msg] ne yes} {
-                       return
-               }
-       }
-
-       set failed {}
-       foreach i $to_delete {
-               set b [lindex $i 0]
-               set o [lindex $i 1]
-               if {[catch {exec git update-ref -d "refs/heads/$b" $o} err]} {
-                       append failed " - $b: $err\n"
-               } else {
-                       set x [lsearch -sorted $all_heads $b]
-                       if {$x >= 0} {
-                               set all_heads [lreplace $all_heads $x $x]
-                       }
-               }
-       }
-
-       if {$failed ne {}} {
-               tk_messageBox \
-                       -icon error \
-                       -type ok \
-                       -title [wm title $w] \
-                       -parent $w \
-                       -message "Failed to delete branches:\n$failed"
-       }
-
-       set all_heads [lsort $all_heads]
-       populate_branch_menu
-       destroy $w
-}
-
-proc do_delete_branch {} {
-       global all_heads tracking_branches current_branch
-       global delete_branch_checkhead delete_branch_head
-
-       set delete_branch_checkhead 1
-       set delete_branch_head $current_branch
-
-       set w .branch_editor
-       toplevel $w
-       wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
-
-       label $w.header -text {Delete Local Branch} \
-               -font font_uibold
-       pack $w.header -side top -fill x
-
-       frame $w.buttons
-       button $w.buttons.create -text Delete \
-               -font font_ui \
-               -command [list do_delete_branch_action $w]
-       pack $w.buttons.create -side right
-       button $w.buttons.cancel -text {Cancel} \
-               -font font_ui \
-               -command [list destroy $w]
-       pack $w.buttons.cancel -side right -padx 5
-       pack $w.buttons -side bottom -fill x -pady 10 -padx 10
-
-       labelframe $w.list \
-               -text {Local Branches} \
-               -font font_ui
-       listbox $w.list.l \
-               -height 10 \
-               -width 50 \
-               -selectmode extended \
-               -font font_ui
-       foreach h $all_heads {
-               if {$h ne $current_branch} {
-                       $w.list.l insert end $h
-               }
-       }
-       pack $w.list.l -fill both -pady 5 -padx 5
-       pack $w.list -fill both -pady 5 -padx 5
-
-       set all_trackings [list]
-       foreach b [array names tracking_branches] {
-               regsub ^refs/(heads|remotes)/ $b {} b
-               lappend all_trackings $b
-       }
-
-       labelframe $w.validate \
-               -text {Only Delete If} \
-               -font font_ui
-       frame $w.validate.head
-       checkbutton $w.validate.head.r \
-               -text {Already Merged Into:} \
-               -variable delete_branch_checkhead \
-               -font font_ui
-       eval tk_optionMenu $w.validate.head.m delete_branch_head \
-               $all_heads \
-               [lsort -unique $all_trackings]
-       pack $w.validate.head.r -side left
-       pack $w.validate.head.m -side left
-       pack $w.validate.head -padx 5 -fill x -expand 1
-       pack $w.validate -anchor nw -fill x -pady 5 -padx 5
-
-       bind $w <Visibility> "grab $w; focus $w"
-       bind $w <Key-Escape> "destroy $w"
-       wm title $w "[appname] ([reponame]): Delete Branch"
-       tkwait window $w
-}
-
-proc switch_branch {b} {
-       global HEAD commit_type file_states current_branch
-       global selected_commit_type ui_comm
-
-       if {![lock_index switch]} return
-
-       # -- Backup the selected branch (repository_state resets it)
-       #
-       set new_branch $current_branch
-
-       # -- Our in memory state should match the repository.
-       #
-       repository_state curType curHEAD curMERGE_HEAD
-       if {[string match amend* $commit_type]
-               && $curType eq {normal}
-               && $curHEAD eq $HEAD} {
-       } elseif {$commit_type ne $curType || $HEAD ne $curHEAD} {
-               info_popup {Last scanned state does not match repository state.
-
-Another Git program has modified this repository
-since the last scan.  A rescan must be performed
-before the current branch can be changed.
-
-The rescan will be automatically started now.
-}
-               unlock_index
-               rescan {set ui_status_value {Ready.}}
-               return
-       }
-
-       # -- Toss the message buffer if we are in amend mode.
-       #
-       if {[string match amend* $curType]} {
-               $ui_comm delete 0.0 end
-               $ui_comm edit reset
-               $ui_comm edit modified false
-       }
-
-       set selected_commit_type new
-       set current_branch $new_branch
-
-       unlock_index
-       error "NOT FINISHED"
-}
-
-######################################################################
-##
-## remote management
-
-proc load_all_remotes {} {
-       global repo_config
-       global all_remotes tracking_branches
-
-       set all_remotes [list]
-       array unset tracking_branches
-
-       set rm_dir [gitdir remotes]
-       if {[file isdirectory $rm_dir]} {
-               set all_remotes [glob \
-                       -types f \
-                       -tails \
-                       -nocomplain \
-                       -directory $rm_dir *]
-
-               foreach name $all_remotes {
-                       catch {
-                               set fd [open [file join $rm_dir $name] r]
-                               while {[gets $fd line] >= 0} {
-                                       if {![regexp {^Pull:[   ]*([^:]+):(.+)$} \
-                                               $line line src dst]} continue
-                                       if {![regexp ^refs/ $dst]} {
-                                               set dst "refs/heads/$dst"
-                                       }
-                                       set tracking_branches($dst) [list $name $src]
-                               }
-                               close $fd
-                       }
-               }
-       }
-
-       foreach line [array names repo_config remote.*.url] {
-               if {![regexp ^remote\.(.*)\.url\$ $line line name]} continue
-               lappend all_remotes $name
-
-               if {[catch {set fl $repo_config(remote.$name.fetch)}]} {
-                       set fl {}
-               }
-               foreach line $fl {
-                       if {![regexp {^([^:]+):(.+)$} $line line src dst]} continue
-                       if {![regexp ^refs/ $dst]} {
-                               set dst "refs/heads/$dst"
-                       }
-                       set tracking_branches($dst) [list $name $src]
-               }
+       if {$new_m eq {__}} {
+               unset file_states($path)
+               catch {unset selected_paths($path)}
        }
        }
+}
+
+proc display_all_files_helper {w path icon_name m} {
+       global file_lists
 
 
-       set all_remotes [lsort -unique $all_remotes]
+       lappend file_lists($w) $path
+       set lno [expr {[lindex [split [$w index end] .] 0] - 1}]
+       $w image create end \
+               -align center -padx 5 -pady 1 \
+               -name $icon_name \
+               -image [mapicon $w $m $path]
+       $w insert end "[escape_path $path]\n"
 }
 
 }
 
-proc populate_fetch_menu {m} {
-       global all_remotes repo_config
+proc display_all_files {} {
+       global ui_index ui_workdir
+       global file_states file_lists
+       global last_clicked
 
 
-       foreach r $all_remotes {
-               set enable 0
-               if {![catch {set a $repo_config(remote.$r.url)}]} {
-                       if {![catch {set a $repo_config(remote.$r.fetch)}]} {
-                               set enable 1
-                       }
-               } else {
-                       catch {
-                               set fd [open [gitdir remotes $r] r]
-                               while {[gets $fd n] >= 0} {
-                                       if {[regexp {^Pull:[ \t]*([^:]+):} $n]} {
-                                               set enable 1
-                                               break
-                                       }
-                               }
-                               close $fd
-                       }
-               }
+       $ui_index conf -state normal
+       $ui_workdir conf -state normal
 
 
-               if {$enable} {
-                       $m add command \
-                               -label "Fetch from $r..." \
-                               -command [list fetch_from $r] \
-                               -font font_ui
-               }
-       }
-}
+       $ui_index delete 0.0 end
+       $ui_workdir delete 0.0 end
+       set last_clicked {}
 
 
-proc populate_push_menu {m} {
-       global all_remotes repo_config
+       set file_lists($ui_index) [list]
+       set file_lists($ui_workdir) [list]
 
 
-       foreach r $all_remotes {
-               set enable 0
-               if {![catch {set a $repo_config(remote.$r.url)}]} {
-                       if {![catch {set a $repo_config(remote.$r.push)}]} {
-                               set enable 1
-                       }
-               } else {
-                       catch {
-                               set fd [open [gitdir remotes $r] r]
-                               while {[gets $fd n] >= 0} {
-                                       if {[regexp {^Push:[ \t]*([^:]+):} $n]} {
-                                               set enable 1
-                                               break
-                                       }
-                               }
-                               close $fd
-                       }
-               }
+       foreach path [lsort [array names file_states]] {
+               set s $file_states($path)
+               set m [lindex $s 0]
+               set icon_name [lindex $s 1]
 
 
-               if {$enable} {
-                       $m add command \
-                               -label "Push to $r..." \
-                               -command [list push_to $r] \
-                               -font font_ui
+               set s [string index $m 0]
+               if {$s ne {U} && $s ne {_}} {
+                       display_all_files_helper $ui_index $path \
+                               $icon_name $s
                }
                }
-       }
-}
-
-proc populate_pull_menu {m} {
-       global repo_config all_remotes disable_on_lock
 
 
-       foreach remote $all_remotes {
-               set rb_list [list]
-               if {[array get repo_config remote.$remote.url] ne {}} {
-                       if {[array get repo_config remote.$remote.fetch] ne {}} {
-                               foreach line $repo_config(remote.$remote.fetch) {
-                                       if {[regexp {^([^:]+):} $line line rb]} {
-                                               lappend rb_list $rb
-                                       }
-                               }
-                       }
+               if {[string index $m 0] eq {U}} {
+                       set s U
                } else {
                } else {
-                       catch {
-                               set fd [open [gitdir remotes $remote] r]
-                               while {[gets $fd line] >= 0} {
-                                       if {[regexp {^Pull:[ \t]*([^:]+):} $line line rb]} {
-                                               lappend rb_list $rb
-                                       }
-                               }
-                               close $fd
-                       }
+                       set s [string index $m 1]
                }
                }
-
-               foreach rb $rb_list {
-                       regsub ^refs/heads/ $rb {} rb_short
-                       $m add command \
-                               -label "Branch $rb_short from $remote..." \
-                               -command [list pull_remote $remote $rb] \
-                               -font font_ui
-                       lappend disable_on_lock \
-                               [list $m entryconf [$m index last] -state]
+               if {$s ne {_}} {
+                       display_all_files_helper $ui_workdir $path \
+                               $icon_name $s
                }
        }
                }
        }
+
+       $ui_index conf -state disabled
+       $ui_workdir conf -state disabled
 }
 
 ######################################################################
 }
 
 ######################################################################
@@ -2309,31 +1587,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
 
@@ -2341,27 +1620,13 @@ unset i
 ##
 ## util
 
 ##
 ## util
 
-proc is_MacOSX {} {
-       global tcl_platform tk_library
-       if {[tk windowingsystem] eq {aqua}} {
-               return 1
-       }
-       return 0
-}
-
-proc is_Windows {} {
-       global tcl_platform
-       if {$tcl_platform(platform) eq {windows}} {
-               return 1
-       }
-       return 0
+proc scrollbar2many {list mode args} {
+       foreach w $list {eval $w $mode $args}
 }
 
 }
 
-proc bind_button3 {w cmd} {
-       bind $w <Any-Button-3> $cmd
-       if {[is_MacOSX]} {
-               bind $w <Control-Button-1> $cmd
-       }
+proc many2scrollbar {list mode sb top bottom} {
+       $sb set $top $bottom
+       foreach w $list {$w $mode moveto $top}
 }
 
 proc incr_font_size {font {amt 1}} {
 }
 
 proc incr_font_size {font {amt 1}} {
@@ -2369,819 +1634,121 @@ proc incr_font_size {font {amt 1}} {
        incr sz $amt
        font configure $font -size $sz
        font configure ${font}bold -size $sz
        incr sz $amt
        font configure $font -size $sz
        font configure ${font}bold -size $sz
-}
-
-proc hook_failed_popup {hook msg} {
-       set w .hookfail
-       toplevel $w
-
-       frame $w.m
-       label $w.m.l1 -text "$hook hook failed:" \
-               -anchor w \
-               -justify left \
-               -font font_uibold
-       text $w.m.t \
-               -background white -borderwidth 1 \
-               -relief sunken \
-               -width 80 -height 10 \
-               -font font_diff \
-               -yscrollcommand [list $w.m.sby set]
-       label $w.m.l2 \
-               -text {You must correct the above errors before committing.} \
-               -anchor w \
-               -justify left \
-               -font font_uibold
-       scrollbar $w.m.sby -command [list $w.m.t yview]
-       pack $w.m.l1 -side top -fill x
-       pack $w.m.l2 -side bottom -fill x
-       pack $w.m.sby -side right -fill y
-       pack $w.m.t -side left -fill both -expand 1
-       pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10
-
-       $w.m.t insert 1.0 $msg
-       $w.m.t conf -state disabled
-
-       button $w.ok -text OK \
-               -width 15 \
-               -font font_ui \
-               -command "destroy $w"
-       pack $w.ok -side bottom -anchor e -pady 10 -padx 10
-
-       bind $w <Visibility> "grab $w; focus $w"
-       bind $w <Key-Return> "destroy $w"
-       wm title $w "[appname] ([reponame]): error"
-       tkwait window $w
-}
-
-set next_console_id 0
-
-proc new_console {short_title long_title} {
-       global next_console_id console_data
-       set w .console[incr next_console_id]
-       set console_data($w) [list $short_title $long_title]
-       return [console_init $w]
-}
-
-proc console_init {w} {
-       global console_cr console_data M1B
-
-       set console_cr($w) 1.0
-       toplevel $w
-       frame $w.m
-       label $w.m.l1 -text "[lindex $console_data($w) 1]:" \
-               -anchor w \
-               -justify left \
-               -font font_uibold
-       text $w.m.t \
-               -background white -borderwidth 1 \
-               -relief sunken \
-               -width 80 -height 10 \
-               -font font_diff \
-               -state disabled \
-               -yscrollcommand [list $w.m.sby set]
-       label $w.m.s -text {Working... please wait...} \
-               -anchor w \
-               -justify left \
-               -font font_uibold
-       scrollbar $w.m.sby -command [list $w.m.t yview]
-       pack $w.m.l1 -side top -fill x
-       pack $w.m.s -side bottom -fill x
-       pack $w.m.sby -side right -fill y
-       pack $w.m.t -side left -fill both -expand 1
-       pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10
-
-       menu $w.ctxm -tearoff 0
-       $w.ctxm add command -label "Copy" \
-               -font font_ui \
-               -command "tk_textCopy $w.m.t"
-       $w.ctxm add command -label "Select All" \
-               -font font_ui \
-               -command "$w.m.t tag add sel 0.0 end"
-       $w.ctxm add command -label "Copy All" \
-               -font font_ui \
-               -command "
-                       $w.m.t tag add sel 0.0 end
-                       tk_textCopy $w.m.t
-                       $w.m.t tag remove sel 0.0 end
-               "
-
-       button $w.ok -text {Close} \
-               -font font_ui \
-               -state disabled \
-               -command "destroy $w"
-       pack $w.ok -side bottom -anchor e -pady 10 -padx 10
-
-       bind_button3 $w.m.t "tk_popup $w.ctxm %X %Y"
-       bind $w.m.t <$M1B-Key-a> "$w.m.t tag add sel 0.0 end;break"
-       bind $w.m.t <$M1B-Key-A> "$w.m.t tag add sel 0.0 end;break"
-       bind $w <Visibility> "focus $w"
-       wm title $w "[appname] ([reponame]): [lindex $console_data($w) 0]"
-       return $w
-}
-
-proc console_exec {w cmd {after {}}} {
-       # -- Windows tosses the enviroment when we exec our child.
-       #    But most users need that so we have to relogin. :-(
-       #
-       if {[is_Windows]} {
-               set cmd [list sh --login -c "cd \"[pwd]\" && [join $cmd { }]"]
-       }
-
-       # -- Tcl won't let us redirect both stdout and stderr to
-       #    the same pipe.  So pass it through cat...
-       #
-       set cmd [concat | $cmd |& cat]
-
-       set fd_f [open $cmd r]
-       fconfigure $fd_f -blocking 0 -translation binary
-       fileevent $fd_f readable [list console_read $w $fd_f $after]
-}
-
-proc console_read {w fd after} {
-       global console_cr console_data
-
-       set buf [read $fd]
-       if {$buf ne {}} {
-               if {![winfo exists $w]} {console_init $w}
-               $w.m.t conf -state normal
-               set c 0
-               set n [string length $buf]
-               while {$c < $n} {
-                       set cr [string first "\r" $buf $c]
-                       set lf [string first "\n" $buf $c]
-                       if {$cr < 0} {set cr [expr {$n + 1}]}
-                       if {$lf < 0} {set lf [expr {$n + 1}]}
-
-                       if {$lf < $cr} {
-                               $w.m.t insert end [string range $buf $c $lf]
-                               set console_cr($w) [$w.m.t index {end -1c}]
-                               set c $lf
-                               incr c
-                       } else {
-                               $w.m.t delete $console_cr($w) end
-                               $w.m.t insert end "\n"
-                               $w.m.t insert end [string range $buf $c $cr]
-                               set c $cr
-                               incr c
-                       }
-               }
-               $w.m.t conf -state disabled
-               $w.m.t see end
-       }
-
-       fconfigure $fd -blocking 1
-       if {[eof $fd]} {
-               if {[catch {close $fd}]} {
-                       if {![winfo exists $w]} {console_init $w}
-                       $w.m.s conf -background red -text {Error: Command Failed}
-                       $w.ok conf -state normal
-                       set ok 0
-               } elseif {[winfo exists $w]} {
-                       $w.m.s conf -background green -text {Success}
-                       $w.ok conf -state normal
-                       set ok 1
-               }
-               array unset console_cr $w
-               array unset console_data $w
-               if {$after ne {}} {
-                       uplevel #0 $after $ok
-               }
-               return
-       }
-       fconfigure $fd -blocking 0
+       font configure ${font}italic -size $sz
 }
 
 ######################################################################
 ##
 ## 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} {
 
 proc do_gitk {revs} {
-       global ui_status_value starting_gitk_msg
-
-       set cmd gitk
-       if {$revs ne {}} {
-               append cmd { }
-               append cmd $revs
-       }
-       if {[is_Windows]} {
-               set cmd "sh -c \"exec $cmd\""
-       }
-       append cmd { &}
-
-       if {[catch {eval exec $cmd} err]} {
-               error_popup "Failed to start gitk:\n\n$err"
-       } else {
-               set ui_status_value $starting_gitk_msg
-               after 10000 {
-                       if {$ui_status_value eq $starting_gitk_msg} {
-                               set ui_status_value {Ready.}
-                       }
-               }
-       }
-}
-
-proc do_gc {} {
-       set w [new_console {gc} {Compressing the object database}]
-       console_exec $w {git gc}
-}
-
-proc do_fsck_objects {} {
-       set w [new_console {fsck-objects} \
-               {Verifying the object database with fsck-objects}]
-       set cmd [list git fsck-objects]
-       lappend cmd --full
-       lappend cmd --cache
-       lappend cmd --strict
-       console_exec $w $cmd
-}
-
-set is_quitting 0
-
-proc do_quit {} {
-       global ui_comm is_quitting repo_config commit_type
-
-       if {$is_quitting} return
-       set is_quitting 1
-
-       # -- Stash our current commit buffer.
-       #
-       set save [gitdir GITGUI_MSG]
-       set msg [string trim [$ui_comm get 0.0 end]]
-       if {![string match amend* $commit_type]
-               && [$ui_comm edit modified]
-               && $msg ne {}} {
-               catch {
-                       set fd [open $save w]
-                       puts $fd [string trim [$ui_comm get 0.0 end]]
-                       close $fd
-               }
-       } else {
-               catch {file delete $save}
-       }
-
-       # -- Stash our current window geometry into this repository.
+       # -- Always start gitk through whatever we were loaded with.  This
+       #    lets us bypass using shell process on Windows systems.
        #
        #
-       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]
-       if {[catch {set rc_geometry $repo_config(gui.geometry)}]} {
-               set rc_geometry {}
-       }
-       if {$cfg_geometry ne $rc_geometry} {
-               catch {exec git repo-config gui.geometry $cfg_geometry}
-       }
-
-       destroy .
-}
-
-proc do_rescan {} {
-       rescan {set ui_status_value {Ready.}}
-}
-
-proc unstage_helper {txt paths} {
-       global file_states current_diff_path
-
-       if {![lock_index begin-update]} return
-
-       set pathList [list]
-       set after {}
-       foreach path $paths {
-               switch -glob -- [lindex $file_states($path) 0] {
-               A? -
-               M? -
-               D? {
-                       lappend pathList $path
-                       if {$path eq $current_diff_path} {
-                               set after {reshow_diff;}
-                       }
-               }
-               }
-       }
-       if {$pathList eq {}} {
-               unlock_index
+       set exe [file join [file dirname $::_git] gitk]
+       set cmd [list [info nameofexecutable] $exe]
+       if {! [file exists $exe]} {
+               error_popup [mc "Unable to start gitk:\n\n%s does not exist" $exe]
        } else {
        } else {
-               update_indexinfo \
-                       $txt \
-                       $pathList \
-                       [concat $after {set ui_status_value {Ready.}}]
-       }
-}
-
-proc do_unstage_selection {} {
-       global current_diff_path selected_paths
-
-       if {[array size selected_paths] > 0} {
-               unstage_helper \
-                       {Unstaging selected files from commit} \
-                       [array names selected_paths]
-       } elseif {$current_diff_path ne {}} {
-               unstage_helper \
-                       "Unstaging [short_path $current_diff_path] from commit" \
-                       [list $current_diff_path]
-       }
-}
-
-proc add_helper {txt paths} {
-       global file_states current_diff_path
+               global env
 
 
-       if {![lock_index begin-update]} return
-
-       set pathList [list]
-       set after {}
-       foreach path $paths {
-               switch -glob -- [lindex $file_states($path) 0] {
-               _O -
-               ?M -
-               ?D -
-               U? {
-                       lappend pathList $path
-                       if {$path eq $current_diff_path} {
-                               set after {reshow_diff;}
-                       }
-               }
+               if {[info exists env(GIT_DIR)]} {
+                       set old_GIT_DIR $env(GIT_DIR)
+               } else {
+                       set old_GIT_DIR {}
                }
                }
-       }
-       if {$pathList eq {}} {
-               unlock_index
-       } else {
-               update_index \
-                       $txt \
-                       $pathList \
-                       [concat $after {set ui_status_value {Ready to commit.}}]
-       }
-}
 
 
-proc do_add_selection {} {
-       global current_diff_path selected_paths
+               set pwd [pwd]
+               cd [file dirname [gitdir]]
+               set env(GIT_DIR) [file tail [gitdir]]
 
 
-       if {[array size selected_paths] > 0} {
-               add_helper \
-                       {Adding selected files} \
-                       [array names selected_paths]
-       } elseif {$current_diff_path ne {}} {
-               add_helper \
-                       "Adding [short_path $current_diff_path]" \
-                       [list $current_diff_path]
-       }
-}
+               eval exec $cmd $revs &
 
 
-proc do_add_all {} {
-       global file_states
-
-       set paths [list]
-       foreach path [array names file_states] {
-               switch -glob -- [lindex $file_states($path) 0] {
-               U? {continue}
-               ?M -
-               ?D {lappend paths $path}
+               if {$old_GIT_DIR eq {}} {
+                       unset env(GIT_DIR)
+               } else {
+                       set env(GIT_DIR) $old_GIT_DIR
                }
                }
-       }
-       add_helper {Adding all changed files} $paths
-}
-
-proc revert_helper {txt paths} {
-       global file_states current_diff_path
-
-       if {![lock_index begin-update]} return
+               cd $pwd
 
 
-       set pathList [list]
-       set after {}
-       foreach path $paths {
-               switch -glob -- [lindex $file_states($path) 0] {
-               U? {continue}
-               ?M -
-               ?D {
-                       lappend pathList $path
-                       if {$path eq $current_diff_path} {
-                               set after {reshow_diff;}
-                       }
-               }
+               ui_status $::starting_gitk_msg
+               after 10000 {
+                       ui_ready $starting_gitk_msg
                }
        }
                }
        }
-
-       set n [llength $pathList]
-       if {$n == 0} {
-               unlock_index
-               return
-       } elseif {$n == 1} {
-               set s "[short_path [lindex $pathList]]"
-       } else {
-               set s "these $n files"
-       }
-
-       set reply [tk_dialog \
-               .confirm_revert \
-               "[appname] ([reponame])" \
-               "Revert changes in $s?
-
-Any unadded changes will be permanently lost by the revert." \
-               question \
-               1 \
-               {Do Nothing} \
-               {Revert Changes} \
-               ]
-       if {$reply == 1} {
-               checkout_index \
-                       $txt \
-                       $pathList \
-                       [concat $after {set ui_status_value {Ready.}}]
-       } else {
-               unlock_index
-       }
-}
-
-proc do_revert_selection {} {
-       global current_diff_path selected_paths
-
-       if {[array size selected_paths] > 0} {
-               revert_helper \
-                       {Reverting selected files} \
-                       [array names selected_paths]
-       } elseif {$current_diff_path ne {}} {
-               revert_helper \
-                       "Reverting [short_path $current_diff_path]" \
-                       [list $current_diff_path]
-       }
 }
 
 }
 
-proc do_signoff {} {
-       global ui_comm
-
-       set me [committer_ident]
-       if {$me eq {}} return
-
-       set sob "Signed-off-by: $me"
-       set last [$ui_comm get {end -1c linestart} {end -1c}]
-       if {$last ne $sob} {
-               $ui_comm edit separator
-               if {$last ne {}
-                       && ![regexp {^[A-Z][A-Za-z]*-[A-Za-z-]+: *} $last]} {
-                       $ui_comm insert end "\n"
-               }
-               $ui_comm insert end "\n$sob"
-               $ui_comm edit separator
-               $ui_comm see end
-       }
-}
+set is_quitting 0
 
 
-proc do_select_commit_type {} {
-       global commit_type selected_commit_type
+proc do_quit {} {
+       global ui_comm is_quitting repo_config commit_type
+       global GITGUI_BCK_exists GITGUI_BCK_i
+       global ui_comm_spell
 
 
-       if {$selected_commit_type eq {new}
-               && [string match amend* $commit_type]} {
-               create_new_commit
-       } elseif {$selected_commit_type eq {amend}
-               && ![string match amend* $commit_type]} {
-               load_last_commit
+       if {$is_quitting} return
+       set is_quitting 1
 
 
-               # The amend request was rejected...
+       if {[winfo exists $ui_comm]} {
+               # -- Stash our current commit buffer.
                #
                #
-               if {![string match amend* $commit_type]} {
-                       set selected_commit_type new
-               }
-       }
-}
-
-proc do_commit {} {
-       commit_tree
-}
-
-proc do_about {} {
-       global appvers copyright
-       global tcl_patchLevel tk_patchLevel
-
-       set w .about_dialog
-       toplevel $w
-       wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
-
-       label $w.header -text "About [appname]" \
-               -font font_uibold
-       pack $w.header -side top -fill x
-
-       frame $w.buttons
-       button $w.buttons.close -text {Close} \
-               -font font_ui \
-               -command [list destroy $w]
-       pack $w.buttons.close -side right
-       pack $w.buttons -side bottom -fill x -pady 10 -padx 10
-
-       label $w.desc \
-               -text "[appname] - a commit creation tool for Git.
-$copyright" \
-               -padx 5 -pady 5 \
-               -justify left \
-               -anchor w \
-               -borderwidth 1 \
-               -relief solid \
-               -font font_ui
-       pack $w.desc -side top -fill x -padx 5 -pady 5
-
-       set v {}
-       append v "[appname] version $appvers\n"
-       append v "[exec git version]\n"
-       append v "\n"
-       if {$tcl_patchLevel eq $tk_patchLevel} {
-               append v "Tcl/Tk version $tcl_patchLevel"
-       } else {
-               append v "Tcl version $tcl_patchLevel"
-               append v ", Tk version $tk_patchLevel"
-       }
-
-       label $w.vers \
-               -text $v \
-               -padx 5 -pady 5 \
-               -justify left \
-               -anchor w \
-               -borderwidth 1 \
-               -relief solid \
-               -font font_ui
-       pack $w.vers -side top -fill x -padx 5 -pady 5
-
-       menu $w.ctxm -tearoff 0
-       $w.ctxm add command \
-               -label {Copy} \
-               -font font_ui \
-               -command "
-               clipboard clear
-               clipboard append -format STRING -type STRING -- \[$w.vers cget -text\]
-       "
-
-       bind $w <Visibility> "grab $w; focus $w"
-       bind $w <Key-Escape> "destroy $w"
-       bind_button3 $w.vers "tk_popup $w.ctxm %X %Y; grab $w; focus $w"
-       wm title $w "About [appname]"
-       tkwait window $w
-}
-
-proc do_options {} {
-       global repo_config global_config font_descs
-       global repo_config_new global_config_new
-
-       array unset repo_config_new
-       array unset global_config_new
-       foreach name [array names repo_config] {
-               set repo_config_new($name) $repo_config($name)
-       }
-       load_config 1
-       foreach name [array names repo_config] {
-               switch -- $name {
-               gui.diffcontext {continue}
-               }
-               set repo_config_new($name) $repo_config($name)
-       }
-       foreach name [array names global_config] {
-               set global_config_new($name) $global_config($name)
-       }
-
-       set w .options_editor
-       toplevel $w
-       wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
-
-       label $w.header -text "[appname] Options" \
-               -font font_uibold
-       pack $w.header -side top -fill x
-
-       frame $w.buttons
-       button $w.buttons.restore -text {Restore Defaults} \
-               -font font_ui \
-               -command do_restore_defaults
-       pack $w.buttons.restore -side left
-       button $w.buttons.save -text Save \
-               -font font_ui \
-               -command [list do_save_config $w]
-       pack $w.buttons.save -side right
-       button $w.buttons.cancel -text {Cancel} \
-               -font font_ui \
-               -command [list destroy $w]
-       pack $w.buttons.cancel -side right -padx 5
-       pack $w.buttons -side bottom -fill x -pady 10 -padx 10
-
-       labelframe $w.repo -text "[reponame] Repository" \
-               -font font_ui \
-               -relief raised -borderwidth 2
-       labelframe $w.global -text {Global (All Repositories)} \
-               -font font_ui \
-               -relief raised -borderwidth 2
-       pack $w.repo -side left -fill both -expand 1 -pady 5 -padx 5
-       pack $w.global -side right -fill both -expand 1 -pady 5 -padx 5
-
-       foreach option {
-               {b pullsummary {Show Pull Summary}}
-               {b trustmtime  {Trust File Modification Timestamps}}
-               {i diffcontext {Number of Diff Context Lines}}
-               } {
-               set type [lindex $option 0]
-               set name [lindex $option 1]
-               set text [lindex $option 2]
-               foreach f {repo global} {
-                       switch $type {
-                       b {
-                               checkbutton $w.$f.$name -text $text \
-                                       -variable ${f}_config_new(gui.$name) \
-                                       -onvalue true \
-                                       -offvalue false \
-                                       -font font_ui
-                               pack $w.$f.$name -side top -anchor w
-                       }
-                       i {
-                               frame $w.$f.$name
-                               label $w.$f.$name.l -text "$text:" -font font_ui
-                               pack $w.$f.$name.l -side left -anchor w -fill x
-                               spinbox $w.$f.$name.v \
-                                       -textvariable ${f}_config_new(gui.$name) \
-                                       -from 1 -to 99 -increment 1 \
-                                       -width 3 \
-                                       -font font_ui
-                               pack $w.$f.$name.v -side right -anchor e
-                               pack $w.$f.$name -side top -anchor w -fill x
-                       }
+               set save [gitdir GITGUI_MSG]
+               if {$GITGUI_BCK_exists && ![$ui_comm edit modified]} {
+                       file rename -force [gitdir GITGUI_BCK] $save
+                       set GITGUI_BCK_exists 0
+               } else {
+                       set msg [string trim [$ui_comm get 0.0 end]]
+                       regsub -all -line {[ \r\t]+$} $msg {} msg
+                       if {(![string match amend* $commit_type]
+                               || [$ui_comm edit modified])
+                               && $msg ne {}} {
+                               catch {
+                                       set fd [open $save w]
+                                       puts -nonewline $fd $msg
+                                       close $fd
+                               }
+                       } else {
+                               catch {file delete $save}
                        }
                }
                        }
                }
-       }
 
 
-       set all_fonts [lsort [font families]]
-       foreach option $font_descs {
-               set name [lindex $option 0]
-               set font [lindex $option 1]
-               set text [lindex $option 2]
-
-               set global_config_new(gui.$font^^family) \
-                       [font configure $font -family]
-               set global_config_new(gui.$font^^size) \
-                       [font configure $font -size]
-
-               frame $w.global.$name
-               label $w.global.$name.l -text "$text:" -font font_ui
-               pack $w.global.$name.l -side left -anchor w -fill x
-               eval tk_optionMenu $w.global.$name.family \
-                       global_config_new(gui.$font^^family) \
-                       $all_fonts
-               spinbox $w.global.$name.size \
-                       -textvariable global_config_new(gui.$font^^size) \
-                       -from 2 -to 80 -increment 1 \
-                       -width 3 \
-                       -font font_ui
-               pack $w.global.$name.size -side right -anchor e
-               pack $w.global.$name.family -side right -anchor e
-               pack $w.global.$name -side top -anchor w -fill x
-       }
-
-       bind $w <Visibility> "grab $w; focus $w"
-       bind $w <Key-Escape> "destroy $w"
-       wm title $w "[appname] ([reponame]): Options"
-       tkwait window $w
-}
-
-proc do_restore_defaults {} {
-       global font_descs default_config repo_config
-       global repo_config_new global_config_new
-
-       foreach name [array names default_config] {
-               set repo_config_new($name) $default_config($name)
-               set global_config_new($name) $default_config($name)
-       }
-
-       foreach option $font_descs {
-               set name [lindex $option 0]
-               set repo_config(gui.$name) $default_config(gui.$name)
-       }
-       apply_config
-
-       foreach option $font_descs {
-               set name [lindex $option 0]
-               set font [lindex $option 1]
-               set global_config_new(gui.$font^^family) \
-                       [font configure $font -family]
-               set global_config_new(gui.$font^^size) \
-                       [font configure $font -size]
-       }
-}
-
-proc do_save_config {w} {
-       if {[catch {save_config} err]} {
-               error_popup "Failed to completely save options:\n\n$err"
-       }
-       reshow_diff
-       destroy $w
-}
-
-proc do_windows_shortcut {} {
-       global argv0
+               # -- Cancel our spellchecker if its running.
+               #
+               if {[info exists ui_comm_spell]} {
+                       $ui_comm_spell stop
+               }
 
 
-       if {[catch {
-               set desktop [exec cygpath \
-                       --windows \
-                       --absolute \
-                       --long-name \
-                       --desktop]
-               }]} {
-                       set desktop .
-       }
-       set fn [tk_getSaveFile \
-               -parent . \
-               -title "[appname] ([reponame]): Create Desktop Icon" \
-               -initialdir $desktop \
-               -initialfile "Git [reponame].bat"]
-       if {$fn != {}} {
-               if {[catch {
-                               set fd [open $fn w]
-                               set sh [exec cygpath \
-                                       --windows \
-                                       --absolute \
-                                       /bin/sh]
-                               set me [exec cygpath \
-                                       --unix \
-                                       --absolute \
-                                       $argv0]
-                               set gd [exec cygpath \
-                                       --unix \
-                                       --absolute \
-                                       [gitdir]]
-                               set gw [exec cygpath \
-                                       --windows \
-                                       --absolute \
-                                       [file dirname [gitdir]]]
-                               regsub -all ' $me "'\\''" me
-                               regsub -all ' $gd "'\\''" gd
-                               puts $fd "@ECHO Entering $gw"
-                               puts $fd "@ECHO Starting git-gui... please wait..."
-                               puts -nonewline $fd "@\"$sh\" --login -c \""
-                               puts -nonewline $fd "GIT_DIR='$gd'"
-                               puts -nonewline $fd " '$me'"
-                               puts $fd "&\""
-                               close $fd
-                       } err]} {
-                       error_popup "Cannot write script:\n\n$err"
+               # -- Remove our editor backup, its not needed.
+               #
+               after cancel $GITGUI_BCK_i
+               if {$GITGUI_BCK_exists} {
+                       catch {file delete [gitdir GITGUI_BCK]}
+               }
+
+               # -- Stash our current window geometry into this repository.
+               #
+               set cfg_geometry [list]
+               lappend cfg_geometry [wm geometry .]
+               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 {$cfg_geometry ne $rc_geometry} {
+                       catch {git config gui.geometry $cfg_geometry}
                }
        }
                }
        }
-}
 
 
-proc do_macosx_app {} {
-       global argv0 env
+       destroy .
+}
 
 
-       set fn [tk_getSaveFile \
-               -parent . \
-               -title "[appname] ([reponame]): Create Desktop Icon" \
-               -initialdir [file join $env(HOME) Desktop] \
-               -initialfile "Git [reponame].app"]
-       if {$fn != {}} {
-               if {[catch {
-                               set Contents [file join $fn Contents]
-                               set MacOS [file join $Contents MacOS]
-                               set exe [file join $MacOS git-gui]
-
-                               file mkdir $MacOS
-
-                               set fd [open [file join $Contents Info.plist] w]
-                               puts $fd {<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>CFBundleDevelopmentRegion</key>
-       <string>English</string>
-       <key>CFBundleExecutable</key>
-       <string>git-gui</string>
-       <key>CFBundleIdentifier</key>
-       <string>org.spearce.git-gui</string>
-       <key>CFBundleInfoDictionaryVersion</key>
-       <string>6.0</string>
-       <key>CFBundlePackageType</key>
-       <string>APPL</string>
-       <key>CFBundleSignature</key>
-       <string>????</string>
-       <key>CFBundleVersion</key>
-       <string>1.0</string>
-       <key>NSPrincipalClass</key>
-       <string>NSApplication</string>
-</dict>
-</plist>}
-                               close $fd
-
-                               set fd [open $exe w]
-                               set gd [file normalize [gitdir]]
-                               set ep [file normalize [exec git --exec-path]]
-                               regsub -all ' $gd "'\\''" gd
-                               regsub -all ' $ep "'\\''" ep
-                               puts $fd "#!/bin/sh"
-                               foreach name [array names env] {
-                                       if {[string match GIT_* $name]} {
-                                               regsub -all ' $env($name) "'\\''" v
-                                               puts $fd "export $name='$v'"
-                                       }
-                               }
-                               puts $fd "export PATH='$ep':\$PATH"
-                               puts $fd "export GIT_DIR='$gd'"
-                               puts $fd "exec [file normalize $argv0]"
-                               close $fd
+proc do_rescan {} {
+       rescan ui_ready
+}
 
 
-                               file attributes $exe -permissions u+x,g+x,o+x
-                       } err]} {
-                       error_popup "Cannot write icon:\n\n$err"
-               }
-       }
+proc do_commit {} {
+       commit_tree
 }
 
 proc toggle_or_diff {w x y} {
 }
 
 proc toggle_or_diff {w x y} {
@@ -3212,12 +1779,12 @@ proc toggle_or_diff {w x y} {
                        update_indexinfo \
                                "Unstaging [short_path $path] from commit" \
                                [list $path] \
                        update_indexinfo \
                                "Unstaging [short_path $path] from commit" \
                                [list $path] \
-                               [concat $after {set ui_status_value {Ready.}}]
+                               [concat $after [list ui_ready]]
                } elseif {$w eq $ui_workdir} {
                        update_index \
                                "Adding [short_path $path]" \
                                [list $path] \
                } elseif {$w eq $ui_workdir} {
                        update_index \
                                "Adding [short_path $path]" \
                                [list $path] \
-                               [concat $after {set ui_status_value {Ready.}}]
+                               [concat $after [list ui_ready]]
                }
        } else {
                show_diff $path $w $lno
                }
        } else {
                show_diff $path $w $lno
@@ -3281,318 +1848,419 @@ proc add_range_to_selection {w x y} {
 
 ######################################################################
 ##
 
 ######################################################################
 ##
-## 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_uibold
-font create font_diffbold
-
-if {[is_Windows]} {
-       set M1B Control
-       set M1T Ctrl
-} elseif {[is_MacOSX]} {
-       set M1B M1
-       set M1T Cmd
-} else {
-       set M1B M1
-       set M1T M1
-}
-
-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}bold -weight bold
-       }
-}
+## ui construction
 
 
-set default_config(gui.trustmtime) false
-set default_config(gui.pullsummary) true
-set default_config(gui.diffcontext) 5
-set default_config(gui.fontui) [font configure font_ui]
-set default_config(gui.fontdiff) [font configure font_diff]
-set font_descs {
-       {fontui   font_ui   {Main Font}}
-       {fontdiff font_diff {Diff/Console Font}}
-}
 load_config 0
 apply_config
 load_config 0
 apply_config
-
-######################################################################
-##
-## ui construction
+set ui_comm {}
 
 # -- Menu Bar
 #
 menu .mbar -tearoff 0
 
 # -- Menu Bar
 #
 menu .mbar -tearoff 0
-.mbar add cascade -label Repository -menu .mbar.repository
-.mbar add cascade -label Edit -menu .mbar.edit
-if {!$single_commit} {
-       .mbar add cascade -label Branch -menu .mbar.branch
+.mbar add cascade -label [mc Repository] -menu .mbar.repository
+.mbar add cascade -label [mc Edit] -menu .mbar.edit
+if {[is_enabled branch]} {
+       .mbar add cascade -label [mc Branch] -menu .mbar.branch
+}
+if {[is_enabled multicommit] || [is_enabled singlecommit]} {
+       .mbar add cascade -label [mc Commit@@noun] -menu .mbar.commit
 }
 }
-.mbar add cascade -label Commit -menu .mbar.commit
-if {!$single_commit} {
-       .mbar add cascade -label Fetch -menu .mbar.fetch
-       .mbar add cascade -label Pull -menu .mbar.pull
-       .mbar add cascade -label Push -menu .mbar.push
+if {[is_enabled transport]} {
+       .mbar add cascade -label [mc Merge] -menu .mbar.merge
+       .mbar add cascade -label [mc Remote] -menu .mbar.remote
 }
 . configure -menu .mbar
 
 # -- Repository Menu
 #
 menu .mbar.repository
 }
 . configure -menu .mbar
 
 # -- Repository Menu
 #
 menu .mbar.repository
+
 .mbar.repository add command \
 .mbar.repository add command \
-       -label {Visualize Current Branch} \
-       -command {do_gitk {}} \
-       -font font_ui
-if {![is_MacOSX]} {
-       .mbar.repository add command \
-               -label {Visualize All Branches} \
-               -command {do_gitk {--all}} \
-               -font font_ui
-}
+       -label [mc "Browse Current Branch's Files"] \
+       -command {browser::new $current_branch}
+set ui_browse_current [.mbar.repository index last]
+.mbar.repository add command \
+       -label [mc "Browse Branch Files..."] \
+       -command browser_open::dialog
+.mbar.repository add separator
+
+.mbar.repository add command \
+       -label [mc "Visualize Current Branch's History"] \
+       -command {do_gitk $current_branch}
+set ui_visualize_current [.mbar.repository index last]
+.mbar.repository add command \
+       -label [mc "Visualize All Branch History"] \
+       -command {do_gitk --all}
 .mbar.repository add separator
 
 .mbar.repository add separator
 
-if {!$single_commit} {
-       .mbar.repository add command -label {Compress Database} \
-               -command do_gc \
-               -font font_ui
+proc current_branch_write {args} {
+       global current_branch
+       .mbar.repository entryconf $::ui_browse_current \
+               -label [mc "Browse %s's Files" $current_branch]
+       .mbar.repository entryconf $::ui_visualize_current \
+               -label [mc "Visualize %s's History" $current_branch]
+}
+trace add variable current_branch write current_branch_write
+
+if {[is_enabled multicommit]} {
+       .mbar.repository add command -label [mc "Database Statistics"] \
+               -command do_stats
+
+       .mbar.repository add command -label [mc "Compress Database"] \
+               -command do_gc
 
 
-       .mbar.repository add command -label {Verify Database} \
-               -command do_fsck_objects \
-               -font font_ui
+       .mbar.repository add command -label [mc "Verify Database"] \
+               -command do_fsck_objects
 
        .mbar.repository add separator
 
 
        .mbar.repository add separator
 
-       if {[is_Windows]} {
+       if {[is_Cygwin]} {
                .mbar.repository add command \
                .mbar.repository add command \
-                       -label {Create Desktop Icon} \
-                       -command do_windows_shortcut \
-                       -font font_ui
+                       -label [mc "Create Desktop Icon"] \
+                       -command do_cygwin_shortcut
+       } elseif {[is_Windows]} {
+               .mbar.repository add command \
+                       -label [mc "Create Desktop Icon"] \
+                       -command do_windows_shortcut
        } elseif {[is_MacOSX]} {
                .mbar.repository add command \
        } elseif {[is_MacOSX]} {
                .mbar.repository add command \
-                       -label {Create Desktop Icon} \
-                       -command do_macosx_app \
-                       -font font_ui
+                       -label [mc "Create Desktop Icon"] \
+                       -command do_macosx_app
        }
 }
 
        }
 }
 
-.mbar.repository add command -label Quit \
+.mbar.repository add command -label [mc Quit] \
        -command do_quit \
        -command do_quit \
-       -accelerator $M1T-Q \
-       -font font_ui
+       -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}} \
        -command {catch {[focus] edit undo}} \
-       -accelerator $M1T-Z \
-       -font font_ui
-.mbar.edit add command -label Redo \
+       -accelerator $M1T-Z
+.mbar.edit add command -label [mc Redo] \
        -command {catch {[focus] edit redo}} \
        -command {catch {[focus] edit redo}} \
-       -accelerator $M1T-Y \
-       -font font_ui
+       -accelerator $M1T-Y
 .mbar.edit add separator
 .mbar.edit add separator
-.mbar.edit add command -label Cut \
+.mbar.edit add command -label [mc Cut] \
        -command {catch {tk_textCut [focus]}} \
        -command {catch {tk_textCut [focus]}} \
-       -accelerator $M1T-X \
-       -font font_ui
-.mbar.edit add command -label Copy \
+       -accelerator $M1T-X
+.mbar.edit add command -label [mc Copy] \
        -command {catch {tk_textCopy [focus]}} \
        -command {catch {tk_textCopy [focus]}} \
-       -accelerator $M1T-C \
-       -font font_ui
-.mbar.edit add command -label Paste \
+       -accelerator $M1T-C
+.mbar.edit add command -label [mc Paste] \
        -command {catch {tk_textPaste [focus]; [focus] see insert}} \
        -command {catch {tk_textPaste [focus]; [focus] see insert}} \
-       -accelerator $M1T-V \
-       -font font_ui
-.mbar.edit add command -label Delete \
+       -accelerator $M1T-V
+.mbar.edit add command -label [mc Delete] \
        -command {catch {[focus] delete sel.first sel.last}} \
        -command {catch {[focus] delete sel.first sel.last}} \
-       -accelerator Del \
-       -font font_ui
+       -accelerator Del
 .mbar.edit add separator
 .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}} \
        -command {catch {[focus] tag add sel 0.0 end}} \
-       -accelerator $M1T-A \
-       -font font_ui
+       -accelerator $M1T-A
 
 # -- Branch Menu
 #
 
 # -- Branch Menu
 #
-if {!$single_commit} {
+if {[is_enabled branch]} {
        menu .mbar.branch
 
        menu .mbar.branch
 
-       .mbar.branch add command -label {Create...} \
-               -command do_create_branch \
-               -accelerator $M1T-N \
-               -font font_ui
+       .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]
+
+       .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]
+
+       .mbar.branch add command -label [mc "Rename..."] \
+               -command branch_rename::dialog
+       lappend disable_on_lock [list .mbar.branch entryconf \
+               [.mbar.branch index last] -state]
+
+       .mbar.branch add command -label [mc "Delete..."] \
+               -command branch_delete::dialog
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
 
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
 
-       .mbar.branch add command -label {Delete...} \
-               -command do_delete_branch \
-               -font font_ui
+       .mbar.branch add command -label [mc "Reset..."] \
+               -command merge::reset_hard
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
 }
 
 # -- Commit Menu
 #
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
 }
 
 # -- Commit Menu
 #
-menu .mbar.commit
+if {[is_enabled multicommit] || [is_enabled singlecommit]} {
+       menu .mbar.commit
+
+       .mbar.commit add radiobutton \
+               -label [mc "New Commit"] \
+               -command do_select_commit_type \
+               -variable selected_commit_type \
+               -value new
+       lappend disable_on_lock \
+               [list .mbar.commit entryconf [.mbar.commit index last] -state]
 
 
-.mbar.commit add radiobutton \
-       -label {New Commit} \
-       -command do_select_commit_type \
-       -variable selected_commit_type \
-       -value new \
-       -font font_ui
-lappend disable_on_lock \
-       [list .mbar.commit entryconf [.mbar.commit index last] -state]
+       .mbar.commit add radiobutton \
+               -label [mc "Amend Last Commit"] \
+               -command do_select_commit_type \
+               -variable selected_commit_type \
+               -value amend
+       lappend disable_on_lock \
+               [list .mbar.commit entryconf [.mbar.commit index last] -state]
 
 
-.mbar.commit add radiobutton \
-       -label {Amend Last Commit} \
-       -command do_select_commit_type \
-       -variable selected_commit_type \
-       -value amend \
-       -font font_ui
-lappend disable_on_lock \
-       [list .mbar.commit entryconf [.mbar.commit index last] -state]
+       .mbar.commit add separator
 
 
-.mbar.commit add separator
+       .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]
 
 
-.mbar.commit add command -label Rescan \
-       -command do_rescan \
-       -accelerator F5 \
-       -font font_ui
-lappend disable_on_lock \
-       [list .mbar.commit entryconf [.mbar.commit index last] -state]
+       .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]
 
 
-.mbar.commit add command -label {Add To Commit} \
-       -command do_add_selection \
-       -font font_ui
-lappend disable_on_lock \
-       [list .mbar.commit entryconf [.mbar.commit index last] -state]
+       .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]
 
 
-.mbar.commit add command -label {Add All To Commit} \
-       -command do_add_all \
-       -accelerator $M1T-I \
-       -font font_ui
-lappend disable_on_lock \
-       [list .mbar.commit entryconf [.mbar.commit index last] -state]
+       .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]
 
 
-.mbar.commit add command -label {Unstage From Commit} \
-       -command do_unstage_selection \
-       -font font_ui
-lappend disable_on_lock \
-       [list .mbar.commit entryconf [.mbar.commit index last] -state]
+       .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 command -label {Revert Changes} \
-       -command do_revert_selection \
-       -font font_ui
-lappend disable_on_lock \
-       [list .mbar.commit entryconf [.mbar.commit index last] -state]
+       .mbar.commit add separator
 
 
-.mbar.commit add separator
+       .mbar.commit add command -label [mc "Sign Off"] \
+               -command do_signoff \
+               -accelerator $M1T-S
 
 
-.mbar.commit add command -label {Sign Off} \
-       -command do_signoff \
-       -accelerator $M1T-S \
-       -font font_ui
+       .mbar.commit add command -label [mc Commit@@verb] \
+               -command do_commit \
+               -accelerator $M1T-Return
+       lappend disable_on_lock \
+               [list .mbar.commit entryconf [.mbar.commit index last] -state]
+}
 
 
-.mbar.commit add command -label Commit \
-       -command do_commit \
-       -accelerator $M1T-Return \
-       -font font_ui
-lappend disable_on_lock \
-       [list .mbar.commit entryconf [.mbar.commit index last] -state]
+# -- Merge Menu
+#
+if {[is_enabled branch]} {
+       menu .mbar.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]
+       .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]
+}
 
 
-# -- Transport menus
+# -- Transport Menu
 #
 #
-if {!$single_commit} {
-       menu .mbar.fetch
-       menu .mbar.pull
-       menu .mbar.push
+if {[is_enabled transport]} {
+       menu .mbar.remote
+
+       .mbar.remote add command \
+               -label [mc "Push..."] \
+               -command do_push_anywhere \
+               -accelerator $M1T-P
+       .mbar.remote add command \
+               -label [mc "Delete..."] \
+               -command remote_branch_delete::dialog
 }
 
 if {[is_MacOSX]} {
        # -- Apple Menu (Mac OS X only)
        #
 }
 
 if {[is_MacOSX]} {
        # -- Apple Menu (Mac OS X only)
        #
-       .mbar add cascade -label Apple -menu .mbar.apple
+       .mbar add cascade -label [mc Apple] -menu .mbar.apple
        menu .mbar.apple
 
        menu .mbar.apple
 
-       .mbar.apple add command -label "About [appname]" \
-               -command do_about \
-               -font font_ui
-       .mbar.apple add command -label "[appname] Options..." \
+       .mbar.apple add command -label [mc "About %s" [appname]] \
+               -command do_about
+       .mbar.apple add separator
+       .mbar.apple add command \
+               -label [mc "Preferences..."] \
                -command do_options \
                -command do_options \
-               -font font_ui
+               -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...} \
-               -command do_options \
-               -font font_ui
+       .mbar.edit add command -label [mc "Options..."] \
+               -command do_options
+}
 
 
-       # -- Tools Menu
-       #
-       if {[file exists /usr/local/miga/lib/gui-miga]
-               && [file exists .pvcsrc]} {
-       proc do_miga {} {
-               global ui_status_value
-               if {![lock_index update]} return
-               set cmd [list sh --login -c "/usr/local/miga/lib/gui-miga \"[pwd]\""]
-               set miga_fd [open "|$cmd" r]
-               fconfigure $miga_fd -blocking 0
-               fileevent $miga_fd readable [list miga_done $miga_fd]
-               set ui_status_value {Running miga...}
+# -- Help Menu
+#
+.mbar add cascade -label [mc Help] -menu .mbar.help
+menu .mbar.help
+
+if {![is_MacOSX]} {
+       .mbar.help add command -label [mc "About %s" [appname]] \
+               -command do_about
+}
+
+set browser {}
+catch {set browser $repo_config(instaweb.browser)}
+set doc_path [file dirname [gitexec]]
+set doc_path [file join $doc_path Documentation index.html]
+
+if {[is_Cygwin]} {
+       set doc_path [exec cygpath --mixed $doc_path]
+}
+
+if {$browser eq {}} {
+       if {[is_MacOSX]} {
+               set browser open
+       } elseif {[is_Cygwin]} {
+               set program_files [file dirname [exec cygpath --windir]]
+               set program_files [file join $program_files {Program Files}]
+               set firefox [file join $program_files {Mozilla Firefox} firefox.exe]
+               set ie [file join $program_files {Internet Explorer} IEXPLORE.EXE]
+               if {[file exists $firefox]} {
+                       set browser $firefox
+               } elseif {[file exists $ie]} {
+                       set browser $ie
+               }
+               unset program_files firefox ie
        }
        }
-       proc miga_done {fd} {
-               read $fd 512
-               if {[eof $fd]} {
-                       close $fd
-                       unlock_index
-                       rescan [list set ui_status_value {Ready.}]
+}
+
+if {[file isfile $doc_path]} {
+       set doc_url "file:$doc_path"
+} else {
+       set doc_url {http://www.kernel.org/pub/software/scm/git/docs/}
+}
+
+if {$browser ne {}} {
+       .mbar.help add command -label [mc "Online Documentation"] \
+               -command [list exec $browser $doc_url &]
+}
+unset browser doc_path doc_url
+
+# -- Standard bindings
+#
+wm protocol . WM_DELETE_WINDOW do_quit
+bind all <$M1B-Key-q> do_quit
+bind all <$M1B-Key-Q> do_quit
+bind all <$M1B-Key-w> {destroy [winfo toplevel %W]}
+bind all <$M1B-Key-W> {destroy [winfo toplevel %W]}
+
+set subcommand_args {}
+proc usage {} {
+       puts stderr "usage: $::argv0 $::subcommand $::subcommand_args"
+       exit 1
+}
+
+# -- Not a normal commit type invocation?  Do that instead!
+#
+switch -- $subcommand {
+browser -
+blame {
+       set subcommand_args {rev? path}
+       if {$argv eq {}} usage
+       set head {}
+       set path {}
+       set is_path 0
+       foreach a $argv {
+               if {$is_path || [file exists $_prefix$a]} {
+                       if {$path ne {}} usage
+                       set path $_prefix$a
+                       break
+               } elseif {$a eq {--}} {
+                       if {$path ne {}} {
+                               if {$head ne {}} usage
+                               set head $path
+                               set path {}
+                       }
+                       set is_path 1
+               } elseif {$head eq {}} {
+                       if {$head ne {}} usage
+                       set head $a
+                       set is_path 1
+               } else {
+                       usage
                }
        }
                }
        }
-       .mbar add cascade -label Tools -menu .mbar.tools
-       menu .mbar.tools
-       .mbar.tools add command -label "Migrate" \
-               -command do_miga \
-               -font font_ui
-       lappend disable_on_lock \
-               [list .mbar.tools entryconf [.mbar.tools index last] -state]
+       unset is_path
+
+       if {$head ne {} && $path eq {}} {
+               set path $_prefix$head
+               set head {}
        }
 
        }
 
-       # -- Help Menu
-       #
-       .mbar add cascade -label Help -menu .mbar.help
-       menu .mbar.help
+       if {$head eq {}} {
+               load_current_branch
+       } else {
+               if {[regexp {^[0-9a-f]{1,39}$} $head]} {
+                       if {[catch {
+                                       set head [git rev-parse --verify $head]
+                               } err]} {
+                               puts stderr $err
+                               exit 1
+                       }
+               }
+               set current_branch $head
+       }
 
 
-       .mbar.help add command -label "About [appname]" \
-               -command do_about \
-               -font font_ui
+       switch -- $subcommand {
+       browser {
+               if {$head eq {}} {
+                       if {$path ne {} && [file isdirectory $path]} {
+                               set head $current_branch
+                       } else {
+                               set head $path
+                               set path {}
+                       }
+               }
+               browser::new $head $path
+       }
+       blame   {
+               if {$head eq {} && ![file exists $path]} {
+                       puts stderr [mc "fatal: cannot stat path %s: No such file or directory" $path]
+                       exit 1
+               }
+               blame::new $head $path
+       }
+       }
+       return
+}
+citool -
+gui {
+       if {[llength $argv] != 0} {
+               puts -nonewline stderr "usage: $argv0"
+               if {$subcommand ne {gui}
+                       && [file tail $argv0] ne "git-$subcommand"} {
+                       puts -nonewline stderr " $subcommand"
+               }
+               puts stderr {}
+               exit 1
+       }
+       # fall through to setup UI for commits
+}
+default {
+       puts stderr "usage: $argv0 \[{blame|browser|citool}\]"
+       exit 1
+}
 }
 }
-
 
 # -- Branch Control
 #
 
 # -- Branch Control
 #
@@ -3600,67 +2268,70 @@ 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 \
        -anchor w \
-       -justify left \
-       -font font_ui
+       -justify left
 label .branch.cb \
        -textvariable current_branch \
        -anchor w \
 label .branch.cb \
        -textvariable current_branch \
        -anchor w \
-       -justify left \
-       -font font_ui
+       -justify left
 pack .branch.l1 -side left
 pack .branch.cb -side left -fill x
 pack .branch -side top -fill x
 
 # -- Main Window Layout
 #
 pack .branch.l1 -side left
 pack .branch.cb -side left -fill x
 pack .branch -side top -fill x
 
 # -- Main Window Layout
 #
-panedwindow .vpane -orient vertical
-panedwindow .vpane.files -orient horizontal
-.vpane add .vpane.files -sticky nsew -height 100 -width 400
+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
 #
 pack .vpane -anchor n -side top -fill both -expand 1
 
 # -- Index File List
 #
-frame .vpane.files.index -height 100 -width 400
-label .vpane.files.index.title -text {Changes To Be Committed} \
-       -background green \
-       -font font_ui
-text $ui_index -background white -borderwidth 0 \
-       -width 40 -height 10 \
-       -font font_ui \
+frame .vpane.files.index -height 100 -width 200
+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 \
        -cursor $cursor_ptr \
-       -yscrollcommand {.vpane.files.index.sb set} \
+       -xscrollcommand {.vpane.files.index.sx set} \
+       -yscrollcommand {.vpane.files.index.sy set} \
        -state disabled
        -state disabled
-scrollbar .vpane.files.index.sb -command [list $ui_index yview]
+scrollbar .vpane.files.index.sx -orient h -command [list $ui_index xview]
+scrollbar .vpane.files.index.sy -orient v -command [list $ui_index yview]
 pack .vpane.files.index.title -side top -fill x
 pack .vpane.files.index.title -side top -fill x
-pack .vpane.files.index.sb -side right -fill y
+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 $ui_index -side left -fill both -expand 1
-.vpane.files add .vpane.files.index -sticky nsew
 
 # -- Working Directory File List
 #
 
 # -- Working Directory File List
 #
-frame .vpane.files.workdir -height 100 -width 100
-label .vpane.files.workdir.title -text {Changed But Not Updated} \
-       -background red \
-       -font font_ui
-text $ui_workdir -background white -borderwidth 0 \
-       -width 40 -height 10 \
-       -font font_ui \
+frame .vpane.files.workdir -height 100 -width 200
+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 \
        -cursor $cursor_ptr \
-       -yscrollcommand {.vpane.files.workdir.sb set} \
+       -xscrollcommand {.vpane.files.workdir.sx set} \
+       -yscrollcommand {.vpane.files.workdir.sy set} \
        -state disabled
        -state disabled
-scrollbar .vpane.files.workdir.sb -command [list $ui_workdir yview]
+scrollbar .vpane.files.workdir.sx -orient h -command [list $ui_workdir xview]
+scrollbar .vpane.files.workdir.sy -orient v -command [list $ui_workdir yview]
 pack .vpane.files.workdir.title -side top -fill x
 pack .vpane.files.workdir.title -side top -fill x
-pack .vpane.files.workdir.sb -side right -fill y
+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 $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 -font font_uibold
-       $i tag conf in_sel \
-               -background [$i cget -foreground] \
-               -foreground [$i cget -background]
+       rmsel_tag $i
+       $i tag conf in_diff -background [$i tag cget in_sel -background]
 }
 unset i
 
 }
 unset i
 
@@ -3669,46 +2340,45 @@ 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
-.vpane add .vpane.lower -stick nsew
+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
 #
 frame .vpane.lower.commarea.buttons
 label .vpane.lower.commarea.buttons.l -text {} \
        -anchor w \
 
 # -- Commit Area Buttons
 #
 frame .vpane.lower.commarea.buttons
 label .vpane.lower.commarea.buttons.l -text {} \
        -anchor w \
-       -justify left \
-       -font font_ui
+       -justify left
 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} \
-       -command do_rescan \
-       -font font_ui
+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}
 
 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 {Add All} \
-       -command do_add_all \
-       -font font_ui
+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}
 
 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} \
-       -command do_signoff \
-       -font font_ui
+button .vpane.lower.commarea.buttons.signoff -text [mc "Sign Off"] \
+       -command do_signoff
 pack .vpane.lower.commarea.buttons.signoff -side top -fill x
 
 pack .vpane.lower.commarea.buttons.signoff -side top -fill x
 
-button .vpane.lower.commarea.buttons.commit -text {Commit} \
-       -command do_commit \
-       -font font_ui
+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}
 
 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 [mc Push] \
+       -command do_push_anywhere
+pack .vpane.lower.commarea.buttons.push -side top -fill x
+
 # -- Commit Message Buffer
 #
 frame .vpane.lower.commarea.buffer
 # -- Commit Message Buffer
 #
 frame .vpane.lower.commarea.buffer
@@ -3716,34 +2386,31 @@ 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 \
        -command do_select_commit_type \
        -variable selected_commit_type \
-       -value new \
-       -font font_ui
+       -value new
 lappend disable_on_lock \
        [list .vpane.lower.commarea.buffer.header.new conf -state]
 radiobutton .vpane.lower.commarea.buffer.header.amend \
 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 \
        -command do_select_commit_type \
        -variable selected_commit_type \
-       -value amend \
-       -font font_ui
+       -value amend
 lappend disable_on_lock \
        [list .vpane.lower.commarea.buffer.header.amend conf -state]
 label $ui_coml \
        -anchor w \
 lappend disable_on_lock \
        [list .vpane.lower.commarea.buffer.header.amend conf -state]
 label $ui_coml \
        -anchor w \
-       -justify left \
-       -font font_ui
+       -justify left
 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
 }
@@ -3752,12 +2419,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 \
@@ -3772,29 +2440,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} \
-       -font font_ui \
+       -label [mc Cut] \
        -command {tk_textCut $ui_comm}
 $ctxm add command \
        -command {tk_textCut $ui_comm}
 $ctxm add command \
-       -label {Copy} \
-       -font font_ui \
+       -label [mc Copy] \
        -command {tk_textCopy $ui_comm}
 $ctxm add command \
        -command {tk_textCopy $ui_comm}
 $ctxm add command \
-       -label {Paste} \
-       -font font_ui \
+       -label [mc Paste] \
        -command {tk_textPaste $ui_comm}
 $ctxm add command \
        -command {tk_textPaste $ui_comm}
 $ctxm add command \
-       -label {Delete} \
-       -font font_ui \
+       -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} \
-       -font font_ui \
-       -command {$ui_comm tag add sel 0.0 end}
+       -label [mc "Select All"] \
+       -command {focus $ui_comm;$ui_comm tag add sel 0.0 end}
 $ctxm add command \
 $ctxm add command \
-       -label {Copy All} \
-       -font font_ui \
+       -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
@@ -3802,15 +2464,12 @@ $ctxm add command \
        }
 $ctxm add separator
 $ctxm add command \
        }
 $ctxm add separator
 $ctxm add command \
-       -label {Sign Off} \
-       -font font_ui \
+       -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
 #
-set current_diff_path {}
-set diff_actions [list]
 proc trace_current_diff_path {varname args} {
        global current_diff_path diff_actions file_states
        if {$current_diff_path eq {}} {
 proc trace_current_diff_path {varname args} {
        global current_diff_path diff_actions file_states
        if {$current_diff_path eq {}} {
@@ -3821,7 +2480,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
        }
@@ -3835,31 +2494,30 @@ proc trace_current_diff_path {varname args} {
 }
 trace add variable current_diff_path write trace_current_diff_path
 
 }
 trace add variable current_diff_path write trace_current_diff_path
 
-frame .vpane.lower.diff.header -background orange
+frame .vpane.lower.diff.header -background gold
 label .vpane.lower.diff.header.status \
 label .vpane.lower.diff.header.status \
-       -background orange \
+       -background gold \
+       -foreground black \
        -width $max_status_desc \
        -anchor w \
        -width $max_status_desc \
        -anchor w \
-       -justify left \
-       -font font_ui
+       -justify left
 label .vpane.lower.diff.header.file \
 label .vpane.lower.diff.header.file \
-       -background orange \
+       -background gold \
+       -foreground black \
        -anchor w \
        -anchor w \
-       -justify left \
-       -font font_ui
+       -justify left
 label .vpane.lower.diff.header.path \
 label .vpane.lower.diff.header.path \
-       -background orange \
+       -background gold \
+       -foreground black \
        -anchor w \
        -anchor w \
-       -justify left \
-       -font font_ui
+       -justify left
 pack .vpane.lower.diff.header.status -side left
 pack .vpane.lower.diff.header.file -side left
 pack .vpane.lower.diff.header.path -fill x
 set ctxm .vpane.lower.diff.header.ctxm
 menu $ctxm -tearoff 0
 $ctxm add command \
 pack .vpane.lower.diff.header.status -side left
 pack .vpane.lower.diff.header.file -side left
 pack .vpane.lower.diff.header.path -fill x
 set ctxm .vpane.lower.diff.header.ctxm
 menu $ctxm -tearoff 0
 $ctxm add command \
-       -label {Copy} \
-       -font font_ui \
+       -label [mc Copy] \
        -command {
                clipboard clear
                clipboard append \
        -command {
                clipboard clear
                clipboard append \
@@ -3874,7 +2532,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} \
@@ -3890,24 +2549,25 @@ pack $ui_diff -side left -fill both -expand 1
 pack .vpane.lower.diff.header -side top -fill x
 pack .vpane.lower.diff.body -side bottom -fill both -expand 1
 
 pack .vpane.lower.diff.header -side top -fill x
 pack .vpane.lower.diff.body -side bottom -fill both -expand 1
 
-$ui_diff tag conf d_@ -font font_diffbold
-$ui_diff tag conf d_+ -foreground blue
+$ui_diff tag conf d_cr -elide true
+$ui_diff tag conf d_@ -foreground blue -font font_diffbold
+$ui_diff tag conf d_+ -foreground {#00a000}
 $ui_diff tag conf d_- -foreground red
 
 $ui_diff tag conf d_- -foreground red
 
-$ui_diff tag conf d_++ -foreground blue
+$ui_diff tag conf d_++ -foreground {#00a000}
 $ui_diff tag conf d_-- -foreground red
 $ui_diff tag conf d_+s \
 $ui_diff tag conf d_-- -foreground red
 $ui_diff tag conf d_+s \
-       -foreground blue \
-       -background azure2
+       -foreground {#00a000} \
+       -background {#e2effa}
 $ui_diff tag conf d_-s \
        -foreground red \
 $ui_diff tag conf d_-s \
        -foreground red \
-       -background azure2
+       -background {#e2effa}
 $ui_diff tag conf d_s+ \
 $ui_diff tag conf d_s+ \
-       -foreground blue \
-       -background {light goldenrod yellow}
+       -foreground {#00a000} \
+       -background ivory1
 $ui_diff tag conf d_s- \
        -foreground red \
 $ui_diff tag conf d_s- \
        -foreground red \
-       -background {light goldenrod yellow}
+       -background ivory1
 
 $ui_diff tag conf d<<<<<<< \
        -foreground orange \
 
 $ui_diff tag conf d<<<<<<< \
        -foreground orange \
@@ -3919,27 +2579,47 @@ $ui_diff tag conf d>>>>>>> \
        -foreground orange \
        -font font_diffbold
 
        -foreground orange \
        -font font_diffbold
 
+$ui_diff tag raise sel
+
 # -- Diff Body Context Menu
 #
 set ctxm .vpane.lower.diff.body.ctxm
 menu $ctxm -tearoff 0
 $ctxm add command \
 # -- Diff Body Context Menu
 #
 set ctxm .vpane.lower.diff.body.ctxm
 menu $ctxm -tearoff 0
 $ctxm add command \
-       -label {Refresh} \
-       -font font_ui \
+       -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 separator
+$ctxm add command \
+       -label [mc "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 [mc "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 [mc Refresh] \
        -command reshow_diff
        -command reshow_diff
+lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
 $ctxm add command \
 $ctxm add command \
-       -label {Copy} \
-       -font font_ui \
+       -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} \
-       -font font_ui \
-       -command {$ui_diff tag add sel 0.0 end}
+       -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 \
 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
 $ctxm add command \
-       -label {Copy All} \
-       -font font_ui \
+       -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
@@ -3948,48 +2628,43 @@ $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 {Decrease Font Size} \
-       -font font_ui \
+       -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} \
-       -font font_ui \
+       -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} \
-       -font font_ui \
-       -command {if {$repo_config(gui.diffcontext) >= 2} {
-               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} \
-       -font font_ui \
-       -command {
-               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...} \
-       -font font_ui \
+$ctxm add command -label [mc "Options..."] \
        -command do_options
        -command do_options
-bind_button3 $ui_diff "tk_popup $ctxm %X %Y"
+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 l [mc "Unstage Hunk From Commit"]
+       } else {
+               set l [mc "Stage Hunk For Commit"]
+       }
+       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
+       } else {
+               set s normal
+       }
+       $ctxm entryconf $::ui_diff_applyhunk -state $s -label $l
+       tk_popup $ctxm $X $Y
+}
+bind_button3 $ui_diff [list popup_diff_menu $ctxm %x %y %X %Y]
 
 # -- Status Bar
 #
 
 # -- Status Bar
 #
-set ui_status_value {Initializing...}
-label .status -textvariable ui_status_value \
-       -anchor w \
-       -justify left \
-       -borderwidth 1 \
-       -relief sunken \
-       -font font_ui
+set main_status [::status_bar::new .status]
 pack .status -anchor w -side bottom -fill x
 pack .status -anchor w -side bottom -fill x
+$main_status show [mc "Initializing..."]
 
 # -- Load geometry
 #
 
 # -- Load geometry
 #
@@ -3997,17 +2672,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}
@@ -4031,25 +2708,37 @@ bind $ui_diff <Key-Up>     {catch {%W yview scroll -1 units};break}
 bind $ui_diff <Key-Down>   {catch {%W yview scroll  1 units};break}
 bind $ui_diff <Key-Left>   {catch {%W xview scroll -1 units};break}
 bind $ui_diff <Key-Right>  {catch {%W xview scroll  1 units};break}
 bind $ui_diff <Key-Down>   {catch {%W yview scroll  1 units};break}
 bind $ui_diff <Key-Left>   {catch {%W xview scroll -1 units};break}
 bind $ui_diff <Key-Right>  {catch {%W xview scroll  1 units};break}
-
-if {!$single_commit} {
-       bind . <$M1B-Key-n> do_create_branch
-       bind . <$M1B-Key-N> do_create_branch
-}
-
-bind .   <Destroy> do_quit
-bind all <Key-F5> do_rescan
-bind all <$M1B-Key-r> do_rescan
-bind all <$M1B-Key-R> do_rescan
+bind $ui_diff <Key-k>         {catch {%W yview scroll -1 units};break}
+bind $ui_diff <Key-j>         {catch {%W yview scroll  1 units};break}
+bind $ui_diff <Key-h>         {catch {%W xview scroll -1 units};break}
+bind $ui_diff <Key-l>         {catch {%W xview scroll  1 units};break}
+bind $ui_diff <Control-Key-b> {catch {%W yview scroll -1 pages};break}
+bind $ui_diff <Control-Key-f> {catch {%W yview scroll  1 pages};break}
+bind $ui_diff <Button-1>   {focus %W}
+
+if {[is_enabled branch]} {
+       bind . <$M1B-Key-n> branch_create::dialog
+       bind . <$M1B-Key-N> branch_create::dialog
+       bind . <$M1B-Key-o> branch_checkout::dialog
+       bind . <$M1B-Key-O> branch_checkout::dialog
+       bind . <$M1B-Key-m> merge::dialog
+       bind . <$M1B-Key-M> merge::dialog
+}
+if {[is_enabled transport]} {
+       bind . <$M1B-Key-p> do_push_anywhere
+       bind . <$M1B-Key-P> do_push_anywhere
+}
+
+bind .   <Key-F5>     do_rescan
+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-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-Return> do_commit
 bind .   <$M1B-Key-i> do_add_all
 bind .   <$M1B-Key-I> do_add_all
 bind .   <$M1B-Key-Return> do_commit
-bind all <$M1B-Key-q> do_quit
-bind all <$M1B-Key-Q> do_quit
-bind all <$M1B-Key-w> {destroy [winfo toplevel %W]}
-bind all <$M1B-Key-W> {destroy [winfo toplevel %W]}
 foreach i [list $ui_index $ui_workdir] {
        bind $i <Button-1>       "toggle_or_diff         $i %x %y; break"
        bind $i <$M1B-Button-1>  "add_one_to_selection   $i %x %y; break"
 foreach i [list $ui_index $ui_workdir] {
        bind $i <Button-1>       "toggle_or_diff         $i %x %y; break"
        bind $i <$M1B-Button-1>  "add_one_to_selection   $i %x %y; break"
@@ -4060,32 +2749,23 @@ unset i
 set file_lists($ui_index) [list]
 set file_lists($ui_workdir) [list]
 
 set file_lists($ui_index) [list]
 set file_lists($ui_workdir) [list]
 
-set HEAD {}
-set PARENT {}
-set MERGE_HEAD [list]
-set commit_type {}
-set empty_tree {}
-set current_branch {}
-set current_diff_path {}
-set selected_commit_type new
-
-wm title . "[appname] ([file normalize [file dirname [gitdir]]])"
+wm title . "[appname] ([reponame]) [file normalize [file dirname [gitdir]]]"
 focus -force $ui_comm
 
 # -- Warn the user about environmental problems.  Cygwin's Tcl
 #    does *not* pass its env array onto any processes it spawns.
 #    This means that git processes get none of our environment.
 #
 focus -force $ui_comm
 
 # -- Warn the user about environmental problems.  Cygwin's Tcl
 #    does *not* pass its env array onto any processes it spawns.
 #    This means that git processes get none of our environment.
 #
-if {[is_Windows]} {
+if {[is_Cygwin]} {
        set ignored_env 0
        set suggest_user {}
        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$} -
@@ -4109,18 +2789,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
        }
@@ -4129,36 +2809,101 @@ user.email settings into your personal
 
 # -- Only initialize complex UI if we are going to stay running.
 #
 
 # -- Only initialize complex UI if we are going to stay running.
 #
-if {!$single_commit} {
+if {[is_enabled transport]} {
        load_all_remotes
        load_all_remotes
-       load_all_heads
 
 
-       populate_branch_menu
-       populate_fetch_menu .mbar.fetch
-       populate_pull_menu .mbar.pull
-       populate_push_menu .mbar.push
+       set n [.mbar.remote index end]
+       populate_push_menu
+       populate_fetch_menu
+       set n [expr {[.mbar.remote index end] - $n}]
+       if {$n > 0} {
+               .mbar.remote insert $n separator
+       }
+       unset n
 }
 
 }
 
-# -- Only suggest a gc run if we are going to stay running.
-#
-if {!$single_commit} {
-       set object_limit 2000
-       if {[is_Windows]} {set object_limit 200}
-       regexp {^([0-9]+) objects,} [exec git count-objects] _junk objects_current
-       if {$objects_current >= $object_limit} {
-               if {[ask_popup \
-                       "This repository currently has $objects_current loose objects.
-
-To maintain optimal performance it is strongly
-recommended that you compress the database
-when more than $object_limit loose objects exist.
-
-Compress the database now?"] eq yes} {
-                       do_gc
+if {[winfo exists $ui_comm]} {
+       set GITGUI_BCK_exists [load_message GITGUI_BCK]
+
+       # -- If both our backup and message files exist use the
+       #    newer of the two files to initialize the buffer.
+       #
+       if {$GITGUI_BCK_exists} {
+               set m [gitdir GITGUI_MSG]
+               if {[file isfile $m]} {
+                       if {[file mtime [gitdir GITGUI_BCK]] > [file mtime $m]} {
+                               catch {file delete [gitdir GITGUI_MSG]}
+                       } else {
+                               $ui_comm delete 0.0 end
+                               $ui_comm edit reset
+                               $ui_comm edit modified false
+                               catch {file delete [gitdir GITGUI_BCK]}
+                               set GITGUI_BCK_exists 0
+                       }
+               }
+               unset m
+       }
+
+       proc backup_commit_buffer {} {
+               global ui_comm GITGUI_BCK_exists
+
+               set m [$ui_comm edit modified]
+               if {$m || $GITGUI_BCK_exists} {
+                       set msg [string trim [$ui_comm get 0.0 end]]
+                       regsub -all -line {[ \r\t]+$} $msg {} msg
+
+                       if {$msg eq {}} {
+                               if {$GITGUI_BCK_exists} {
+                                       catch {file delete [gitdir GITGUI_BCK]}
+                                       set GITGUI_BCK_exists 0
+                               }
+                       } elseif {$m} {
+                               catch {
+                                       set fd [open [gitdir GITGUI_BCK] w]
+                                       puts -nonewline $fd $msg
+                                       close $fd
+                                       set GITGUI_BCK_exists 1
+                               }
+                       }
+
+                       $ui_comm edit modified false
                }
                }
+
+               set ::GITGUI_BCK_i [after 2000 backup_commit_buffer]
        }
        }
-       unset object_limit _junk objects_current
+
+       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
+if {![winfo ismapped .]} {
+       wm deiconify .
+}
 after 1 do_rescan
 after 1 do_rescan
+if {[is_enabled multicommit]} {
+       after 1000 hint_gc
+}