Code

git-gui: display summary when showing diff of a submodule
[git.git] / git-gui.sh
index 078636f23f31a2466c479fda8803a953173eb9e3..3c0ce2602987c5ca04acbde27a021a0009917d6b 100755 (executable)
@@ -122,6 +122,7 @@ unset oguimsg
 set _appname {Git Gui}
 set _gitdir {}
 set _gitexec {}
+set _githtmldir {}
 set _reponame {}
 set _iscygwin {}
 set _search_path {}
@@ -168,6 +169,28 @@ proc gitexec {args} {
        return [eval [list file join $_gitexec] $args]
 }
 
+proc githtmldir {args} {
+       global _githtmldir
+       if {$_githtmldir eq {}} {
+               if {[catch {set _githtmldir [git --html-path]}]} {
+                       # Git not installed or option not yet supported
+                       return {}
+               }
+               if {[is_Cygwin]} {
+                       set _githtmldir [exec cygpath \
+                               --windows \
+                               --absolute \
+                               $_githtmldir]
+               } else {
+                       set _githtmldir [file normalize $_githtmldir]
+               }
+       }
+       if {$args eq {}} {
+               return $_githtmldir
+       }
+       return [eval [list file join $_githtmldir] $args]
+}
+
 proc reponame {} {
        return $::_reponame
 }
@@ -591,6 +614,34 @@ bind . <Visibility> {
 
 if {[is_Windows]} {
        wm iconbitmap . -default $oguilib/git-gui.ico
+       set ::tk::AlwaysShowSelection 1
+
+       # Spoof an X11 display for SSH
+       if {![info exists env(DISPLAY)]} {
+               set env(DISPLAY) :9999
+       }
+} else {
+       catch {
+               image create photo gitlogo -width 16 -height 16
+
+               gitlogo put #33CC33 -to  7  0  9  2
+               gitlogo put #33CC33 -to  4  2 12  4
+               gitlogo put #33CC33 -to  7  4  9  6
+               gitlogo put #CC3333 -to  4  6 12  8
+               gitlogo put gray26  -to  4  9  6 10
+               gitlogo put gray26  -to  3 10  6 12
+               gitlogo put gray26  -to  8  9 13 11
+               gitlogo put gray26  -to  8 11 10 12
+               gitlogo put gray26  -to 11 11 13 14
+               gitlogo put gray26  -to  3 12  5 14
+               gitlogo put gray26  -to  5 13
+               gitlogo put gray26  -to 10 13
+               gitlogo put gray26  -to  4 14 12 15
+               gitlogo put gray26  -to  5 15 11 16
+               gitlogo redither
+
+               wm iconphoto . -default gitlogo
+       }
 }
 
 ######################################################################
@@ -612,10 +663,13 @@ font create font_diffbold
 font create font_diffitalic
 
 foreach class {Button Checkbutton Entry Label
-               Labelframe Listbox Menu Message
+               Labelframe Listbox Message
                Radiobutton Spinbox Text} {
        option add *$class.font font_ui
 }
+if {![is_MacOSX]} {
+       option add *Menu.font font_ui
+}
 unset class
 
 if {[is_Windows] || [is_MacOSX]} {
@@ -671,7 +725,7 @@ proc apply_config {} {
 
 set default_config(branch.autosetupmerge) true
 set default_config(merge.tool) {}
-set default_config(merge.keepbackup) true
+set default_config(mergetool.keepbackup) true
 set default_config(merge.diffstat) true
 set default_config(merge.summary) false
 set default_config(merge.verbosity) 2
@@ -741,9 +795,9 @@ if {![regsub {^git version } $_git_version {} _git_version]} {
 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 {\.[a-zA-Z]+\.?[0-9]+$} $_git_version {} _git_version
 regsub {\.GIT$} $_git_version {} _git_version
-regsub {\.[a-zA-Z]+\.[0-9]+$} $_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 .}
@@ -912,19 +966,25 @@ git-version proc _parse_config {arr_name args} {
 }
 
 proc load_config {include_global} {
-       global repo_config global_config default_config
+       global repo_config global_config system_config default_config
 
        if {$include_global} {
+               _parse_config system_config --system
                _parse_config global_config --global
        }
        _parse_config repo_config
 
        foreach name [array names default_config] {
+               if {[catch {set v $system_config($name)}]} {
+                       set system_config($name) $default_config($name)
+               }
+       }
+       foreach name [array names system_config] {
                if {[catch {set v $global_config($name)}]} {
-                       set global_config($name) $default_config($name)
+                       set global_config($name) $system_config($name)
                }
                if {[catch {set v $repo_config($name)}]} {
-                       set repo_config($name) $default_config($name)
+                       set repo_config($name) $system_config($name)
                }
        }
 }
@@ -991,10 +1051,22 @@ citool {
 }
 }
 
+######################################################################
+##
+## execution environment
+
+set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
+
+# Suggest our implementation of askpass, if none is set
+if {![info exists env(SSH_ASKPASS)]} {
+       set env(SSH_ASKPASS) [gitexec git-gui--askpass]
+}
+
 ######################################################################
 ##
 ## repository setup
 
+set picked 0
 if {[catch {
                set _gitdir $env(GIT_DIR)
                set _prefix {}
@@ -1006,6 +1078,7 @@ if {[catch {
        load_config 1
        apply_config
        choose_repository::pick
+       set picked 1
 }
 if {![file isdirectory $_gitdir] && [is_Cygwin]} {
        catch {set _gitdir [exec cygpath --windows $_gitdir]}
@@ -1061,6 +1134,7 @@ set current_diff_path {}
 set is_3way_diff 0
 set is_conflict_diff 0
 set selected_commit_type new
+set diff_empty_count 0
 
 set nullid "0000000000000000000000000000000000000000"
 set nullid2 "0000000000000000000000000000000000000001"
@@ -1444,10 +1518,8 @@ proc rescan_done {fd buf after} {
        prune_selection
        unlock_index
        display_all_files
-       if {$current_diff_path ne {}} reshow_diff
-       if {$current_diff_path eq {}} select_first_diff
-
-       uplevel #0 $after
+       if {$current_diff_path ne {}} { reshow_diff $after }
+       if {$current_diff_path eq {}} { select_first_diff $after }
 }
 
 proc prune_selection {} {
@@ -1869,6 +1941,19 @@ proc do_gitk {revs} {
        }
 }
 
+proc do_explore {} {
+       set explorer {}
+       if {[is_Cygwin] || [is_Windows]} {
+               set explorer "explorer.exe"
+       } elseif {[is_MacOSX]} {
+               set explorer "open"
+       } else {
+               # freedesktop.org-conforming system is our best shot
+               set explorer "xdg-open"
+       }
+       eval exec $explorer [list [file nativename [file dirname [gitdir]]]] &
+}
+
 set is_quitting 0
 set ret_code    1
 
@@ -1946,16 +2031,16 @@ proc do_rescan {} {
 }
 
 proc ui_do_rescan {} {
-       rescan {force_first_diff; ui_ready}
+       rescan {force_first_diff ui_ready}
 }
 
 proc do_commit {} {
        commit_tree
 }
 
-proc next_diff {} {
+proc next_diff {{after {}}} {
        global next_diff_p next_diff_w next_diff_i
-       show_diff $next_diff_p $next_diff_w {}
+       show_diff $next_diff_p $next_diff_w {} {} $after
 }
 
 proc find_anchor_pos {lst name} {
@@ -2040,25 +2125,42 @@ proc next_diff_after_action {w path {lno {}} {mmask {}}} {
        }
 }
 
-proc select_first_diff {} {
+proc select_first_diff {after} {
        global ui_workdir
 
        if {[find_next_diff $ui_workdir {} 1 {^_?U}] ||
            [find_next_diff $ui_workdir {} 1 {[^O]$}]} {
-               next_diff
+               next_diff $after
+       } else {
+               uplevel #0 $after
        }
 }
 
-proc force_first_diff {} {
-       global current_diff_path
+proc force_first_diff {after} {
+       global ui_workdir current_diff_path file_states
 
        if {[info exists file_states($current_diff_path)]} {
                set state [lindex $file_states($current_diff_path) 0]
+       } else {
+               set state {OO}
+       }
 
-               if {[string index $state 1] ne {O}} return
+       set reselect 0
+       if {[string first {U} $state] >= 0} {
+               # Already a conflict, do nothing
+       } elseif {[find_next_diff $ui_workdir $current_diff_path {} {^_?U}]} {
+               set reselect 1
+       } elseif {[string index $state 1] ne {O}} {
+               # Already a diff & no conflicts, do nothing
+       } elseif {[find_next_diff $ui_workdir $current_diff_path {} {[^O]$}]} {
+               set reselect 1
        }
 
-       select_first_diff
+       if {$reselect} {
+               next_diff $after
+       } else {
+               uplevel #0 $after
+       }
 }
 
 proc toggle_or_diff {w x y} {
@@ -2202,6 +2304,12 @@ set ui_comm {}
 # -- Menu Bar
 #
 menu .mbar -tearoff 0
+if {[is_MacOSX]} {
+       # -- Apple Menu (Mac OS X only)
+       #
+       .mbar add cascade -label Apple -menu .mbar.apple
+       menu .mbar.apple
+}
 .mbar add cascade -label [mc Repository] -menu .mbar.repository
 .mbar add cascade -label [mc Edit] -menu .mbar.edit
 if {[is_enabled branch]} {
@@ -2214,12 +2322,19 @@ 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
+if {[is_enabled multicommit] || [is_enabled singlecommit]} {
+       .mbar add cascade -label [mc Tools] -menu .mbar.tools
+}
 
 # -- Repository Menu
 #
 menu .mbar.repository
 
+.mbar.repository add command \
+       -label [mc "Explore Working Copy"] \
+       -command {do_explore}
+.mbar.repository add separator
+
 .mbar.repository add command \
        -label [mc "Browse Current Branch's Files"] \
        -command {browser::new $current_branch}
@@ -2448,6 +2563,10 @@ if {[is_enabled branch]} {
 if {[is_enabled transport]} {
        menu .mbar.remote
 
+       .mbar.remote add command \
+               -label [mc "Add..."] \
+               -command remote_add::dialog \
+               -accelerator $M1T-A
        .mbar.remote add command \
                -label [mc "Push..."] \
                -command do_push_anywhere \
@@ -2458,19 +2577,7 @@ if {[is_enabled transport]} {
 }
 
 if {[is_MacOSX]} {
-       # -- Apple Menu (Mac OS X only)
-       #
-       .mbar add cascade -label Apple -menu .mbar.apple
-       menu .mbar.apple
-
-       .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 \
-               -accelerator $M1T-,
-       bind . <$M1B-,> do_options
+       proc ::tk::mac::ShowPreferences {} {do_options}
 } else {
        # -- Edit Menu
        #
@@ -2479,39 +2586,41 @@ if {[is_MacOSX]} {
                -command do_options
 }
 
+# -- Tools Menu
+#
+if {[is_enabled multicommit] || [is_enabled singlecommit]} {
+       set tools_menubar .mbar.tools
+       menu $tools_menubar
+       $tools_menubar add separator
+       $tools_menubar add command -label [mc "Add..."] -command tools_add::dialog
+       $tools_menubar add command -label [mc "Remove..."] -command tools_remove::dialog
+       set tools_tailcnt 3
+       if {[array names repo_config guitool.*.cmd] ne {}} {
+               tools_populate_all
+       }
+}
+
 # -- Help Menu
 #
 .mbar add cascade -label [mc Help] -menu .mbar.help
 menu .mbar.help
 
-if {![is_MacOSX]} {
+if {[is_MacOSX]} {
+       .mbar.apple add command -label [mc "About %s" [appname]] \
+               -command do_about
+       .mbar.apple add separator
+} else {
        .mbar.help add command -label [mc "About %s" [appname]] \
                -command do_about
 }
+. configure -menu .mbar
 
-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]
-}
+set doc_path [githtmldir]
+if {$doc_path ne {}} {
+       set doc_path [file join $doc_path index.html]
 
-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
+       if {[is_Cygwin]} {
+               set doc_path [exec cygpath --mixed $doc_path]
        }
 }
 
@@ -2521,11 +2630,17 @@ if {[file isfile $doc_path]} {
        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 &]
+proc start_browser {url} {
+       git "web--browse" $url
 }
-unset browser doc_path doc_url
+
+.mbar.help add command -label [mc "Online Documentation"] \
+       -command [list start_browser $doc_url]
+
+.mbar.help add command -label [mc "Show SSH Key"] \
+       -command do_ssh_key
+
+unset doc_path doc_url
 
 # -- Standard bindings
 #
@@ -2541,6 +2656,20 @@ proc usage {} {
        exit 1
 }
 
+proc normalize_relpath {path} {
+       set elements {}
+       foreach item [file split $path] {
+               if {$item eq {.}} continue
+               if {$item eq {..} && [llength $elements] > 0
+                   && [lindex $elements end] ne {..}} {
+                       set elements [lrange $elements 0 end-1]
+                       continue
+               }
+               lappend elements $item
+       }
+       return [eval file join $elements]
+}
+
 # -- Not a normal commit type invocation?  Do that instead!
 #
 switch -- $subcommand {
@@ -2559,7 +2688,7 @@ blame {
        foreach a $argv {
                if {$is_path || [file exists $_prefix$a]} {
                        if {$path ne {}} usage
-                       set path $_prefix$a
+                       set path [normalize_relpath $_prefix$a]
                        break
                } elseif {$a eq {--}} {
                        if {$path ne {}} {
@@ -2582,7 +2711,7 @@ blame {
        unset is_path
 
        if {$head ne {} && $path eq {}} {
-               set path $_prefix$head
+               set path [normalize_relpath $_prefix$head]
                set head {}
        }
 
@@ -2841,7 +2970,7 @@ $ctxm add command \
        -command {tk_textPaste $ui_comm}
 $ctxm add command \
        -label [mc Delete] \
-       -command {$ui_comm delete sel.first sel.last}
+       -command {catch {$ui_comm delete sel.first sel.last}}
 $ctxm add separator
 $ctxm add command \
        -label [mc "Select All"] \
@@ -3083,7 +3212,7 @@ proc popup_diff_menu {ctxm ctxmmg x y X Y} {
                        set l [mc "Stage Hunk For Commit"]
                        set t [mc "Stage Line For Commit"]
                }
-               if {$::is_3way_diff
+               if {$::is_3way_diff || $::is_submodule_diff
                        || $current_diff_path eq {}
                        || {__} eq $state
                        || {_O} eq $state
@@ -3226,7 +3355,6 @@ by %s:
                {^GIT_PAGER$} -
                {^GIT_TRACE$} -
                {^GIT_CONFIG$} -
-               {^GIT_CONFIG_LOCAL$} -
                {^GIT_(AUTHOR|COMMITTER)_DATE$} {
                        append msg " - $name\n"
                        incr ignored_env
@@ -3263,8 +3391,7 @@ if {[is_enabled transport]} {
        load_all_remotes
 
        set n [.mbar.remote index end]
-       populate_push_menu
-       populate_fetch_menu
+       populate_remotes_menu
        set n [expr {[.mbar.remote index end] - $n}]
        if {$n > 0} {
                if {[.mbar.remote type 0] eq "tearoff"} { incr n }
@@ -3371,3 +3498,6 @@ if {[is_enabled multicommit]} {
 if {[is_enabled retcode]} {
        bind . <Destroy> {+terminate_me %W}
 }
+if {$picked && [is_config_true gui.autoexplore]} {
+       do_explore
+}