2 # Tcl ignores the next line -*- tcl -*- \
3 if test "z$*" = zversion \
4 ||
test "z$*" = z--version
; \
6 echo 'git-gui version @@GITGUI_VERSION@@'; \
11 set appvers
{@@GITGUI_VERSION@@
}
13 Copyright ©
2006, 2007 Shawn Pearce
, et. al.
15 This program is free software
; you can redistribute it and
/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation
; either version
2 of the License
, or
18 (at your option
) any later version.
20 This program is distributed
in the hope that it will be useful
,
21 but WITHOUT ANY WARRANTY
; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License
for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program
; if not
, write to the Free Software
27 Foundation
, Inc.
, 59 Temple Place
, Suite
330, Boston
, MA
02111-1307 USA
}
29 ######################################################################
31 ## Tcl/Tk sanity check
33 if {[catch
{package require Tcl
8.4} err
]
34 ||
[catch
{package require Tk
8.4} err
]
40 -title "git-gui: fatal error" \
45 ######################################################################
47 ## enable verbose loading?
49 if {![catch
{set _verbose
$env(GITGUI_VERBOSE
)}]} {
51 rename auto_load real__auto_load
52 proc auto_load
{name args
} {
53 puts stderr
"auto_load $name"
54 return [uplevel
1 real__auto_load
$name $args]
56 rename
source real__source
58 puts stderr
"source $name"
59 uplevel
1 real__source
$name
63 ######################################################################
65 ## configure our library
67 set oguilib
{@@GITGUI_LIBDIR@@
}
68 set oguirel
{@@GITGUI_RELATIVE@@
}
69 if {$oguirel eq
{1}} {
70 set oguilib
[file dirname [file dirname [file normalize
$argv0]]]
71 set oguilib
[file join $oguilib share git-gui lib
]
72 } elseif
{[string match @@
* $oguirel]} {
73 set oguilib
[file join [file dirname [file normalize
$argv0]] lib
]
76 set idx
[file join $oguilib tclIndex
]
77 if {[catch
{set fd
[open
$idx r
]} err
]} {
82 -title "git-gui: fatal error" \
86 if {[gets
$fd] eq
{# Autogenerated by git-gui Makefile}} {
88 while {[gets
$fd n
] >= 0} {
89 if {$n ne
{} && ![string match
#* $n]} {
101 if {[lsearch
-exact $loaded $p] >= 0} continue
102 source [file join $oguilib $p]
107 set auto_path
[concat
[list
$oguilib] $auto_path]
109 unset -nocomplain oguirel idx fd
111 ######################################################################
115 set _appname
[lindex
[file split $argv0] end
]
132 return [eval [list
file join $_gitdir] $args]
135 proc gitexec
{args
} {
137 if {$_gitexec eq
{}} {
138 if {[catch
{set _gitexec
[git
--exec-path]} err
]} {
139 error
"Git not installed?\n\n$err"
142 set _gitexec
[exec cygpath \
147 set _gitexec
[file normalize
$_gitexec]
153 return [eval [list
file join $_gitexec] $args]
162 global tcl_platform tk_library
163 if {[tk windowingsystem
] eq
{aqua
}} {
171 if {$tcl_platform(platform
) eq
{windows
}} {
178 global tcl_platform _iscygwin
179 if {$_iscygwin eq
{}} {
180 if {$tcl_platform(platform
) eq
{windows
}} {
181 if {[catch
{set p
[exec cygpath
--windir]} err
]} {
193 proc is_enabled
{option
} {
194 global enabled_options
195 if {[catch
{set on
$enabled_options($option)}]} {return 0}
199 proc enable_option
{option
} {
200 global enabled_options
201 set enabled_options
($option) 1
204 proc disable_option
{option
} {
205 global enabled_options
206 set enabled_options
($option) 0
209 ######################################################################
213 proc is_many_config
{name
} {
214 switch
-glob -- $name {
223 proc is_config_true
{name
} {
225 if {[catch
{set v
$repo_config($name)}]} {
227 } elseif
{$v eq
{true
} ||
$v eq
{1} ||
$v eq
{yes}} {
234 proc get_config
{name
} {
236 if {[catch
{set v
$repo_config($name)}]} {
243 proc load_config
{include_global
} {
244 global repo_config global_config default_config
246 array
unset global_config
247 if {$include_global} {
249 set fd_rc
[git_read config
--global --list]
250 while {[gets
$fd_rc line
] >= 0} {
251 if {[regexp
{^
([^
=]+)=(.
*)$
} $line line name value
]} {
252 if {[is_many_config
$name]} {
253 lappend global_config
($name) $value
255 set global_config
($name) $value
263 array
unset repo_config
265 set fd_rc
[git_read config
--list]
266 while {[gets
$fd_rc line
] >= 0} {
267 if {[regexp
{^
([^
=]+)=(.
*)$
} $line line name value
]} {
268 if {[is_many_config
$name]} {
269 lappend repo_config
($name) $value
271 set repo_config
($name) $value
278 foreach name
[array names default_config
] {
279 if {[catch
{set v
$global_config($name)}]} {
280 set global_config
($name) $default_config($name)
282 if {[catch
{set v
$repo_config($name)}]} {
283 set repo_config
($name) $default_config($name)
288 ######################################################################
292 proc _git_cmd
{name
} {
295 if {[catch
{set v
$_git_cmd_path($name)}]} {
299 --exec-path { return [list $
::_git
$name] }
302 set p
[gitexec git-
$name$
::_search_exe
]
303 if {[file exists
$p]} {
305 } elseif
{[is_Cygwin
]} {
306 # On Cygwin git is a proper Cygwin program and knows
307 # how to properly restart the Cygwin environment and
308 # spawn its non-.exe support program.
310 set v
[list $
::_git
$name]
311 } elseif
{[is_Windows
]
313 && [file exists
[gitexec git-
$name]]} {
314 # Assume this is a UNIX shell script. We can
315 # probably execute it through a Bourne shell.
317 set v
[list $
::_sh
[gitexec git-
$name]]
319 # Assume it is builtin to git somehow and we
320 # aren't actually able to see a file for it.
322 set v
[list $
::_git
$name]
324 set _git_cmd_path
($name) $v
330 global env _search_exe _search_path
332 if {$_search_path eq
{}} {
334 set _search_path
[split [exec cygpath \
340 } elseif
{[is_Windows
]} {
341 set _search_path
[split $env(PATH
) {;}]
344 set _search_path
[split $env(PATH
) :]
349 foreach p
$_search_path {
350 set p
[file join $p $what$_search_exe]
351 if {[file exists
$p]} {
352 return [file normalize
$p]
362 switch
-- [lindex
$args 0] {
376 set args
[lrange
$args 1 end
]
379 set cmdp
[_git_cmd
[lindex
$args 0]]
380 set args
[lrange
$args 1 end
]
382 return [eval $opt $cmdp $args]
385 proc git_read
{args
} {
389 switch
-- [lindex
$args 0] {
407 set args
[lrange
$args 1 end
]
410 set cmdp
[_git_cmd
[lindex
$args 0]]
411 set args
[lrange
$args 1 end
]
414 set fd
[open
[concat
$opt $cmdp $args] r
]
416 if { [lindex
$args end
] eq
{2>@
1}
417 && $err eq
{can not
find channel named
"1"}
419 # Older versions of Tcl 8.4 don't have this 2>@1 IO
420 # redirect operator. Fallback to |& cat for those.
421 # The command was not actually started, so its safe
422 # to try to start it a second time.
424 set fd
[open
[concat \
427 [lrange
$args 0 end-1
] \
437 proc git_write
{args
} {
441 switch
-- [lindex
$args 0] {
455 set args
[lrange
$args 1 end
]
458 set cmdp
[_git_cmd
[lindex
$args 0]]
459 set args
[lrange
$args 1 end
]
461 return [open
[concat
$opt $cmdp $args] w
]
464 proc load_current_branch
{} {
465 global current_branch is_detached
467 set fd
[open
[gitdir HEAD
] r
]
468 if {[gets
$fd ref
] < 1} {
473 set pfx
{ref
: refs
/heads
/}
474 set len
[string length
$pfx]
475 if {[string equal
-length $len $pfx $ref]} {
476 # We're on a branch. It might not exist. But
477 # HEAD looks good enough to be a branch.
479 set current_branch
[string range
$ref $len end
]
482 # Assume this is a detached head.
484 set current_branch HEAD
489 auto_load tk_optionMenu
490 rename tk_optionMenu real__tkOptionMenu
491 proc tk_optionMenu
{w varName args
} {
492 set m
[eval real__tkOptionMenu
$w $varName $args]
493 $m configure
-font font_ui
494 $w configure
-font font_ui
498 ######################################################################
502 set _git
[_which git
]
504 catch
{wm withdraw .
}
505 error_popup
"Cannot find git in PATH."
508 set _nice
[_which nice
]
511 ######################################################################
515 if {[catch
{set _git_version
[git
--version]} err
]} {
516 catch
{wm withdraw .
}
517 error_popup
"Cannot determine Git version:
521 [appname] requires Git 1.5.0 or later."
524 if {![regsub
{^git version
} $_git_version {} _git_version
]} {
525 catch
{wm withdraw .
}
526 error_popup
"Cannot parse Git version string:\n\n$_git_version"
529 regsub
{\.
[0-9]+\.g
[0-9a-f]+$
} $_git_version {} _git_version
530 regsub
{\.rc
[0-9]+$
} $_git_version {} _git_version
532 proc git-version
{args
} {
535 switch
[llength
$args] {
541 set op
[lindex
$args 0]
542 set vr
[lindex
$args 1]
543 set cm
[package vcompare
$_git_version $vr]
544 return [expr $cm $op 0]
548 set type [lindex
$args 0]
549 set name
[lindex
$args 1]
550 set parm
[lindex
$args 2]
551 set body
[lindex
$args 3]
553 if {($type ne
{proc
} && $type ne
{method
})} {
554 error
"Invalid arguments to git-version"
556 if {[llength
$body] < 2 ||
[lindex
$body end-1
] ne
{default
}} {
557 error
"Last arm of $type $name must be default"
560 foreach
{op vr cb
} [lrange
$body 0 end-2
] {
561 if {[git-version
$op $vr]} {
562 return [uplevel
[list
$type $name $parm $cb]]
566 return [uplevel
[list
$type $name $parm [lindex
$body end
]]]
570 error
"git-version >= x"
576 if {[git-version
< 1.5]} {
577 catch
{wm withdraw .
}
578 error_popup
"[appname] requires Git 1.5.0 or later.
580 You are using [git-version]:
586 ######################################################################
591 set _gitdir
$env(GIT_DIR
)
595 set _gitdir
[git rev-parse
--git-dir]
596 set _prefix
[git rev-parse
--show-prefix]
598 catch
{wm withdraw .
}
599 error_popup
"Cannot find the git directory:\n\n$err"
602 if {![file isdirectory
$_gitdir] && [is_Cygwin
]} {
603 catch
{set _gitdir
[exec cygpath
--unix $_gitdir]}
605 if {![file isdirectory
$_gitdir]} {
606 catch
{wm withdraw .
}
607 error_popup
"Git directory not found:\n\n$_gitdir"
610 if {[lindex
[file split $_gitdir] end
] ne
{.git
}} {
611 catch
{wm withdraw .
}
612 error_popup
"Cannot use funny .git directory:\n\n$_gitdir"
615 if {[catch
{cd [file dirname $_gitdir]} err
]} {
616 catch
{wm withdraw .
}
617 error_popup
"No working directory [file dirname $_gitdir]:\n\n$err"
620 set _reponame
[lindex
[file split \
621 [file normalize
[file dirname $_gitdir]]] \
624 ######################################################################
628 set current_diff_path
{}
629 set current_diff_side
{}
630 set diff_actions
[list
]
634 set MERGE_HEAD
[list
]
637 set current_branch
{}
639 set current_diff_path
{}
640 set selected_commit_type new
642 ######################################################################
650 set disable_on_lock
[list
]
651 set index_lock_type none
653 proc lock_index
{type} {
654 global index_lock_type disable_on_lock
656 if {$index_lock_type eq
{none
}} {
657 set index_lock_type
$type
658 foreach w
$disable_on_lock {
659 uplevel
#0 $w disabled
662 } elseif
{$index_lock_type eq
"begin-$type"} {
663 set index_lock_type
$type
669 proc unlock_index
{} {
670 global index_lock_type disable_on_lock
672 set index_lock_type none
673 foreach w
$disable_on_lock {
678 ######################################################################
682 proc repository_state
{ctvar hdvar mhvar
} {
683 global current_branch
684 upvar
$ctvar ct
$hdvar hd
$mhvar mh
689 if {[catch
{set hd
[git rev-parse
--verify HEAD
]}]} {
695 set merge_head
[gitdir MERGE_HEAD
]
696 if {[file exists
$merge_head]} {
698 set fd_mh
[open
$merge_head r
]
699 while {[gets
$fd_mh line
] >= 0} {
710 global PARENT empty_tree
712 set p
[lindex
$PARENT 0]
716 if {$empty_tree eq
{}} {
717 set empty_tree
[git mktree
<< {}]
722 proc rescan
{after
{honor_trustmtime
1}} {
723 global HEAD PARENT MERGE_HEAD commit_type
724 global ui_index ui_workdir ui_comm
725 global rescan_active file_states
728 if {$rescan_active > 0 ||
![lock_index
read]} return
730 repository_state newType newHEAD newMERGE_HEAD
731 if {[string match amend
* $commit_type]
732 && $newType eq
{normal
}
733 && $newHEAD eq
$HEAD} {
737 set MERGE_HEAD
$newMERGE_HEAD
738 set commit_type
$newType
741 array
unset file_states
743 if {![$ui_comm edit modified
]
744 ||
[string trim
[$ui_comm get
0.0 end
]] eq
{}} {
745 if {[string match amend
* $commit_type]} {
746 } elseif
{[load_message GITGUI_MSG
]} {
747 } elseif
{[load_message MERGE_MSG
]} {
748 } elseif
{[load_message SQUASH_MSG
]} {
751 $ui_comm edit modified false
754 if {$honor_trustmtime && $repo_config(gui.trustmtime
) eq
{true
}} {
755 rescan_stage2
{} $after
758 ui_status
{Refreshing
file status...
}
759 set fd_rf
[git_read update-index \
765 fconfigure
$fd_rf -blocking 0 -translation binary
766 fileevent
$fd_rf readable \
767 [list rescan_stage2
$fd_rf $after]
771 proc rescan_stage2
{fd after
} {
772 global rescan_active buf_rdi buf_rdf buf_rlo
776 if {![eof
$fd]} return
780 set ls_others
[list
--exclude-per-directory=.gitignore
]
781 set info_exclude
[gitdir info exclude
]
782 if {[file readable
$info_exclude]} {
783 lappend ls_others
"--exclude-from=$info_exclude"
791 ui_status
{Scanning
for modified files ...
}
792 set fd_di
[git_read diff-index
--cached -z [PARENT
]]
793 set fd_df
[git_read diff-files
-z]
794 set fd_lo
[eval git_read ls-files
--others -z $ls_others]
796 fconfigure
$fd_di -blocking 0 -translation binary
-encoding binary
797 fconfigure
$fd_df -blocking 0 -translation binary
-encoding binary
798 fconfigure
$fd_lo -blocking 0 -translation binary
-encoding binary
799 fileevent
$fd_di readable
[list read_diff_index
$fd_di $after]
800 fileevent
$fd_df readable
[list read_diff_files
$fd_df $after]
801 fileevent
$fd_lo readable
[list read_ls_others
$fd_lo $after]
804 proc load_message
{file} {
808 if {[file isfile
$f]} {
809 if {[catch
{set fd
[open
$f r
]}]} {
812 set content
[string trim
[read $fd]]
814 regsub
-all -line {[ \r\t]+$
} $content {} content
815 $ui_comm delete
0.0 end
816 $ui_comm insert end
$content
822 proc read_diff_index
{fd after
} {
825 append buf_rdi
[read $fd]
827 set n
[string length
$buf_rdi]
829 set z1
[string first
"\0" $buf_rdi $c]
832 set z2
[string first
"\0" $buf_rdi $z1]
836 set i
[split [string range
$buf_rdi $c [expr {$z1 - 2}]] { }]
837 set p
[string range
$buf_rdi $z1 [expr {$z2 - 1}]]
839 [encoding convertfrom
$p] \
841 [list
[lindex
$i 0] [lindex
$i 2]] \
847 set buf_rdi
[string range
$buf_rdi $c end
]
852 rescan_done
$fd buf_rdi
$after
855 proc read_diff_files
{fd after
} {
858 append buf_rdf
[read $fd]
860 set n
[string length
$buf_rdf]
862 set z1
[string first
"\0" $buf_rdf $c]
865 set z2
[string first
"\0" $buf_rdf $z1]
869 set i
[split [string range
$buf_rdf $c [expr {$z1 - 2}]] { }]
870 set p
[string range
$buf_rdf $z1 [expr {$z2 - 1}]]
872 [encoding convertfrom
$p] \
875 [list
[lindex
$i 0] [lindex
$i 2]]
880 set buf_rdf
[string range
$buf_rdf $c end
]
885 rescan_done
$fd buf_rdf
$after
888 proc read_ls_others
{fd after
} {
891 append buf_rlo
[read $fd]
892 set pck
[split $buf_rlo "\0"]
893 set buf_rlo
[lindex
$pck end
]
894 foreach p
[lrange
$pck 0 end-1
] {
895 merge_state
[encoding convertfrom
$p] ?O
897 rescan_done
$fd buf_rlo
$after
900 proc rescan_done
{fd buf after
} {
901 global rescan_active current_diff_path
902 global file_states repo_config
905 if {![eof
$fd]} return
908 if {[incr rescan_active
-1] > 0} return
913 if {$current_diff_path ne
{}} reshow_diff
917 proc prune_selection
{} {
918 global file_states selected_paths
920 foreach path
[array names selected_paths
] {
921 if {[catch
{set still_here
$file_states($path)}]} {
922 unset selected_paths
($path)
927 ######################################################################
931 proc mapicon
{w state path
} {
934 if {[catch
{set r
$all_icons($state$w)}]} {
935 puts
"error: no icon for $w state={$state} $path"
941 proc mapdesc
{state path
} {
944 if {[catch
{set r
$all_descs($state)}]} {
945 puts
"error: no desc for state={$state} $path"
951 proc ui_status
{msg
} {
952 $
::main_status show
$msg
955 proc ui_ready
{{test {}}} {
956 $
::main_status show
{Ready.
} $test
959 proc escape_path
{path
} {
960 regsub
-all {\\} $path "\\\\" path
961 regsub
-all "\n" $path "\\n" path
965 proc short_path
{path
} {
966 return [escape_path
[lindex
[file split $path] end
]]
970 set null_sha1
[string repeat
0 40]
972 proc merge_state
{path new_state
{head_info
{}} {index_info
{}}} {
973 global file_states next_icon_id null_sha1
975 set s0
[string index
$new_state 0]
976 set s1
[string index
$new_state 1]
978 if {[catch
{set info
$file_states($path)}]} {
980 set icon n
[incr next_icon_id
]
982 set state
[lindex
$info 0]
983 set icon
[lindex
$info 1]
984 if {$head_info eq
{}} {set head_info
[lindex
$info 2]}
985 if {$index_info eq
{}} {set index_info
[lindex
$info 3]}
988 if {$s0 eq
{?
}} {set s0
[string index
$state 0]} \
989 elseif
{$s0 eq
{_
}} {set s0 _
}
991 if {$s1 eq
{?
}} {set s1
[string index
$state 1]} \
992 elseif
{$s1 eq
{_
}} {set s1 _
}
994 if {$s0 eq
{A
} && $s1 eq
{_
} && $head_info eq
{}} {
995 set head_info
[list
0 $null_sha1]
996 } elseif
{$s0 ne
{_
} && [string index
$state 0] eq
{_
}
997 && $head_info eq
{}} {
998 set head_info
$index_info
1001 set file_states
($path) [list
$s0$s1 $icon \
1002 $head_info $index_info \
1007 proc display_file_helper
{w path icon_name old_m new_m
} {
1010 if {$new_m eq
{_
}} {
1011 set lno
[lsearch
-sorted -exact $file_lists($w) $path]
1013 set file_lists
($w) [lreplace
$file_lists($w) $lno $lno]
1015 $w conf
-state normal
1016 $w delete
$lno.0 [expr {$lno + 1}].0
1017 $w conf
-state disabled
1019 } elseif
{$old_m eq
{_
} && $new_m ne
{_
}} {
1020 lappend file_lists
($w) $path
1021 set file_lists
($w) [lsort
-unique $file_lists($w)]
1022 set lno
[lsearch
-sorted -exact $file_lists($w) $path]
1024 $w conf
-state normal
1025 $w image create
$lno.0 \
1026 -align center
-padx 5 -pady 1 \
1028 -image [mapicon
$w $new_m $path]
1029 $w insert
$lno.1 "[escape_path $path]\n"
1030 $w conf
-state disabled
1031 } elseif
{$old_m ne
$new_m} {
1032 $w conf
-state normal
1033 $w image conf
$icon_name -image [mapicon
$w $new_m $path]
1034 $w conf
-state disabled
1038 proc display_file
{path state
} {
1039 global file_states selected_paths
1040 global ui_index ui_workdir
1042 set old_m
[merge_state
$path $state]
1043 set s
$file_states($path)
1044 set new_m
[lindex
$s 0]
1045 set icon_name
[lindex
$s 1]
1047 set o
[string index
$old_m 0]
1048 set n
[string index
$new_m 0]
1055 display_file_helper
$ui_index $path $icon_name $o $n
1057 if {[string index
$old_m 0] eq
{U
}} {
1060 set o
[string index
$old_m 1]
1062 if {[string index
$new_m 0] eq
{U
}} {
1065 set n
[string index
$new_m 1]
1067 display_file_helper
$ui_workdir $path $icon_name $o $n
1069 if {$new_m eq
{__
}} {
1070 unset file_states
($path)
1071 catch
{unset selected_paths
($path)}
1075 proc display_all_files_helper
{w path icon_name m
} {
1078 lappend file_lists
($w) $path
1079 set lno
[expr {[lindex
[split [$w index end
] .
] 0] - 1}]
1080 $w image create end \
1081 -align center
-padx 5 -pady 1 \
1083 -image [mapicon
$w $m $path]
1084 $w insert end
"[escape_path $path]\n"
1087 proc display_all_files
{} {
1088 global ui_index ui_workdir
1089 global file_states file_lists
1092 $ui_index conf
-state normal
1093 $ui_workdir conf
-state normal
1095 $ui_index delete
0.0 end
1096 $ui_workdir delete
0.0 end
1099 set file_lists
($ui_index) [list
]
1100 set file_lists
($ui_workdir) [list
]
1102 foreach path
[lsort
[array names file_states
]] {
1103 set s
$file_states($path)
1105 set icon_name
[lindex
$s 1]
1107 set s
[string index
$m 0]
1108 if {$s ne
{U
} && $s ne
{_
}} {
1109 display_all_files_helper
$ui_index $path \
1113 if {[string index
$m 0] eq
{U
}} {
1116 set s
[string index
$m 1]
1119 display_all_files_helper
$ui_workdir $path \
1124 $ui_index conf
-state disabled
1125 $ui_workdir conf
-state disabled
1128 ######################################################################
1133 #define mask_width 14
1134 #define mask_height 15
1135 static unsigned char mask_bits
[] = {
1136 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
1137 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
1138 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f};
1141 image create bitmap file_plain
-background white
-foreground black
-data {
1142 #define plain_width 14
1143 #define plain_height 15
1144 static unsigned char plain_bits
[] = {
1145 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
1146 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10,
1147 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1148 } -maskdata $filemask
1150 image create bitmap file_mod
-background white
-foreground blue
-data {
1151 #define mod_width 14
1152 #define mod_height 15
1153 static unsigned char mod_bits
[] = {
1154 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
1155 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
1156 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
1157 } -maskdata $filemask
1159 image create bitmap file_fulltick
-background white
-foreground "#007000" -data {
1160 #define file_fulltick_width 14
1161 #define file_fulltick_height 15
1162 static unsigned char file_fulltick_bits
[] = {
1163 0xfe, 0x01, 0x02, 0x1a, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x16, 0x02, 0x16,
1164 0x02, 0x13, 0x00, 0x13, 0x86, 0x11, 0x8c, 0x11, 0xd8, 0x10, 0xf2, 0x10,
1165 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1166 } -maskdata $filemask
1168 image create bitmap file_parttick
-background white
-foreground "#005050" -data {
1169 #define parttick_width 14
1170 #define parttick_height 15
1171 static unsigned char parttick_bits
[] = {
1172 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
1173 0x7a, 0x14, 0x02, 0x16, 0x02, 0x13, 0x8a, 0x11, 0xda, 0x10, 0x72, 0x10,
1174 0x22, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1175 } -maskdata $filemask
1177 image create bitmap file_question
-background white
-foreground black
-data {
1178 #define file_question_width 14
1179 #define file_question_height 15
1180 static unsigned char file_question_bits
[] = {
1181 0xfe, 0x01, 0x02, 0x02, 0xe2, 0x04, 0xf2, 0x09, 0x1a, 0x1b, 0x0a, 0x13,
1182 0x82, 0x11, 0xc2, 0x10, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, 0x62, 0x10,
1183 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1184 } -maskdata $filemask
1186 image create bitmap file_removed
-background white
-foreground red
-data {
1187 #define file_removed_width 14
1188 #define file_removed_height 15
1189 static unsigned char file_removed_bits
[] = {
1190 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
1191 0x1a, 0x16, 0x32, 0x13, 0xe2, 0x11, 0xc2, 0x10, 0xe2, 0x11, 0x32, 0x13,
1192 0x1a, 0x16, 0x02, 0x10, 0xfe, 0x1f};
1193 } -maskdata $filemask
1195 image create bitmap file_merge
-background white
-foreground blue
-data {
1196 #define file_merge_width 14
1197 #define file_merge_height 15
1198 static unsigned char file_merge_bits
[] = {
1199 0xfe, 0x01, 0x02, 0x03, 0x62, 0x05, 0x62, 0x09, 0x62, 0x1f, 0x62, 0x10,
1200 0xfa, 0x11, 0xf2, 0x10, 0x62, 0x10, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
1201 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
1202 } -maskdata $filemask
1205 #define file_width 18
1206 #define file_height 18
1207 static unsigned char file_bits
[] = {
1208 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x00,
1209 0x0c, 0x03, 0x00, 0x04, 0xfe, 0x00, 0x06, 0x80, 0x00, 0xff, 0x9f, 0x00,
1210 0x03, 0x98, 0x00, 0x02, 0x90, 0x00, 0x06, 0xb0, 0x00, 0x04, 0xa0, 0x00,
1211 0x0c, 0xe0, 0x00, 0x08, 0xc0, 0x00, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00,
1212 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1214 image create bitmap file_dir
-background white
-foreground blue \
1215 -data $file_dir_data -maskdata $file_dir_data
1218 set file_uplevel_data
{
1220 #define up_height 15
1221 static unsigned char up_bits
[] = {
1222 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc, 0x1f,
1223 0xfe, 0x3f, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01,
1224 0xc0, 0x01, 0xc0, 0x01, 0x00, 0x00};
1226 image create bitmap file_uplevel
-background white
-foreground red \
1227 -data $file_uplevel_data -maskdata $file_uplevel_data
1228 unset file_uplevel_data
1230 set ui_index .vpane.files.index.list
1231 set ui_workdir .vpane.files.workdir.list
1233 set all_icons
(_
$ui_index) file_plain
1234 set all_icons
(A
$ui_index) file_fulltick
1235 set all_icons
(M
$ui_index) file_fulltick
1236 set all_icons
(D
$ui_index) file_removed
1237 set all_icons
(U
$ui_index) file_merge
1239 set all_icons
(_
$ui_workdir) file_plain
1240 set all_icons
(M
$ui_workdir) file_mod
1241 set all_icons
(D
$ui_workdir) file_question
1242 set all_icons
(U
$ui_workdir) file_merge
1243 set all_icons
(O
$ui_workdir) file_plain
1245 set max_status_desc
0
1249 {_M
"Modified, not staged"}
1250 {M_
"Staged for commit"}
1251 {MM
"Portions staged for commit"}
1252 {MD
"Staged for commit, missing"}
1254 {_O
"Untracked, not staged"}
1255 {A_
"Staged for commit"}
1256 {AM
"Portions staged for commit"}
1257 {AD
"Staged for commit, missing"}
1260 {D_
"Staged for removal"}
1261 {DO
"Staged for removal, still present"}
1263 {U_
"Requires merge resolution"}
1264 {UU
"Requires merge resolution"}
1265 {UM
"Requires merge resolution"}
1266 {UD
"Requires merge resolution"}
1268 if {$max_status_desc < [string length
[lindex
$i 1]]} {
1269 set max_status_desc
[string length
[lindex
$i 1]]
1271 set all_descs
([lindex
$i 0]) [lindex
$i 1]
1275 ######################################################################
1279 proc bind_button3
{w cmd
} {
1280 bind $w <Any-Button-3
> $cmd
1282 bind $w <Control-Button-1
> $cmd
1286 proc scrollbar2many
{list mode args
} {
1287 foreach w
$list {eval $w $mode $args}
1290 proc many2scrollbar
{list mode sb top bottom
} {
1291 $sb set $top $bottom
1292 foreach w
$list {$w $mode moveto
$top}
1295 proc incr_font_size
{font
{amt
1}} {
1296 set sz
[font configure
$font -size]
1298 font configure
$font -size $sz
1299 font configure
${font}bold
-size $sz
1300 font configure
${font}italic
-size $sz
1303 ######################################################################
1307 set starting_gitk_msg
{Starting gitk... please
wait...
}
1309 proc do_gitk
{revs
} {
1310 # -- Always start gitk through whatever we were loaded with. This
1311 # lets us bypass using shell process on Windows systems.
1313 set exe
[file join [file dirname $
::_git
] gitk
]
1314 set cmd
[list
[info nameofexecutable
] $exe]
1315 if {! [file exists
$exe]} {
1316 error_popup
"Unable to start gitk:\n\n$exe does not exist"
1318 eval exec $cmd $revs &
1319 ui_status $
::starting_gitk_msg
1321 ui_ready
$starting_gitk_msg
1329 global ui_comm is_quitting repo_config commit_type
1331 if {$is_quitting} return
1334 if {[winfo exists
$ui_comm]} {
1335 # -- Stash our current commit buffer.
1337 set save
[gitdir GITGUI_MSG
]
1338 set msg
[string trim
[$ui_comm get
0.0 end
]]
1339 regsub
-all -line {[ \r\t]+$
} $msg {} msg
1340 if {(![string match amend
* $commit_type]
1341 ||
[$ui_comm edit modified
])
1344 set fd
[open
$save w
]
1345 puts
-nonewline $fd $msg
1349 catch
{file delete
$save}
1352 # -- Stash our current window geometry into this repository.
1354 set cfg_geometry
[list
]
1355 lappend cfg_geometry
[wm geometry .
]
1356 lappend cfg_geometry
[lindex
[.vpane sash coord
0] 1]
1357 lappend cfg_geometry
[lindex
[.vpane.files sash coord
0] 0]
1358 if {[catch
{set rc_geometry
$repo_config(gui.geometry
)}]} {
1361 if {$cfg_geometry ne
$rc_geometry} {
1362 catch
{git config gui.geometry
$cfg_geometry}
1377 proc toggle_or_diff
{w x y
} {
1378 global file_states file_lists current_diff_path ui_index ui_workdir
1379 global last_clicked selected_paths
1381 set pos
[split [$w index @
$x,$y] .
]
1382 set lno
[lindex
$pos 0]
1383 set col [lindex
$pos 1]
1384 set path
[lindex
$file_lists($w) [expr {$lno - 1}]]
1390 set last_clicked
[list
$w $lno]
1391 array
unset selected_paths
1392 $ui_index tag remove in_sel
0.0 end
1393 $ui_workdir tag remove in_sel
0.0 end
1396 if {$current_diff_path eq
$path} {
1397 set after
{reshow_diff
;}
1401 if {$w eq
$ui_index} {
1403 "Unstaging [short_path $path] from commit" \
1405 [concat
$after [list ui_ready
]]
1406 } elseif
{$w eq
$ui_workdir} {
1408 "Adding [short_path $path]" \
1410 [concat
$after [list ui_ready
]]
1413 show_diff
$path $w $lno
1417 proc add_one_to_selection
{w x y
} {
1418 global file_lists last_clicked selected_paths
1420 set lno
[lindex
[split [$w index @
$x,$y] .
] 0]
1421 set path
[lindex
$file_lists($w) [expr {$lno - 1}]]
1427 if {$last_clicked ne
{}
1428 && [lindex
$last_clicked 0] ne
$w} {
1429 array
unset selected_paths
1430 [lindex
$last_clicked 0] tag remove in_sel
0.0 end
1433 set last_clicked
[list
$w $lno]
1434 if {[catch
{set in_sel
$selected_paths($path)}]} {
1438 unset selected_paths
($path)
1439 $w tag remove in_sel
$lno.0 [expr {$lno + 1}].0
1441 set selected_paths
($path) 1
1442 $w tag add in_sel
$lno.0 [expr {$lno + 1}].0
1446 proc add_range_to_selection
{w x y
} {
1447 global file_lists last_clicked selected_paths
1449 if {[lindex
$last_clicked 0] ne
$w} {
1450 toggle_or_diff
$w $x $y
1454 set lno
[lindex
[split [$w index @
$x,$y] .
] 0]
1455 set lc
[lindex
$last_clicked 1]
1464 foreach path
[lrange
$file_lists($w) \
1465 [expr {$begin - 1}] \
1466 [expr {$end - 1}]] {
1467 set selected_paths
($path) 1
1469 $w tag add in_sel
$begin.0 [expr {$end + 1}].0
1472 ######################################################################
1476 set cursor_ptr arrow
1477 font create font_diff
-family Courier
-size 10
1481 eval font configure font_ui
[font actual
[.dummy cget
-font]]
1485 font create font_uiitalic
1486 font create font_uibold
1487 font create font_diffbold
1488 font create font_diffitalic
1490 foreach class
{Button Checkbutton Entry Label
1491 Labelframe Listbox Menu Message
1492 Radiobutton Spinbox Text
} {
1493 option add
*$class.font font_ui
1497 if {[is_Windows
] ||
[is_MacOSX
]} {
1498 option add
*Menu.tearOff
0
1509 proc apply_config
{} {
1510 global repo_config font_descs
1512 foreach option
$font_descs {
1513 set name
[lindex
$option 0]
1514 set font
[lindex
$option 1]
1516 foreach
{cn cv
} $repo_config(gui.
$name) {
1517 font configure
$font $cn $cv
1520 error_popup
"Invalid font specified in gui.$name:\n\n$err"
1522 foreach
{cn cv
} [font configure
$font] {
1523 font configure
${font}bold
$cn $cv
1524 font configure
${font}italic
$cn $cv
1526 font configure
${font}bold
-weight bold
1527 font configure
${font}italic
-slant italic
1531 set default_config
(merge.diffstat
) true
1532 set default_config
(merge.summary
) false
1533 set default_config
(merge.verbosity
) 2
1534 set default_config
(user.name
) {}
1535 set default_config
(user.email
) {}
1537 set default_config
(gui.matchtrackingbranch
) false
1538 set default_config
(gui.pruneduringfetch
) false
1539 set default_config
(gui.trustmtime
) false
1540 set default_config
(gui.diffcontext
) 5
1541 set default_config
(gui.newbranchtemplate
) {}
1542 set default_config
(gui.fontui
) [font configure font_ui
]
1543 set default_config
(gui.fontdiff
) [font configure font_diff
]
1545 {fontui font_ui
{Main Font
}}
1546 {fontdiff font_diff
{Diff
/Console Font
}}
1551 ######################################################################
1553 ## feature option selection
1555 if {[regexp
{^git-
(.
+)$
} [appname
] _junk subcommand
]} {
1560 if {$subcommand eq
{gui.sh
}} {
1563 if {$subcommand eq
{gui
} && [llength
$argv] > 0} {
1564 set subcommand
[lindex
$argv 0]
1565 set argv
[lrange
$argv 1 end
]
1568 enable_option multicommit
1569 enable_option branch
1570 enable_option transport
1572 switch
-- $subcommand {
1575 disable_option multicommit
1576 disable_option branch
1577 disable_option transport
1580 enable_option singlecommit
1582 disable_option multicommit
1583 disable_option branch
1584 disable_option transport
1588 ######################################################################
1596 menu .mbar
-tearoff 0
1597 .mbar add cascade
-label Repository
-menu .mbar.repository
1598 .mbar add cascade
-label Edit
-menu .mbar.edit
1599 if {[is_enabled branch
]} {
1600 .mbar add cascade
-label Branch
-menu .mbar.branch
1602 if {[is_enabled multicommit
] ||
[is_enabled singlecommit
]} {
1603 .mbar add cascade
-label Commit
-menu .mbar.commit
1605 if {[is_enabled transport
]} {
1606 .mbar add cascade
-label Merge
-menu .mbar.merge
1607 .mbar add cascade
-label Fetch
-menu .mbar.fetch
1608 .mbar add cascade
-label Push
-menu .mbar.push
1610 . configure
-menu .mbar
1612 # -- Repository Menu
1614 menu .mbar.repository
1616 .mbar.repository add
command \
1617 -label {Browse Current Branch
} \
1618 -command {browser
::new
$current_branch}
1619 trace add variable current_branch
write ".mbar.repository entryconf [.mbar.repository index last] -label \"Browse \$current_branch\" ;#"
1620 .mbar.repository add separator
1622 .mbar.repository add
command \
1623 -label {Visualize Current Branch
} \
1624 -command {do_gitk
$current_branch}
1625 trace add variable current_branch
write ".mbar.repository entryconf [.mbar.repository index last] -label \"Visualize \$current_branch\" ;#"
1626 .mbar.repository add
command \
1627 -label {Visualize All Branches
} \
1628 -command {do_gitk
--all}
1629 .mbar.repository add separator
1631 if {[is_enabled multicommit
]} {
1632 .mbar.repository add
command -label {Database Statistics
} \
1635 .mbar.repository add
command -label {Compress Database
} \
1638 .mbar.repository add
command -label {Verify Database
} \
1639 -command do_fsck_objects
1641 .mbar.repository add separator
1644 .mbar.repository add
command \
1645 -label {Create Desktop Icon
} \
1646 -command do_cygwin_shortcut
1647 } elseif
{[is_Windows
]} {
1648 .mbar.repository add
command \
1649 -label {Create Desktop Icon
} \
1650 -command do_windows_shortcut
1651 } elseif
{[is_MacOSX
]} {
1652 .mbar.repository add
command \
1653 -label {Create Desktop Icon
} \
1654 -command do_macosx_app
1658 .mbar.repository add
command -label Quit \
1665 .mbar.edit add
command -label Undo \
1666 -command {catch
{[focus
] edit undo
}} \
1668 .mbar.edit add
command -label Redo \
1669 -command {catch
{[focus
] edit redo
}} \
1671 .mbar.edit add separator
1672 .mbar.edit add
command -label Cut \
1673 -command {catch
{tk_textCut
[focus
]}} \
1675 .mbar.edit add
command -label Copy \
1676 -command {catch
{tk_textCopy
[focus
]}} \
1678 .mbar.edit add
command -label Paste \
1679 -command {catch
{tk_textPaste
[focus
]; [focus
] see insert
}} \
1681 .mbar.edit add
command -label Delete \
1682 -command {catch
{[focus
] delete sel.first sel.last
}} \
1684 .mbar.edit add separator
1685 .mbar.edit add
command -label {Select All
} \
1686 -command {catch
{[focus
] tag add sel
0.0 end
}} \
1691 if {[is_enabled branch
]} {
1694 .mbar.branch add
command -label {Create...
} \
1695 -command branch_create
::dialog \
1697 lappend disable_on_lock
[list .mbar.branch entryconf \
1698 [.mbar.branch index last
] -state]
1700 .mbar.branch add
command -label {Checkout...
} \
1701 -command branch_checkout
::dialog \
1703 lappend disable_on_lock
[list .mbar.branch entryconf \
1704 [.mbar.branch index last
] -state]
1706 .mbar.branch add
command -label {Rename...
} \
1707 -command branch_rename
::dialog
1708 lappend disable_on_lock
[list .mbar.branch entryconf \
1709 [.mbar.branch index last
] -state]
1711 .mbar.branch add
command -label {Delete...
} \
1712 -command branch_delete
::dialog
1713 lappend disable_on_lock
[list .mbar.branch entryconf \
1714 [.mbar.branch index last
] -state]
1716 .mbar.branch add
command -label {Reset...
} \
1717 -command merge
::reset_hard
1718 lappend disable_on_lock
[list .mbar.branch entryconf \
1719 [.mbar.branch index last
] -state]
1724 if {[is_enabled multicommit
] ||
[is_enabled singlecommit
]} {
1727 .mbar.commit add radiobutton \
1728 -label {New Commit
} \
1729 -command do_select_commit_type \
1730 -variable selected_commit_type \
1732 lappend disable_on_lock \
1733 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1735 .mbar.commit add radiobutton \
1736 -label {Amend Last Commit
} \
1737 -command do_select_commit_type \
1738 -variable selected_commit_type \
1740 lappend disable_on_lock \
1741 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1743 .mbar.commit add separator
1745 .mbar.commit add
command -label Rescan \
1746 -command do_rescan \
1748 lappend disable_on_lock \
1749 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1751 .mbar.commit add
command -label {Add To Commit
} \
1752 -command do_add_selection
1753 lappend disable_on_lock \
1754 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1756 .mbar.commit add
command -label {Add Existing To Commit
} \
1757 -command do_add_all \
1759 lappend disable_on_lock \
1760 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1762 .mbar.commit add
command -label {Unstage From Commit
} \
1763 -command do_unstage_selection
1764 lappend disable_on_lock \
1765 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1767 .mbar.commit add
command -label {Revert Changes
} \
1768 -command do_revert_selection
1769 lappend disable_on_lock \
1770 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1772 .mbar.commit add separator
1774 .mbar.commit add
command -label {Sign Off
} \
1775 -command do_signoff \
1778 .mbar.commit add
command -label Commit \
1779 -command do_commit \
1780 -accelerator $M1T-Return
1781 lappend disable_on_lock \
1782 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1787 if {[is_enabled branch
]} {
1789 .mbar.merge add
command -label {Local Merge...
} \
1790 -command merge
::dialog
1791 lappend disable_on_lock \
1792 [list .mbar.merge entryconf
[.mbar.merge index last
] -state]
1793 .mbar.merge add
command -label {Abort Merge...
} \
1794 -command merge
::reset_hard
1795 lappend disable_on_lock \
1796 [list .mbar.merge entryconf
[.mbar.merge index last
] -state]
1802 if {[is_enabled transport
]} {
1806 .mbar.push add
command -label {Push...
} \
1807 -command do_push_anywhere \
1809 .mbar.push add
command -label {Delete...
} \
1810 -command remote_branch_delete
::dialog
1814 # -- Apple Menu (Mac OS X only)
1816 .mbar add cascade
-label Apple
-menu .mbar.apple
1819 .mbar.apple add
command -label "About [appname]" \
1821 .mbar.apple add
command -label "Options..." \
1826 .mbar.edit add separator
1827 .mbar.edit add
command -label {Options...
} \
1832 if {[is_Cygwin
] && [file exists
/usr
/local
/miga
/lib
/gui-miga
]} {
1834 if {![lock_index update
]} return
1835 set cmd
[list sh
--login -c "/usr/local/miga/lib/gui-miga \"[pwd]\""]
1836 set miga_fd
[open
"|$cmd" r
]
1837 fconfigure
$miga_fd -blocking 0
1838 fileevent
$miga_fd readable
[list miga_done
$miga_fd]
1839 ui_status
{Running miga...
}
1841 proc miga_done
{fd
} {
1849 .mbar add cascade
-label Tools
-menu .mbar.tools
1851 .mbar.tools add
command -label "Migrate" \
1853 lappend disable_on_lock \
1854 [list .mbar.tools entryconf
[.mbar.tools index last
] -state]
1860 .mbar add cascade
-label Help
-menu .mbar.
help
1864 .mbar.
help add
command -label "About [appname]" \
1869 catch
{set browser
$repo_config(instaweb.browser
)}
1870 set doc_path
[file dirname [gitexec
]]
1871 set doc_path
[file join $doc_path Documentation index.html
]
1874 set doc_path
[exec cygpath
--mixed $doc_path]
1877 if {$browser eq
{}} {
1880 } elseif
{[is_Cygwin
]} {
1881 set program_files
[file dirname [exec cygpath
--windir]]
1882 set program_files
[file join $program_files {Program Files
}]
1883 set firefox
[file join $program_files {Mozilla Firefox
} firefox.exe
]
1884 set ie
[file join $program_files {Internet Explorer
} IEXPLORE.EXE
]
1885 if {[file exists
$firefox]} {
1886 set browser
$firefox
1887 } elseif
{[file exists
$ie]} {
1890 unset program_files firefox ie
1894 if {[file isfile
$doc_path]} {
1895 set doc_url
"file:$doc_path"
1897 set doc_url
{http
://www.kernel.org
/pub
/software
/scm
/git
/docs
/}
1900 if {$browser ne
{}} {
1901 .mbar.
help add
command -label {Online Documentation
} \
1902 -command [list
exec $browser $doc_url &]
1904 unset browser doc_path doc_url
1906 # -- Standard bindings
1908 wm protocol . WM_DELETE_WINDOW do_quit
1909 bind all
<$M1B-Key-q> do_quit
1910 bind all
<$M1B-Key-Q> do_quit
1911 bind all
<$M1B-Key-w> {destroy
[winfo toplevel
%W
]}
1912 bind all
<$M1B-Key-W> {destroy
[winfo toplevel
%W
]}
1914 set subcommand_args
{}
1916 puts stderr
"usage: $::argv0 $::subcommand $::subcommand_args"
1920 # -- Not a normal commit type invocation? Do that instead!
1922 switch
-- $subcommand {
1924 set subcommand_args
{rev?
}
1925 switch
[llength
$argv] {
1926 0 { load_current_branch
}
1928 set current_branch
[lindex
$argv 0]
1929 if {[regexp
{^
[0-9a-f]{1,39}$
} $current_branch]} {
1931 set current_branch \
1932 [git rev-parse
--verify $current_branch]
1941 browser
::new
$current_branch
1945 set subcommand_args
{rev? path?
}
1950 if {$is_path ||
[file exists
$_prefix$a]} {
1951 if {$path ne
{}} usage
1954 } elseif
{$a eq
{--}} {
1956 if {$head ne
{}} usage
1961 } elseif
{$head eq
{}} {
1962 if {$head ne
{}} usage
1973 if {[regexp
{^
[0-9a-f]{1,39}$
} $head]} {
1975 set head [git rev-parse
--verify $head]
1981 set current_branch
$head
1984 if {$path eq
{}} usage
1985 blame
::new
$head $path
1990 if {[llength
$argv] != 0} {
1991 puts
-nonewline stderr
"usage: $argv0"
1992 if {$subcommand ne
{gui
} && [appname
] ne
"git-$subcommand"} {
1993 puts
-nonewline stderr
" $subcommand"
1998 # fall through to setup UI for commits
2001 puts stderr
"usage: $argv0 \[{blame|browser|citool}\]"
2012 -text {Current Branch
:} \
2016 -textvariable current_branch \
2019 pack .branch.l1
-side left
2020 pack .branch.cb
-side left
-fill x
2021 pack .branch
-side top
-fill x
2023 # -- Main Window Layout
2025 panedwindow .vpane
-orient vertical
2026 panedwindow .vpane.files
-orient horizontal
2027 .vpane add .vpane.files
-sticky nsew
-height 100 -width 200
2028 pack .vpane
-anchor n
-side top
-fill both
-expand 1
2030 # -- Index File List
2032 frame .vpane.files.index
-height 100 -width 200
2033 label .vpane.files.index.title
-text {Staged Changes
(Will Be Committed
)} \
2034 -background lightgreen
2035 text
$ui_index -background white
-borderwidth 0 \
2036 -width 20 -height 10 \
2038 -cursor $cursor_ptr \
2039 -xscrollcommand {.vpane.files.index.sx
set} \
2040 -yscrollcommand {.vpane.files.index.sy
set} \
2042 scrollbar .vpane.files.index.sx
-orient h
-command [list
$ui_index xview
]
2043 scrollbar .vpane.files.index.sy
-orient v
-command [list
$ui_index yview
]
2044 pack .vpane.files.index.title
-side top
-fill x
2045 pack .vpane.files.index.sx
-side bottom
-fill x
2046 pack .vpane.files.index.sy
-side right
-fill y
2047 pack
$ui_index -side left
-fill both
-expand 1
2048 .vpane.files add .vpane.files.index
-sticky nsew
2050 # -- Working Directory File List
2052 frame .vpane.files.workdir
-height 100 -width 200
2053 label .vpane.files.workdir.title
-text {Unstaged Changes
(Will Not Be Committed
)} \
2054 -background lightsalmon
2055 text
$ui_workdir -background white
-borderwidth 0 \
2056 -width 20 -height 10 \
2058 -cursor $cursor_ptr \
2059 -xscrollcommand {.vpane.files.workdir.sx
set} \
2060 -yscrollcommand {.vpane.files.workdir.sy
set} \
2062 scrollbar .vpane.files.workdir.sx
-orient h
-command [list
$ui_workdir xview
]
2063 scrollbar .vpane.files.workdir.sy
-orient v
-command [list
$ui_workdir yview
]
2064 pack .vpane.files.workdir.title
-side top
-fill x
2065 pack .vpane.files.workdir.sx
-side bottom
-fill x
2066 pack .vpane.files.workdir.sy
-side right
-fill y
2067 pack
$ui_workdir -side left
-fill both
-expand 1
2068 .vpane.files add .vpane.files.workdir
-sticky nsew
2070 foreach i
[list
$ui_index $ui_workdir] {
2071 $i tag conf in_diff
-background lightgray
2072 $i tag conf in_sel
-background lightgray
2076 # -- Diff and Commit Area
2078 frame .vpane.lower
-height 300 -width 400
2079 frame .vpane.lower.commarea
2080 frame .vpane.lower.
diff -relief sunken
-borderwidth 1
2081 pack .vpane.lower.commarea
-side top
-fill x
2082 pack .vpane.lower.
diff -side bottom
-fill both
-expand 1
2083 .vpane add .vpane.lower
-sticky nsew
2085 # -- Commit Area Buttons
2087 frame .vpane.lower.commarea.buttons
2088 label .vpane.lower.commarea.buttons.l
-text {} \
2091 pack .vpane.lower.commarea.buttons.l
-side top
-fill x
2092 pack .vpane.lower.commarea.buttons
-side left
-fill y
2094 button .vpane.lower.commarea.buttons.rescan
-text {Rescan
} \
2096 pack .vpane.lower.commarea.buttons.rescan
-side top
-fill x
2097 lappend disable_on_lock \
2098 {.vpane.lower.commarea.buttons.rescan conf
-state}
2100 button .vpane.lower.commarea.buttons.incall
-text {Add Existing
} \
2102 pack .vpane.lower.commarea.buttons.incall
-side top
-fill x
2103 lappend disable_on_lock \
2104 {.vpane.lower.commarea.buttons.incall conf
-state}
2106 button .vpane.lower.commarea.buttons.signoff
-text {Sign Off
} \
2108 pack .vpane.lower.commarea.buttons.signoff
-side top
-fill x
2110 button .vpane.lower.commarea.buttons.commit
-text {Commit
} \
2112 pack .vpane.lower.commarea.buttons.commit
-side top
-fill x
2113 lappend disable_on_lock \
2114 {.vpane.lower.commarea.buttons.commit conf
-state}
2116 button .vpane.lower.commarea.buttons.push
-text {Push
} \
2117 -command do_push_anywhere
2118 pack .vpane.lower.commarea.buttons.push
-side top
-fill x
2120 # -- Commit Message Buffer
2122 frame .vpane.lower.commarea.buffer
2123 frame .vpane.lower.commarea.buffer.header
2124 set ui_comm .vpane.lower.commarea.buffer.t
2125 set ui_coml .vpane.lower.commarea.buffer.header.l
2126 radiobutton .vpane.lower.commarea.buffer.header.new \
2127 -text {New Commit
} \
2128 -command do_select_commit_type \
2129 -variable selected_commit_type \
2131 lappend disable_on_lock \
2132 [list .vpane.lower.commarea.buffer.header.new conf
-state]
2133 radiobutton .vpane.lower.commarea.buffer.header.amend \
2134 -text {Amend Last Commit
} \
2135 -command do_select_commit_type \
2136 -variable selected_commit_type \
2138 lappend disable_on_lock \
2139 [list .vpane.lower.commarea.buffer.header.amend conf
-state]
2143 proc trace_commit_type
{varname args
} {
2144 global ui_coml commit_type
2145 switch
-glob -- $commit_type {
2146 initial
{set txt
{Initial Commit Message
:}}
2147 amend
{set txt
{Amended Commit Message
:}}
2148 amend-initial
{set txt
{Amended Initial Commit Message
:}}
2149 amend-merge
{set txt
{Amended Merge Commit Message
:}}
2150 merge
{set txt
{Merge Commit Message
:}}
2151 * {set txt
{Commit Message
:}}
2153 $ui_coml conf
-text $txt
2155 trace add variable commit_type
write trace_commit_type
2156 pack
$ui_coml -side left
-fill x
2157 pack .vpane.lower.commarea.buffer.header.amend
-side right
2158 pack .vpane.lower.commarea.buffer.header.new
-side right
2160 text
$ui_comm -background white
-borderwidth 1 \
2163 -autoseparators true \
2165 -width 75 -height 9 -wrap none \
2167 -yscrollcommand {.vpane.lower.commarea.buffer.sby
set}
2168 scrollbar .vpane.lower.commarea.buffer.sby \
2169 -command [list
$ui_comm yview
]
2170 pack .vpane.lower.commarea.buffer.header
-side top
-fill x
2171 pack .vpane.lower.commarea.buffer.sby
-side right
-fill y
2172 pack
$ui_comm -side left
-fill y
2173 pack .vpane.lower.commarea.buffer
-side left
-fill y
2175 # -- Commit Message Buffer Context Menu
2177 set ctxm .vpane.lower.commarea.buffer.ctxm
2178 menu
$ctxm -tearoff 0
2181 -command {tk_textCut
$ui_comm}
2184 -command {tk_textCopy
$ui_comm}
2187 -command {tk_textPaste
$ui_comm}
2190 -command {$ui_comm delete sel.first sel.last
}
2193 -label {Select All
} \
2194 -command {focus
$ui_comm;$ui_comm tag add sel
0.0 end
}
2198 $ui_comm tag add sel
0.0 end
2199 tk_textCopy
$ui_comm
2200 $ui_comm tag remove sel
0.0 end
2206 bind_button3
$ui_comm "tk_popup $ctxm %X %Y"
2210 proc trace_current_diff_path
{varname args
} {
2211 global current_diff_path diff_actions file_states
2212 if {$current_diff_path eq
{}} {
2218 set p
$current_diff_path
2219 set s
[mapdesc
[lindex
$file_states($p) 0] $p]
2221 set p
[escape_path
$p]
2225 .vpane.lower.
diff.header.status configure
-text $s
2226 .vpane.lower.
diff.header.
file configure
-text $f
2227 .vpane.lower.
diff.header.path configure
-text $p
2228 foreach w
$diff_actions {
2232 trace add variable current_diff_path
write trace_current_diff_path
2234 frame .vpane.lower.
diff.header
-background gold
2235 label .vpane.lower.
diff.header.status \
2237 -width $max_status_desc \
2240 label .vpane.lower.
diff.header.
file \
2244 label .vpane.lower.
diff.header.path \
2248 pack .vpane.lower.
diff.header.status
-side left
2249 pack .vpane.lower.
diff.header.
file -side left
2250 pack .vpane.lower.
diff.header.path
-fill x
2251 set ctxm .vpane.lower.
diff.header.ctxm
2252 menu
$ctxm -tearoff 0
2260 -- $current_diff_path
2262 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2263 bind_button3 .vpane.lower.
diff.header.path
"tk_popup $ctxm %X %Y"
2267 frame .vpane.lower.
diff.body
2268 set ui_diff .vpane.lower.
diff.body.t
2269 text
$ui_diff -background white
-borderwidth 0 \
2270 -width 80 -height 15 -wrap none \
2272 -xscrollcommand {.vpane.lower.
diff.body.sbx
set} \
2273 -yscrollcommand {.vpane.lower.
diff.body.sby
set} \
2275 scrollbar .vpane.lower.
diff.body.sbx
-orient horizontal \
2276 -command [list
$ui_diff xview
]
2277 scrollbar .vpane.lower.
diff.body.sby
-orient vertical \
2278 -command [list
$ui_diff yview
]
2279 pack .vpane.lower.
diff.body.sbx
-side bottom
-fill x
2280 pack .vpane.lower.
diff.body.sby
-side right
-fill y
2281 pack
$ui_diff -side left
-fill both
-expand 1
2282 pack .vpane.lower.
diff.header
-side top
-fill x
2283 pack .vpane.lower.
diff.body
-side bottom
-fill both
-expand 1
2285 $ui_diff tag conf d_cr
-elide true
2286 $ui_diff tag conf d_@
-foreground blue
-font font_diffbold
2287 $ui_diff tag conf d_
+ -foreground {#00a000}
2288 $ui_diff tag conf d_-
-foreground red
2290 $ui_diff tag conf d_
++ -foreground {#00a000}
2291 $ui_diff tag conf d_--
-foreground red
2292 $ui_diff tag conf d_
+s \
2293 -foreground {#00a000} \
2294 -background {#e2effa}
2295 $ui_diff tag conf d_-s \
2297 -background {#e2effa}
2298 $ui_diff tag conf d_s
+ \
2299 -foreground {#00a000} \
2301 $ui_diff tag conf d_s- \
2305 $ui_diff tag conf d
<<<<<<< \
2306 -foreground orange \
2308 $ui_diff tag conf d
======= \
2309 -foreground orange \
2311 $ui_diff tag conf d
>>>>>>> \
2312 -foreground orange \
2315 $ui_diff tag raise sel
2317 # -- Diff Body Context Menu
2319 set ctxm .vpane.lower.
diff.body.ctxm
2320 menu
$ctxm -tearoff 0
2323 -command reshow_diff
2324 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2327 -command {tk_textCopy
$ui_diff}
2328 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2330 -label {Select All
} \
2331 -command {focus
$ui_diff;$ui_diff tag add sel
0.0 end
}
2332 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2336 $ui_diff tag add sel
0.0 end
2337 tk_textCopy
$ui_diff
2338 $ui_diff tag remove sel
0.0 end
2340 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2343 -label {Apply
/Reverse Hunk
} \
2344 -command {apply_hunk
$cursorX $cursorY}
2345 set ui_diff_applyhunk
[$ctxm index last
]
2346 lappend diff_actions
[list
$ctxm entryconf
$ui_diff_applyhunk -state]
2349 -label {Decrease Font Size
} \
2350 -command {incr_font_size font_diff
-1}
2351 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2353 -label {Increase Font Size
} \
2354 -command {incr_font_size font_diff
1}
2355 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2358 -label {Show Less Context
} \
2359 -command {if {$repo_config(gui.diffcontext
) >= 1} {
2360 incr repo_config
(gui.diffcontext
) -1
2363 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2365 -label {Show More Context
} \
2366 -command {if {$repo_config(gui.diffcontext
) < 99} {
2367 incr repo_config
(gui.diffcontext
)
2370 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2372 $ctxm add
command -label {Options...
} \
2374 bind_button3
$ui_diff "
2377 if {\$ui_index eq \$current_diff_side} {
2378 $ctxm entryconf $ui_diff_applyhunk -label {Unstage Hunk From Commit}
2380 $ctxm entryconf $ui_diff_applyhunk -label {Stage Hunk For Commit}
2382 tk_popup $ctxm %X %Y
2384 unset ui_diff_applyhunk
2388 set main_status
[::status_bar
::new .status
]
2389 pack .status
-anchor w
-side bottom
-fill x
2390 $main_status show
{Initializing...
}
2395 set gm
$repo_config(gui.geometry
)
2396 wm geometry .
[lindex
$gm 0]
2397 .vpane sash place
0 \
2398 [lindex
[.vpane sash coord
0] 0] \
2400 .vpane.files sash place
0 \
2402 [lindex
[.vpane.files sash coord
0] 1]
2408 bind $ui_comm <$M1B-Key-Return> {do_commit
;break}
2409 bind $ui_comm <$M1B-Key-i> {do_add_all
;break}
2410 bind $ui_comm <$M1B-Key-I> {do_add_all
;break}
2411 bind $ui_comm <$M1B-Key-x> {tk_textCut
%W
;break}
2412 bind $ui_comm <$M1B-Key-X> {tk_textCut
%W
;break}
2413 bind $ui_comm <$M1B-Key-c> {tk_textCopy
%W
;break}
2414 bind $ui_comm <$M1B-Key-C> {tk_textCopy
%W
;break}
2415 bind $ui_comm <$M1B-Key-v> {tk_textPaste
%W
; %W see insert
; break}
2416 bind $ui_comm <$M1B-Key-V> {tk_textPaste
%W
; %W see insert
; break}
2417 bind $ui_comm <$M1B-Key-a> {%W tag add sel
0.0 end
;break}
2418 bind $ui_comm <$M1B-Key-A> {%W tag add sel
0.0 end
;break}
2420 bind $ui_diff <$M1B-Key-x> {tk_textCopy
%W
;break}
2421 bind $ui_diff <$M1B-Key-X> {tk_textCopy
%W
;break}
2422 bind $ui_diff <$M1B-Key-c> {tk_textCopy
%W
;break}
2423 bind $ui_diff <$M1B-Key-C> {tk_textCopy
%W
;break}
2424 bind $ui_diff <$M1B-Key-v> {break}
2425 bind $ui_diff <$M1B-Key-V> {break}
2426 bind $ui_diff <$M1B-Key-a> {%W tag add sel
0.0 end
;break}
2427 bind $ui_diff <$M1B-Key-A> {%W tag add sel
0.0 end
;break}
2428 bind $ui_diff <Key-Up
> {catch
{%W yview scroll
-1 units
};break}
2429 bind $ui_diff <Key-Down
> {catch
{%W yview scroll
1 units
};break}
2430 bind $ui_diff <Key-Left
> {catch
{%W xview scroll
-1 units
};break}
2431 bind $ui_diff <Key-Right
> {catch
{%W xview scroll
1 units
};break}
2432 bind $ui_diff <Key-k
> {catch
{%W yview scroll
-1 units
};break}
2433 bind $ui_diff <Key-j
> {catch
{%W yview scroll
1 units
};break}
2434 bind $ui_diff <Key-h
> {catch
{%W xview scroll
-1 units
};break}
2435 bind $ui_diff <Key-l
> {catch
{%W xview scroll
1 units
};break}
2436 bind $ui_diff <Control-Key-b
> {catch
{%W yview scroll
-1 pages
};break}
2437 bind $ui_diff <Control-Key-f
> {catch
{%W yview scroll
1 pages
};break}
2438 bind $ui_diff <Button-1
> {focus
%W
}
2440 if {[is_enabled branch
]} {
2441 bind .
<$M1B-Key-n> branch_create
::dialog
2442 bind .
<$M1B-Key-N> branch_create
::dialog
2443 bind .
<$M1B-Key-o> branch_checkout
::dialog
2444 bind .
<$M1B-Key-O> branch_checkout
::dialog
2446 if {[is_enabled transport
]} {
2447 bind .
<$M1B-Key-p> do_push_anywhere
2448 bind .
<$M1B-Key-P> do_push_anywhere
2451 bind .
<Key-F5
> do_rescan
2452 bind .
<$M1B-Key-r> do_rescan
2453 bind .
<$M1B-Key-R> do_rescan
2454 bind .
<$M1B-Key-s> do_signoff
2455 bind .
<$M1B-Key-S> do_signoff
2456 bind .
<$M1B-Key-i> do_add_all
2457 bind .
<$M1B-Key-I> do_add_all
2458 bind .
<$M1B-Key-Return> do_commit
2459 foreach i
[list
$ui_index $ui_workdir] {
2460 bind $i <Button-1
> "toggle_or_diff $i %x %y; break"
2461 bind $i <$M1B-Button-1> "add_one_to_selection $i %x %y; break"
2462 bind $i <Shift-Button-1
> "add_range_to_selection $i %x %y; break"
2466 set file_lists
($ui_index) [list
]
2467 set file_lists
($ui_workdir) [list
]
2469 wm title .
"[appname] ([reponame]) [file normalize [file dirname [gitdir]]]"
2470 focus
-force $ui_comm
2472 # -- Warn the user about environmental problems. Cygwin's Tcl
2473 # does *not* pass its env array onto any processes it spawns.
2474 # This means that git processes get none of our environment.
2479 set msg
"Possible environment issues exist.
2481 The following environment variables are probably
2482 going to be ignored by any Git subprocess run
2486 foreach name
[array names env
] {
2487 switch
-regexp -- $name {
2488 {^GIT_INDEX_FILE$
} -
2489 {^GIT_OBJECT_DIRECTORY$
} -
2490 {^GIT_ALTERNATE_OBJECT_DIRECTORIES$
} -
2492 {^GIT_EXTERNAL_DIFF$
} -
2496 {^GIT_CONFIG_LOCAL$
} -
2497 {^GIT_
(AUTHOR|COMMITTER
)_DATE$
} {
2498 append msg
" - $name\n"
2501 {^GIT_
(AUTHOR|COMMITTER
)_
(NAME|EMAIL
)$
} {
2502 append msg
" - $name\n"
2504 set suggest_user
$name
2508 if {$ignored_env > 0} {
2510 This is due to a known issue with the
2511 Tcl binary distributed by Cygwin."
2513 if {$suggest_user ne
{}} {
2516 A good replacement for $suggest_user
2517 is placing values for the user.name and
2518 user.email settings into your personal
2524 unset ignored_env msg suggest_user name
2527 # -- Only initialize complex UI if we are going to stay running.
2529 if {[is_enabled transport
]} {
2536 # -- Only suggest a gc run if we are going to stay running.
2538 if {[is_enabled multicommit
]} {
2539 set object_limit
2000
2540 if {[is_Windows
]} {set object_limit
200}
2541 regexp
{^
([0-9]+) objects
,} [git count-objects
] _junk objects_current
2542 if {$objects_current >= $object_limit} {
2544 "This repository currently has $objects_current loose objects.
2546 To maintain optimal performance it is strongly recommended that you compress the database when more than $object_limit loose objects exist.
2548 Compress the database now?"] eq
yes} {
2552 unset object_limit _junk objects_current
2555 lock_index begin-read