Code

git-gui: View blame from the command line.
[git.git] / git-gui.sh
index 8db878966263f5b26c6f31ff2b0261b742990fbf..66d85dc6d06cffae2c5e13068886ce50042cbef1 100755 (executable)
@@ -93,6 +93,22 @@ proc is_Cygwin {} {
        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
+}
+
 ######################################################################
 ##
 ## config
@@ -303,11 +319,6 @@ set _reponame [lindex [file split \
        [file normalize [file dirname $_gitdir]]] \
        end]
 
-set single_commit 0
-if {[appname] eq {git-citool}} {
-       set single_commit 1
-}
-
 ######################################################################
 ##
 ## task management
@@ -400,7 +411,7 @@ proc rescan {after {honor_trustmtime 1}} {
        global HEAD PARENT MERGE_HEAD commit_type
        global ui_index ui_workdir ui_status_value ui_comm
        global rescan_active file_states
-       global repo_config single_commit
+       global repo_config
 
        if {$rescan_active > 0 || ![lock_index read]} return
 
@@ -427,7 +438,7 @@ proc rescan {after {honor_trustmtime 1}} {
                $ui_comm edit modified false
        }
 
-       if {!$single_commit} {
+       if {[is_enabled branch]} {
                load_all_heads
                populate_branch_menu
        }
@@ -1181,7 +1192,7 @@ proc commit_writetree {curHEAD msg} {
 
 proc commit_committree {fd_wt curHEAD msg} {
        global HEAD PARENT MERGE_HEAD commit_type
-       global single_commit all_heads current_branch
+       global all_heads current_branch
        global ui_status_value ui_comm selected_commit_type
        global file_states selected_paths rescan_active
        global repo_config
@@ -1286,7 +1297,7 @@ proc commit_committree {fd_wt curHEAD msg} {
        $ui_comm edit reset
        $ui_comm edit modified false
 
-       if {$single_commit} do_quit
+       if {[is_enabled singlecommit]} do_quit
 
        # -- Update in memory status
        #
@@ -1381,6 +1392,7 @@ proc mapdesc {state path} {
 }
 
 proc escape_path {path} {
+       regsub -all {\\} $path "\\\\" path
        regsub -all "\n" $path "\\n" path
        return $path
 }
@@ -3214,12 +3226,17 @@ proc read_ls_tree {fd w} {
 proc show_blame {commit path} {
        global next_browser_id blame_status blame_data
 
-       set w .browser[incr next_browser_id]
+       if {[winfo ismapped .]} {
+               set w .browser[incr next_browser_id]
+               set tl $w
+               toplevel $w
+       } else {
+               set w {}
+               set tl .
+       }
        set blame_status($w) {Loading current file content...}
        set texts [list]
 
-       toplevel $w
-
        label $w.path -text "$commit:$path" \
                -anchor w \
                -justify left \
@@ -3377,12 +3394,12 @@ proc show_blame {commit path} {
 
        set blame_data($w,colors) {}
 
-       bind $w <Visibility> "focus $w"
-       bind $w <Destroy> "
-               array unset blame_status $w
+       bind $tl <Visibility> "focus $tl"
+       bind $tl <Destroy> "
+               array unset blame_status {$w}
                array unset blame_data $w,*
        "
-       wm title $w "[appname] ([reponame]): File Viewer"
+       wm title $tl "[appname] ([reponame]): File Viewer"
 
        set blame_data($w,total_lines) 0
        set cmd [list git cat-file blob "$commit:$path"]
@@ -3420,7 +3437,9 @@ proc read_blame_catfile {fd w commit path texts w_lno w_file} {
                lappend cmd $commit -- $path
                set fd [open "| $cmd" r]
                fconfigure $fd -blocking 0 -translation lf -encoding binary
-               fileevent $fd readable "read_blame_incremental $fd $w $texts"
+               set handler [list read_blame_incremental $fd $w]
+               append handler " $texts"
+               fileevent $fd readable $handler
        }
 }
 
@@ -4104,34 +4123,36 @@ proc do_quit {} {
        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]]
-       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
+       if {[winfo exists $ui_comm]} {
+               # -- Stash our current commit buffer.
+               #
+               set save [gitdir GITGUI_MSG]
+               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}
                }
-       } else {
-               catch {file delete $save}
-       }
 
-       # -- 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] 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}
+               # -- 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] 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 .
@@ -4892,20 +4913,48 @@ set font_descs {
 load_config 0
 apply_config
 
+######################################################################
+##
+## feature option selection
+
+enable_option multicommit
+enable_option branch
+enable_option transport
+
+if {[appname] eq {git-citool}} {
+       enable_option singlecommit
+
+       disable_option multicommit
+       disable_option branch
+       disable_option transport
+}
+
+switch -- [lindex $argv 0] {
+blame {
+       disable_option multicommit
+       disable_option branch
+       disable_option transport
+}
+}
+
 ######################################################################
 ##
 ## ui construction
 
+set ui_comm {}
+
 # -- Menu Bar
 #
 menu .mbar -tearoff 0
 .mbar add cascade -label Repository -menu .mbar.repository
 .mbar add cascade -label Edit -menu .mbar.edit
-if {!$single_commit} {
+if {[is_enabled branch]} {
        .mbar add cascade -label Branch -menu .mbar.branch
 }
-.mbar add cascade -label Commit -menu .mbar.commit
-if {!$single_commit} {
+if {[is_enabled multicommit] || [is_enabled singlecommit]} {
+       .mbar add cascade -label Commit -menu .mbar.commit
+}
+if {[is_enabled transport]} {
        .mbar add cascade -label Merge -menu .mbar.merge
        .mbar add cascade -label Fetch -menu .mbar.fetch
        .mbar add cascade -label Push -menu .mbar.push
@@ -4920,19 +4969,21 @@ menu .mbar.repository
        -label {Browse Current Branch} \
        -command {new_browser $current_branch} \
        -font font_ui
+trace add variable current_branch write ".mbar.repository entryconf [.mbar.repository index last] -label \"Browse \$current_branch\" ;#"
 .mbar.repository add separator
 
 .mbar.repository add command \
        -label {Visualize Current Branch} \
-       -command {do_gitk {}} \
+       -command {do_gitk $current_branch} \
        -font font_ui
+trace add variable current_branch write ".mbar.repository entryconf [.mbar.repository index last] -label \"Visualize \$current_branch\" ;#"
 .mbar.repository add command \
        -label {Visualize All Branches} \
-       -command {do_gitk {--all}} \
+       -command {do_gitk --all} \
        -font font_ui
 .mbar.repository add separator
 
-if {!$single_commit} {
+if {[is_enabled multicommit]} {
        .mbar.repository add command -label {Database Statistics} \
                -command do_stats \
                -font font_ui
@@ -5006,7 +5057,7 @@ menu .mbar.edit
 
 # -- Branch Menu
 #
-if {!$single_commit} {
+if {[is_enabled branch]} {
        menu .mbar.branch
 
        .mbar.branch add command -label {Create...} \
@@ -5025,73 +5076,75 @@ if {!$single_commit} {
 
 # -- Commit Menu
 #
-menu .mbar.commit
-
-.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]
+if {[is_enabled multicommit] || [is_enabled singlecommit]} {
+       menu .mbar.commit
+
+       .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 {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 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 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 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 {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 {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 {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 {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 {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 {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 {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 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 {Sign Off} \
-       -command do_signoff \
-       -accelerator $M1T-S \
-       -font font_ui
+       .mbar.commit add command -label {Sign Off} \
+               -command do_signoff \
+               -accelerator $M1T-S \
+               -font font_ui
 
-.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]
+       .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]
+}
 
 if {[is_MacOSX]} {
        # -- Apple Menu (Mac OS X only)
@@ -5194,6 +5247,34 @@ if {$browser ne {}} {
 }
 unset browser doc_path doc_url
 
+# -- Standard bindings
+#
+bind .   <Destroy> 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]}
+
+# -- Not a normal commit type invocation?  Do that instead!
+#
+switch -- [lindex $argv 0] {
+blame {
+       if {[llength $argv] == 3} {
+               set current_branch [lindex $argv 1]
+               show_blame $current_branch [lindex $argv 2]
+               return
+       } else {
+               puts stderr "usage: $argv0 blame commit path"
+               exit 1
+       }
+}
+{} {}
+default {
+       puts stderr "usage: $argv0 \[{blame}\]"
+       exit 1
+}
+}
+
 # -- Branch Control
 #
 frame .branch \
@@ -5213,7 +5294,7 @@ pack .branch.l1 -side left
 pack .branch.cb -side left -fill x
 pack .branch -side top -fill x
 
-if {!$single_commit} {
+if {[is_enabled branch]} {
        menu .mbar.merge
        .mbar.merge add command -label {Local Merge...} \
                -command do_local_merge \
@@ -5685,12 +5766,11 @@ 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 <Button-1>   {focus %W}
 
-if {!$single_commit} {
+if {[is_enabled branch]} {
        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
@@ -5699,10 +5779,6 @@ bind .   <$M1B-Key-S> do_signoff
 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"
@@ -5782,7 +5858,7 @@ user.email settings into your personal
 
 # -- Only initialize complex UI if we are going to stay running.
 #
-if {!$single_commit} {
+if {[is_enabled transport]} {
        load_all_remotes
        load_all_heads
 
@@ -5793,7 +5869,7 @@ if {!$single_commit} {
 
 # -- Only suggest a gc run if we are going to stay running.
 #
-if {!$single_commit} {
+if {[is_enabled multicommit]} {
        set object_limit 2000
        if {[is_Windows]} {set object_limit 200}
        regexp {^([0-9]+) objects,} [exec git count-objects] _junk objects_current