git-gui: Make initial commits work properly.
[gitweb.git] / git-gui
diff --git a/git-gui b/git-gui
index 9a6953e970bd5a499f13404559122a903546cf30..e2e0beae95004f2bdcc09e79a59fd5dd2c84d242 100755 (executable)
--- a/git-gui
+++ b/git-gui
@@ -130,12 +130,15 @@ proc error_popup {msg} {
                        end]
                append title {)}
        }
-       tk_messageBox \
-               -parent . \
+       set cmd [list tk_messageBox \
                -icon error \
                -type ok \
                -title "$title: error" \
-               -message $msg
+               -message $msg]
+       if {[winfo ismapped .]} {
+               lappend cmd -parent .
+       }
+       eval $cmd
 }
 
 proc info_popup {msg} {
@@ -161,16 +164,27 @@ proc info_popup {msg} {
 ##
 ## repository setup
 
-if {   [catch {set cdup [exec git rev-parse --show-cdup]} err]
-       || [catch {set gitdir [exec git rev-parse --git-dir]} err]} {
+if {   [catch {set gitdir $env(GIT_DIR)}]
+       && [catch {set gitdir [exec git rev-parse --git-dir]} err]} {
        catch {wm withdraw .}
        error_popup "Cannot find the git directory:\n\n$err"
        exit 1
 }
-if {$cdup ne ""} {
-       cd $cdup
+if {![file isdirectory $gitdir]} {
+       catch {wm withdraw .}
+       error_popup "Git directory not found:\n\n$gitdir"
+       exit 1
+}
+if {[lindex [file split $gitdir] end] ne {.git}} {
+       catch {wm withdraw .}
+       error_popup "Cannot use funny .git directory:\n\n$gitdir"
+       exit 1
+}
+if {[catch {cd [file dirname $gitdir]} err]} {
+       catch {wm withdraw .}
+       error_popup "No working directory [file dirname $gitdir]:\n\n$err"
+       exit 1
 }
-unset cdup
 
 set single_commit 0
 if {$appname eq {git-citool}} {
@@ -191,6 +205,7 @@ set index_lock_type none
 set HEAD {}
 set PARENT {}
 set commit_type {}
+set empty_tree {}
 
 proc lock_index {type} {
        global index_lock_type disable_on_lock
@@ -226,6 +241,7 @@ proc repository_state {hdvar ctvar} {
        upvar $hdvar hd $ctvar ct
 
        if {[catch {set hd [exec git rev-parse --verify HEAD]}]} {
+               set hd {}
                set ct initial
        } elseif {[file exists [file join $gitdir MERGE_HEAD]]} {
                set ct merge
@@ -234,6 +250,18 @@ proc repository_state {hdvar ctvar} {
        }
 }
 
+proc PARENT {} {
+       global PARENT empty_tree
+
+       if {$PARENT ne {}} {
+               return $PARENT
+       }
+       if {$empty_tree eq {}} {
+               set empty_tree [exec git mktree << {}]
+       }
+       return $empty_tree
+}
+
 proc rescan {after} {
        global HEAD PARENT commit_type
        global ui_index ui_other ui_status_value ui_comm
@@ -243,7 +271,7 @@ proc rescan {after} {
        if {$rescan_active > 0 || ![lock_index read]} return
 
        repository_state new_HEAD new_type
-       if {$commit_type eq {amend}
+       if {[string match amend* $commit_type]
                && $new_type eq {normal}
                && $new_HEAD eq $HEAD} {
        } else {
@@ -282,10 +310,8 @@ proc rescan {after} {
 }
 
 proc rescan_stage2 {fd after} {
-       global gitdir PARENT commit_type
-       global ui_index ui_other ui_status_value ui_comm
-       global rescan_active
-       global buf_rdi buf_rdf buf_rlo
+       global gitdir ui_status_value
+       global rescan_active buf_rdi buf_rdf buf_rlo
 
        if {$fd ne {}} {
                read $fd
@@ -306,7 +332,7 @@ proc rescan_stage2 {fd after} {
 
        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_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]
 
@@ -455,34 +481,33 @@ proc prune_selection {} {
 ## diff
 
 proc clear_diff {} {
-       global ui_diff ui_fname_value ui_fstatus_value ui_index ui_other
+       global ui_diff current_diff ui_index ui_other
 
        $ui_diff conf -state normal
        $ui_diff delete 0.0 end
        $ui_diff conf -state disabled
 
-       set ui_fname_value {}
-       set ui_fstatus_value {}
+       set current_diff {}
 
        $ui_index tag remove in_diff 0.0 end
        $ui_other tag remove in_diff 0.0 end
 }
 
 proc reshow_diff {} {
-       global ui_fname_value ui_status_value file_states
+       global current_diff ui_status_value file_states
 
-       if {$ui_fname_value eq {}
-               || [catch {set s $file_states($ui_fname_value)}]} {
+       if {$current_diff eq {}
+               || [catch {set s $file_states($current_diff)}]} {
                clear_diff
        } else {
-               show_diff $ui_fname_value
+               show_diff $current_diff
        }
 }
 
 proc handle_empty_diff {} {
-       global ui_fname_value file_states file_lists
+       global current_diff file_states file_lists
 
-       set path $ui_fname_value
+       set path $current_diff
        set s $file_states($path)
        if {[lindex $s 0] ne {_M}} return
 
@@ -519,8 +544,8 @@ files list, to prevent possible confusion.
 
 proc show_diff {path {w {}} {lno {}}} {
        global file_states file_lists
-       global PARENT diff_3way diff_active repo_config
-       global ui_diff ui_fname_value ui_fstatus_value ui_status_value
+       global diff_3way diff_active repo_config
+       global ui_diff current_diff ui_status_value
 
        if {$diff_active || ![lock_index read]} return
 
@@ -542,8 +567,7 @@ proc show_diff {path {w {}} {lno {}}} {
        set m [lindex $s 0]
        set diff_3way 0
        set diff_active 1
-       set ui_fname_value $path
-       set ui_fstatus_value [mapdesc $m $path]
+       set current_diff $path
        set ui_status_value "Loading diff of [escape_path $path]..."
 
        set cmd [list | git diff-index]
@@ -579,7 +603,7 @@ proc show_diff {path {w {}} {lno {}}} {
        }
        }
 
-       lappend cmd $PARENT
+       lappend cmd [PARENT]
        lappend cmd --
        lappend cmd $path
 
@@ -659,7 +683,7 @@ proc read_diff {fd} {
 proc load_last_commit {} {
        global HEAD PARENT commit_type ui_comm
 
-       if {$commit_type eq {amend}} return
+       if {[string match amend* $commit_type]} return
        if {$commit_type ne {normal}} {
                error_popup "Can't amend a $commit_type commit."
                return
@@ -683,23 +707,24 @@ proc load_last_commit {} {
                return
        }
 
+       if {$parent_count > 1} {
+               error_popup {Can't amend a merge commit.}
+               return
+       }
+
        if {$parent_count == 0} {
-               set commit_type amend
-               set HEAD {}
+               set commit_type amend-initial
                set PARENT {}
-               rescan {set ui_status_value {Ready.}}
        } elseif {$parent_count == 1} {
                set commit_type amend
                set PARENT $parent
-               $ui_comm delete 0.0 end
-               $ui_comm insert end $msg
-               $ui_comm edit modified false
-               $ui_comm edit reset
-               rescan {set ui_status_value {Ready.}}
-       } else {
-               error_popup {You can't amend a merge commit.}
-               return
        }
+
+       $ui_comm delete 0.0 end
+       $ui_comm insert end $msg
+       $ui_comm edit modified false
+       $ui_comm edit reset
+       rescan {set ui_status_value {Ready.}}
 }
 
 proc commit_tree {} {
@@ -710,7 +735,7 @@ proc commit_tree {} {
        # -- Our in memory state should match the repository.
        #
        repository_state curHEAD cur_type
-       if {$commit_type eq {amend}
+       if {[string match amend* $commit_type]
                && $cur_type eq {normal}
                && $curHEAD eq $HEAD} {
        } elseif {$commit_type ne $cur_type || $HEAD ne $curHEAD} {
@@ -1261,7 +1286,7 @@ proc update_index {msg pathList after} {
 
 proc write_update_index {fd pathList totalCnt batch msg after} {
        global update_index_cp update_index_rsd ui_status_value
-       global file_states ui_fname_value
+       global file_states current_diff
 
        if {$update_index_cp >= $totalCnt} {
                close $fd
@@ -1296,7 +1321,7 @@ proc write_update_index {fd pathList totalCnt batch msg after} {
                puts -nonewline $fd $path
                puts -nonewline $fd "\0"
                display_file $path $new
-               if {$ui_fname_value eq $path} {
+               if {$current_diff eq $path} {
                        set update_index_rsd 1
                }
        }
@@ -1334,13 +1359,65 @@ proc load_all_remotes {} {
        set all_remotes [lsort -unique $all_remotes]
 }
 
-proc populate_remote_menu {m pfx op} {
-       global all_remotes
+proc populate_fetch_menu {m} {
+       global gitdir all_remotes repo_config
 
-       foreach remote $all_remotes {
-               $m add command -label "$pfx $remote..." \
-                       -command [list $op $remote] \
-                       -font font_ui
+       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 [file join $gitdir remotes $r] r]
+                               while {[gets $fd n] >= 0} {
+                                       if {[regexp {^Pull:[ \t]*([^:]+):} $n]} {
+                                               set enable 1
+                                               break
+                                       }
+                               }
+                               close $fd
+                       }
+               }
+
+               if {$enable} {
+                       $m add command \
+                               -label "Fetch from $r..." \
+                               -command [list fetch_from $r] \
+                               -font font_ui
+               }
+       }
+}
+
+proc populate_push_menu {m} {
+       global gitdir all_remotes repo_config
+
+       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 [file join $gitdir remotes $r] r]
+                               while {[gets $fd n] >= 0} {
+                                       if {[regexp {^Push:[ \t]*([^:]+):} $n]} {
+                                               set enable 1
+                                               break
+                                       }
+                               }
+                               close $fd
+                       }
+               }
+
+               if {$enable} {
+                       $m add command \
+                               -label "Push to $r..." \
+                               -command [list push_to $r] \
+                               -font font_ui
+               }
        }
 }
 
@@ -2003,6 +2080,129 @@ proc do_save_config {w} {
        destroy $w
 }
 
+proc do_windows_shortcut {} {
+       global gitdir appname argv0
+
+       set reponame [lindex [file split \
+               [file normalize [file dirname $gitdir]]] \
+               end]
+
+       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 \
+                                       --long-name \
+                                       /bin/sh]
+                               set me [exec cygpath \
+                                       --unix \
+                                       --absolute \
+                                       $argv0]
+                               set gd [exec cygpath \
+                                       --unix \
+                                       --absolute \
+                                       $gitdir]
+                               regsub -all ' $me "'\\''" me
+                               regsub -all ' $gd "'\\''" gd
+                               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"
+               }
+       }
+}
+
+proc do_macosx_app {} {
+       global gitdir appname argv0 env
+
+       set reponame [lindex [file split \
+               [file normalize [file dirname $gitdir]]] \
+               end]
+
+       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 PkgInfo] w]
+                               puts -nonewline $fd {APPL????}
+                               close $fd
+
+                               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
+
+                               file attributes $exe -permissions u+x,g+x,o+x
+                       } err]} {
+                       error_popup "Cannot write icon:\n\n$err"
+               }
+       }
+}
+
 proc toggle_or_diff {w x y} {
        global file_lists ui_index ui_other
        global last_clicked selected_paths
@@ -2169,6 +2369,18 @@ if {!$single_commit} {
        .mbar.project add command -label {Repack Database} \
                -command do_repack \
                -font font_ui
+
+       if {$tcl_platform(platform) eq {windows}} {
+               .mbar.project add command \
+                       -label {Create Desktop Icon} \
+                       -command do_windows_shortcut \
+                       -font font_ui
+       } elseif {[is_MacOSX]} {
+               .mbar.project add command \
+                       -label {Create Desktop Icon} \
+                       -command do_macosx_app \
+                       -font font_ui
+       }
 }
 .mbar.project add command -label Quit \
        -command do_quit \
@@ -2360,13 +2572,18 @@ label $ui_coml -text {Commit Message:} \
        -anchor w \
        -justify left \
        -font font_ui
-trace add variable commit_type write {uplevel #0 {
-       switch -glob $commit_type \
-       initial {$ui_coml conf -text {Initial Commit Message:}} \
-       amend   {$ui_coml conf -text {Amended Commit Message:}} \
-       merge   {$ui_coml conf -text {Merge Commit Message:}} \
-       *       {$ui_coml conf -text {Commit Message:}}
-}}
+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:}}
+       merge         {set txt {Merge Commit Message:}}
+       *             {set txt {Commit Message:}}
+       }
+       $ui_coml conf -text $txt
+}
+trace add variable commit_type write trace_commit_type
 text $ui_comm -background white -borderwidth 1 \
        -undo true \
        -maxundo 20 \
@@ -2384,71 +2601,105 @@ pack .vpane.lower.commarea.buffer -side left -fill y
 
 # -- Commit Message Buffer Context Menu
 #
-menu $ui_comm.ctxm -tearoff 0
-$ui_comm.ctxm add command -label "Cut" \
+set ctxm .vpane.lower.commarea.buffer.ctxm
+menu $ctxm -tearoff 0
+$ctxm add command \
+       -label {Cut} \
        -font font_ui \
-       -command "tk_textCut $ui_comm"
-$ui_comm.ctxm add command -label "Copy" \
+       -command {tk_textCut $ui_comm}
+$ctxm add command \
+       -label {Copy} \
        -font font_ui \
-       -command "tk_textCopy $ui_comm"
-$ui_comm.ctxm add command -label "Paste" \
+       -command {tk_textCopy $ui_comm}
+$ctxm add command \
+       -label {Paste} \
        -font font_ui \
-       -command "tk_textPaste $ui_comm"
-$ui_comm.ctxm add command -label "Delete" \
+       -command {tk_textPaste $ui_comm}
+$ctxm add command \
+       -label {Delete} \
        -font font_ui \
-       -command "$ui_comm delete sel.first sel.last"
-$ui_comm.ctxm add separator
-$ui_comm.ctxm add command -label "Select All" \
+       -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"
-$ui_comm.ctxm add command -label "Copy All" \
+       -command {$ui_comm tag add sel 0.0 end}
+$ctxm add command \
+       -label {Copy All} \
        -font font_ui \
-       -command "
+       -command {
                $ui_comm tag add sel 0.0 end
                tk_textCopy $ui_comm
                $ui_comm tag remove sel 0.0 end
-       "
-$ui_comm.ctxm add separator
-$ui_comm.ctxm add command -label "Sign Off" \
+       }
+$ctxm add separator
+$ctxm add command \
+       -label {Sign Off} \
        -font font_ui \
        -command do_signoff
-bind_button3 $ui_comm "tk_popup $ui_comm.ctxm %X %Y"
+bind_button3 $ui_comm "tk_popup $ctxm %X %Y"
 
 # -- Diff Header
-set ui_fname_value {}
-set ui_fstatus_value {}
+set current_diff {}
+set diff_actions [list]
+proc current_diff_trace {varname args} {
+       global current_diff diff_actions file_states
+       if {$current_diff eq {}} {
+               set s {}
+               set f {}
+               set p {}
+               set o disabled
+       } else {
+               set p $current_diff
+               set s [mapdesc [lindex $file_states($p) 0] $p]
+               set f {File:}
+               set p [escape_path $p]
+               set o normal
+       }
+
+       .vpane.lower.diff.header.status configure -text $s
+       .vpane.lower.diff.header.file configure -text $f
+       .vpane.lower.diff.header.path configure -text $p
+       foreach w $diff_actions {
+               uplevel #0 $w $o
+       }
+}
+trace add variable current_diff write current_diff_trace
+
 frame .vpane.lower.diff.header -background orange
-label .vpane.lower.diff.header.l4 \
-       -textvariable ui_fstatus_value \
+label .vpane.lower.diff.header.status \
        -background orange \
        -width $max_status_desc \
        -anchor w \
        -justify left \
        -font font_ui
-label .vpane.lower.diff.header.l1 -text {File:} \
+label .vpane.lower.diff.header.file \
        -background orange \
+       -anchor w \
+       -justify left \
        -font font_ui
-set ui_fname .vpane.lower.diff.header.l2
-label $ui_fname \
-       -textvariable ui_fname_value \
+label .vpane.lower.diff.header.path \
        -background orange \
        -anchor w \
        -justify left \
        -font font_ui
-menu $ui_fname.ctxm -tearoff 0
-$ui_fname.ctxm add command -label "Copy" \
+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 \
        -command {
                clipboard clear
                clipboard append \
                        -format STRING \
                        -type STRING \
-                       -- $ui_fname_value
+                       -- $current_diff
        }
-bind_button3 $ui_fname "tk_popup $ui_fname.ctxm %X %Y"
-pack .vpane.lower.diff.header.l4 -side left
-pack .vpane.lower.diff.header.l1 -side left
-pack $ui_fname -fill x
+lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
+bind_button3 .vpane.lower.diff.header.path "tk_popup $ctxm %X %Y"
 
 # -- Diff Body
 frame .vpane.lower.diff.body
@@ -2478,48 +2729,63 @@ $ui_diff tag conf bold -font font_diffbold
 
 # -- Diff Body Context Menu
 #
-menu $ui_diff.ctxm -tearoff 0
-$ui_diff.ctxm add command -label "Copy" \
+set ctxm .vpane.lower.diff.body.ctxm
+menu $ctxm -tearoff 0
+$ctxm add command \
+       -label {Copy} \
        -font font_ui \
-       -command "tk_textCopy $ui_diff"
-$ui_diff.ctxm add command -label "Select All" \
+       -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"
-$ui_diff.ctxm add command -label "Copy All" \
+       -command {$ui_diff tag add sel 0.0 end}
+lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
+$ctxm add command \
+       -label {Copy All} \
        -font font_ui \
-       -command "
+       -command {
                $ui_diff tag add sel 0.0 end
                tk_textCopy $ui_diff
                $ui_diff tag remove sel 0.0 end
-       "
-$ui_diff.ctxm add separator
-$ui_diff.ctxm add command -label "Decrease Font Size" \
+       }
+lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
+$ctxm add separator
+$ctxm add command \
+       -label {Decrease Font Size} \
        -font font_ui \
        -command {incr_font_size font_diff -1}
-$ui_diff.ctxm add command -label "Increase Font Size" \
+lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
+$ctxm add command \
+       -label {Increase Font Size} \
        -font font_ui \
        -command {incr_font_size font_diff 1}
-$ui_diff.ctxm add separator
-$ui_diff.ctxm add command -label "Show Less Context" \
+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 {$ui_fname_value ne {}
-               && $repo_config(gui.diffcontext) >= 2} {
+       -command {if {$repo_config(gui.diffcontext) >= 2} {
                incr repo_config(gui.diffcontext) -1
                reshow_diff
        }}
-$ui_diff.ctxm add command -label "Show More Context" \
+lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
+$ctxm add command \
+       -label {Show More Context} \
        -font font_ui \
-       -command {if {$ui_fname_value ne {}} {
+       -command {
                incr repo_config(gui.diffcontext)
                reshow_diff
-       }}
-$ui_diff.ctxm add separator
-$ui_diff.ctxm add command -label {Options...} \
+       }
+lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
+$ctxm add separator
+$ctxm add command -label {Options...} \
        -font font_ui \
        -command do_options
-bind_button3 $ui_diff "tk_popup $ui_diff.ctxm %X %Y"
+bind_button3 $ui_diff "tk_popup $ctxm %X %Y"
 
 # -- Status Bar
+#
 set ui_status_value {Initializing...}
 label .status -textvariable ui_status_value \
        -anchor w \
@@ -2530,6 +2796,7 @@ label .status -textvariable ui_status_value \
 pack .status -anchor w -side bottom -fill x
 
 # -- Load geometry
+#
 catch {
 set gm $repo_config(gui.geometry)
 wm geometry . [lindex $gm 0]
@@ -2543,6 +2810,7 @@ unset gm
 }
 
 # -- Key Bindings
+#
 bind $ui_comm <$M1B-Key-Return> {do_commit;break}
 bind $ui_comm <$M1B-Key-i> {do_include_all;break}
 bind $ui_comm <$M1B-Key-I> {do_include_all;break}
@@ -2590,13 +2858,14 @@ unset i
 
 set file_lists($ui_index) [list]
 set file_lists($ui_other) [list]
+set current_diff {}
 
 wm title . "$appname ([file normalize [file dirname $gitdir]])"
 focus -force $ui_comm
 if {!$single_commit} {
        load_all_remotes
-       populate_remote_menu .mbar.fetch From fetch_from
-       populate_remote_menu .mbar.push To push_to
+       populate_fetch_menu .mbar.fetch
        populate_pull_menu .mbar.pull
+       populate_push_menu .mbar.push
 }
 after 1 do_rescan