git-gui: Initial revision.
[git-gui.git] / git-gui
blobdfa3000260d3a95c1be6060e768775d6674f0662
1 #!/bin/sh
2 # Tcl ignores the next line -*- tcl -*- \
3 exec wish "$0" -- "$@"
5 # Copyright (C) 2006 Shawn Pearce, Paul Mackerras. All rights reserved.
6 # This program is free software; it may be used, copied, modified
7 # and distributed under the terms of the GNU General Public Licence,
8 # either version 2, or (at your option) any later version.
11 ######################################################################
13 ## status
15 set status_active 0
17 proc update_status {} {
18 global gitdir HEAD commit_type
19 global ui_index ui_other ui_status_value
20 global status_active file_states
22 if {$status_active > 0} return
24 array unset file_states
25 set ui_status_value {Refreshing file status...}
26 foreach w [list $ui_index $ui_other] {
27 $w conf -state normal
28 $w delete 0.0 end
29 $w conf -state disabled
32 if {[catch {set HEAD [exec git rev-parse --verify HEAD]}]} {
33 set commit_type initial
34 } else {
35 set commit_type normal
38 set ls_others [list | git ls-files --others -z \
39 --exclude-per-directory=.gitignore]
40 set info_exclude [file join $gitdir info exclude]
41 if {[file readable $info_exclude]} {
42 lappend ls_others "--exclude-from=$info_exclude"
45 set fd_di [open "| git diff-index --cached -z $HEAD" r]
46 set fd_df [open "| git diff-files -z" r]
47 set fd_lo [open $ls_others r]
48 set status_active 3
50 fconfigure $fd_di -blocking 0 -translation binary
51 fconfigure $fd_df -blocking 0 -translation binary
52 fconfigure $fd_lo -blocking 0 -translation binary
53 fileevent $fd_di readable [list read_diff_index $fd_di]
54 fileevent $fd_df readable [list read_diff_files $fd_df]
55 fileevent $fd_lo readable [list read_ls_others $fd_lo]
58 proc read_diff_index {fd} {
59 global buf_rdi
61 append buf_rdi [read $fd]
62 set pck [split $buf_rdi "\0"]
63 set buf_rdi [lindex $pck end]
64 foreach {m p} [lrange $pck 0 end-1] {
65 if {$m != {} && $p != {}} {
66 display_file $p [string index $m end]_
69 status_eof $fd buf_rdi
72 proc read_diff_files {fd} {
73 global buf_rdf
75 append buf_rdf [read $fd]
76 set pck [split $buf_rdf "\0"]
77 set buf_rdf [lindex $pck end]
78 foreach {m p} [lrange $pck 0 end-1] {
79 if {$m != {} && $p != {}} {
80 display_file $p _[string index $m end]
83 status_eof $fd buf_rdf
86 proc read_ls_others {fd} {
87 global buf_rlo
89 append buf_rlo [read $fd]
90 set pck [split $buf_rlo "\0"]
91 set buf_rlo [lindex $pck end]
92 foreach p [lrange $pck 0 end-1] {
93 display_file $p _O
95 status_eof $fd buf_rlo
98 proc status_eof {fd buf} {
99 global status_active $buf
100 global ui_fname_value ui_status_value
102 if {[eof $fd]} {
103 set $buf {}
104 close $fd
105 if {[incr status_active -1] == 0} {
106 set ui_status_value {Ready.}
107 if {$ui_fname_value != {}} {
108 show_diff $ui_fname_value
114 ######################################################################
116 ## diff
118 set diff_active 0
120 proc clear_diff {} {
121 global ui_diff ui_fname_value ui_fstatus_value
123 $ui_diff conf -state normal
124 $ui_diff delete 0.0 end
125 $ui_diff conf -state disabled
126 set ui_fname_value {}
127 set ui_fstatus_value {}
130 proc show_diff {path} {
131 global file_states HEAD status_active diff_3way diff_active
132 global ui_diff ui_fname_value ui_fstatus_value ui_status_value
134 if {$status_active > 0} return
135 if {$diff_active} return
137 clear_diff
138 set s $file_states($path)
139 set m [lindex $s 0]
140 set diff_3way 0
141 set diff_active 1
142 set ui_fname_value $path
143 set ui_fstatus_value [mapdesc $m $path]
144 set ui_status_value "Loading diff of $path..."
146 set cmd [list | git diff-index -p $HEAD -- $path]
147 switch $m {
148 AM {
150 MM {
151 set cmd [list | git diff-index -p -c $HEAD $path]
153 _O {
154 if {[catch {
155 set fd [open $path r]
156 set content [read $fd]
157 close $fd
158 } err ]} {
159 set ui_status_value "Unable to display $path"
160 error_popup "Error loading file:\n$err"
161 return
163 $ui_diff conf -state normal
164 $ui_diff insert end $content
165 $ui_diff conf -state disabled
166 return
170 if {[catch {set fd [open $cmd r]} err]} {
171 set ui_status_value "Unable to display $path"
172 error_popup "Error loading diff:\n$err"
173 return
176 fconfigure $fd -blocking 0
177 fileevent $fd readable [list read_diff $fd]
180 proc read_diff {fd} {
181 global ui_diff ui_status_value diff_3way diff_active
183 while {[gets $fd line] >= 0} {
184 if {[string match index* $line]} {
185 if {[string first , $line] >= 0} {
186 set diff_3way 1
190 $ui_diff conf -state normal
191 if {!$diff_3way} {
192 set x [string index $line 0]
193 switch -- $x {
194 "@" {set tags da}
195 "+" {set tags dp}
196 "-" {set tags dm}
197 default {set tags {}}
199 } else {
200 set x [string range $line 0 1]
201 switch -- $x {
202 default {set tags {}}
203 "@@" {set tags da}
204 "++" {set tags dp; set x " +"}
205 " +" {set tags {di bold}; set x "++"}
206 "+ " {set tags dni; set x "-+"}
207 "--" {set tags dm; set x " -"}
208 " -" {set tags {dm bold}; set x "--"}
209 "- " {set tags di; set x "+-"}
210 default {set tags {}}
212 set line [string replace $line 0 1 $x]
214 $ui_diff insert end $line $tags
215 $ui_diff insert end "\n"
216 $ui_diff conf -state disabled
219 if {[eof $fd]} {
220 close $fd
221 set diff_active 0
222 set ui_status_value {Ready.}
226 ######################################################################
228 ## ui helpers
230 proc mapcol {state path} {
231 global all_cols
233 if {[catch {set r $all_cols($state)}]} {
234 puts "error: no column for state={$state} $path"
235 return o
237 return $r
240 proc mapicon {state path} {
241 global all_icons
243 if {[catch {set r $all_icons($state)}]} {
244 puts "error: no icon for state={$state} $path"
245 return file_plain
247 return $r
250 proc mapdesc {state path} {
251 global all_descs
253 if {[catch {set r $all_descs($state)}]} {
254 puts "error: no desc for state={$state} $path"
255 return $state
257 return $r
260 proc bsearch {w path} {
261 set hi [expr [lindex [split [$w index end] .] 0] - 2]
262 if {$hi == 0} {
263 return -1
265 set lo 0
266 while {$lo < $hi} {
267 set mi [expr [expr $lo + $hi] / 2]
268 set ti [expr $mi + 1]
269 set cmp [string compare [$w get $ti.1 $ti.end] $path]
270 if {$cmp < 0} {
271 set lo $ti
272 } elseif {$cmp == 0} {
273 return $mi
274 } else {
275 set hi $mi
278 return -[expr $lo + 1]
281 proc merge_state {path state} {
282 global file_states
284 if {[array names file_states -exact $path] == {}} {
285 set o __
286 set s [list $o none none]
287 } else {
288 set s $file_states($path)
289 set o [lindex $s 0]
292 set m [lindex $s 0]
293 if {[string index $state 0] == "_"} {
294 set state [string index $m 0][string index $state 1]
295 } elseif {[string index $state 0] == "*"} {
296 set state _[string index $state 1]
299 if {[string index $state 1] == "_"} {
300 set state [string index $state 0][string index $m 1]
301 } elseif {[string index $state 1] == "*"} {
302 set state [string index $state 0]_
305 set file_states($path) [lreplace $s 0 0 $state]
306 return $o
309 proc display_file {path state} {
310 global ui_index ui_other file_states
312 set old_m [merge_state $path $state]
313 set s $file_states($path)
314 set m [lindex $s 0]
316 if {[mapcol $m $path] == "o"} {
317 set ii 1
318 set ai 2
319 set iw $ui_index
320 set aw $ui_other
321 } else {
322 set ii 2
323 set ai 1
324 set iw $ui_other
325 set aw $ui_index
328 set d [lindex $s $ii]
329 if {$d != "none"} {
330 set lno [bsearch $iw $path]
331 if {$lno >= 0} {
332 incr lno
333 $iw conf -state normal
334 $iw delete $lno.0 [expr $lno + 1].0
335 $iw conf -state disabled
336 set s [lreplace $s $ii $ii none]
340 set d [lindex $s $ai]
341 if {$d == "none"} {
342 set lno [expr abs([bsearch $aw $path] + 1) + 1]
343 $aw conf -state normal
344 set ico [$aw image create $lno.0 \
345 -align center -padx 5 -pady 1 \
346 -image [mapicon $m $path]]
347 $aw insert $lno.1 "$path\n"
348 $aw conf -state disabled
349 set file_states($path) [lreplace $s $ai $ai [list $ico]]
350 } elseif {[mapicon $m $path] != [mapicon $old_m $path]} {
351 set ico [lindex $d 0]
352 $aw image conf $ico -image [mapicon $m $path]
356 proc toggle_mode {path} {
357 global file_states
359 set s $file_states($path)
360 set m [lindex $s 0]
362 switch -- $m {
363 AM -
364 _O {
365 set new A*
366 set cmd [list exec git update-index --add $path]
368 MM {
369 set new M*
370 set cmd [list exec git update-index $path]
372 _D {
373 set new D*
374 set cmd [list exec git update-index --remove $path]
376 default {
377 return
381 if {[catch {eval $cmd} err]} {
382 error_popup "Error processing file:\n$err"
383 return
385 display_file $path $new
388 ######################################################################
390 ## icons
392 set filemask {
393 #define mask_width 14
394 #define mask_height 15
395 static unsigned char mask_bits[] = {
396 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
397 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
398 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f};
401 image create bitmap file_plain -background white -foreground black -data {
402 #define plain_width 14
403 #define plain_height 15
404 static unsigned char plain_bits[] = {
405 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
406 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10,
407 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f};
408 } -maskdata $filemask
410 image create bitmap file_mod -background white -foreground blue -data {
411 #define mod_width 14
412 #define mod_height 15
413 static unsigned char mod_bits[] = {
414 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
415 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
416 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
417 } -maskdata $filemask
419 image create bitmap file_tick -background white -foreground "#007000" -data {
420 #define file_tick_width 14
421 #define file_tick_height 15
422 static unsigned char file_tick_bits[] = {
423 0xfe, 0x01, 0x02, 0x1a, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x16, 0x02, 0x16,
424 0x02, 0x13, 0x00, 0x13, 0x86, 0x11, 0x8c, 0x11, 0xd8, 0x10, 0xf2, 0x10,
425 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
426 } -maskdata $filemask
428 image create bitmap file_parttick -background white -foreground "#005050" -data {
429 #define parttick_width 14
430 #define parttick_height 15
431 static unsigned char parttick_bits[] = {
432 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
433 0x7a, 0x14, 0x02, 0x16, 0x02, 0x13, 0x8a, 0x11, 0xda, 0x10, 0x72, 0x10,
434 0x22, 0x10, 0x02, 0x10, 0xfe, 0x1f};
435 } -maskdata $filemask
437 image create bitmap file_question -background white -foreground black -data {
438 #define file_question_width 14
439 #define file_question_height 15
440 static unsigned char file_question_bits[] = {
441 0xfe, 0x01, 0x02, 0x02, 0xe2, 0x04, 0xf2, 0x09, 0x1a, 0x1b, 0x0a, 0x13,
442 0x82, 0x11, 0xc2, 0x10, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, 0x62, 0x10,
443 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
444 } -maskdata $filemask
446 image create bitmap file_removed -background white -foreground red -data {
447 #define file_removed_width 14
448 #define file_removed_height 15
449 static unsigned char file_removed_bits[] = {
450 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
451 0x1a, 0x16, 0x32, 0x13, 0xe2, 0x11, 0xc2, 0x10, 0xe2, 0x11, 0x32, 0x13,
452 0x1a, 0x16, 0x02, 0x10, 0xfe, 0x1f};
453 } -maskdata $filemask
455 image create bitmap file_merge -background white -foreground blue -data {
456 #define file_merge_width 14
457 #define file_merge_height 15
458 static unsigned char file_merge_bits[] = {
459 0xfe, 0x01, 0x02, 0x03, 0x62, 0x05, 0x62, 0x09, 0x62, 0x1f, 0x62, 0x10,
460 0xfa, 0x11, 0xf2, 0x10, 0x62, 0x10, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
461 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
462 } -maskdata $filemask
464 foreach i {
465 {__ i "Unmodified" plain}
466 {_M i "Modified" mod}
467 {M_ i "Checked in" tick}
468 {MM i "Partially checked in" parttick}
470 {_O o "Untracked" plain}
471 {A_ o "Added" tick}
472 {AM o "Partially added" parttick}
474 {_D i "Missing" question}
475 {D_ i "Removed" removed}
476 {DD i "Removed" removed}
477 {DO i "Partially removed" removed}
479 {UM i "Merge conflicts" merge}
480 {U_ i "Merge conflicts" merge}
482 set all_cols([lindex $i 0]) [lindex $i 1]
483 set all_descs([lindex $i 0]) [lindex $i 2]
484 set all_icons([lindex $i 0]) file_[lindex $i 3]
486 unset filemask i
488 ######################################################################
490 ## util
492 proc error_popup {msg} {
493 set w .error
494 toplevel $w
495 wm transient $w .
496 show_msg $w $w $msg
499 proc show_msg {w top msg} {
500 message $w.m -text $msg -justify center -aspect 400
501 pack $w.m -side top -fill x -padx 20 -pady 20
502 button $w.ok -text OK -command "destroy $top"
503 pack $w.ok -side bottom -fill x
504 bind $top <Visibility> "grab $top; focus $top"
505 bind $top <Key-Return> "destroy $top"
506 tkwait window $top
509 ######################################################################
511 ## ui commands
513 proc do_gitk {} {
514 global tcl_platform
516 if {$tcl_platform(platform) == "windows"} {
517 exec sh -c gitk &
518 } else {
519 exec gitk &
523 proc do_quit {} {
524 destroy .
527 proc do_rescan {} {
528 update_status
531 # shift == 1: left click
532 # 3: right click
533 proc click {w x y shift wx wy} {
534 set pos [split [$w index @$x,$y] .]
535 set lno [lindex $pos 0]
536 set col [lindex $pos 1]
537 set path [$w get $lno.1 $lno.end]
538 if {$path == {}} return
540 if {$col > 0 && $shift == 1} {
541 show_diff $path
545 proc unclick {w x y} {
546 set pos [split [$w index @$x,$y] .]
547 set lno [lindex $pos 0]
548 set col [lindex $pos 1]
549 set path [$w get $lno.1 $lno.end]
550 if {$path == {}} return
552 if {$col == 0} {
553 toggle_mode $path
557 ######################################################################
559 ## ui init
561 set mainfont {Helvetica 10}
562 set difffont {Courier 10}
563 set maincursor [. cget -cursor]
565 # -- Menu Bar
566 menu .mbar -tearoff 0
567 .mbar add cascade -label Project -menu .mbar.project
568 .mbar add cascade -label Commit -menu .mbar.commit
569 .mbar add cascade -label Fetch -menu .mbar.fetch
570 .mbar add cascade -label Pull -menu .mbar.pull
571 . configure -menu .mbar
573 # -- Project Menu
574 menu .mbar.project
575 .mbar.project add command -label Visulize \
576 -command do_gitk \
577 -font $mainfont
578 .mbar.project add command -label Quit \
579 -command do_quit \
580 -font $mainfont
582 # -- Commit Menu
583 menu .mbar.commit
584 .mbar.commit add command -label Rescan \
585 -command do_rescan \
586 -font $mainfont
588 # -- Fetch Menu
589 menu .mbar.fetch
591 # -- Pull Menu
592 menu .mbar.pull
594 # -- Main Window Layout
595 panedwindow .vpane -orient vertical
596 panedwindow .vpane.files -orient horizontal
597 .vpane add .vpane.files -sticky nsew
598 pack .vpane -anchor n -side top -fill both -expand 1
600 # -- Index File List
601 set ui_index .vpane.files.index.list
602 frame .vpane.files.index -height 100 -width 400
603 label .vpane.files.index.title -text {Modified Files} \
604 -background green \
605 -font $mainfont
606 text $ui_index -background white -borderwidth 0 \
607 -width 40 -height 10 \
608 -font $mainfont \
609 -yscrollcommand {.vpane.files.index.sb set} \
610 -cursor $maincursor \
611 -state disabled
612 scrollbar .vpane.files.index.sb -command [list $ui_index yview]
613 pack .vpane.files.index.title -side top -fill x
614 pack .vpane.files.index.sb -side right -fill y
615 pack $ui_index -side left -fill both -expand 1
616 .vpane.files add .vpane.files.index -sticky nsew
618 # -- Other (Add) File List
619 set ui_other .vpane.files.other.list
620 frame .vpane.files.other -height 100 -width 100
621 label .vpane.files.other.title -text {Untracked Files} \
622 -background red \
623 -font $mainfont
624 text $ui_other -background white -borderwidth 0 \
625 -width 40 -height 10 \
626 -font $mainfont \
627 -yscrollcommand {.vpane.files.other.sb set} \
628 -cursor $maincursor \
629 -state disabled
630 scrollbar .vpane.files.other.sb -command [list $ui_other yview]
631 pack .vpane.files.other.title -side top -fill x
632 pack .vpane.files.other.sb -side right -fill y
633 pack $ui_other -side left -fill both -expand 1
634 .vpane.files add .vpane.files.other -sticky nsew
636 # -- Diff Header
637 set ui_fname_value {}
638 set ui_fstatus_value {}
639 frame .vpane.diff -height 100 -width 100
640 frame .vpane.diff.header
641 label .vpane.diff.header.l1 -text {File:} -font $mainfont
642 label .vpane.diff.header.l2 -textvariable ui_fname_value \
643 -anchor w \
644 -justify left \
645 -font $mainfont
646 label .vpane.diff.header.l3 -text {Status:} -font $mainfont
647 label .vpane.diff.header.l4 -textvariable ui_fstatus_value \
648 -width 20 \
649 -anchor w \
650 -justify left \
651 -font $mainfont
652 pack .vpane.diff.header.l1 -side left
653 pack .vpane.diff.header.l2 -side left -fill x
654 pack .vpane.diff.header.l4 -side right
655 pack .vpane.diff.header.l3 -side right
657 # -- Diff Body
658 frame .vpane.diff.body
659 set ui_diff .vpane.diff.body.t
660 text $ui_diff -background white -borderwidth 0 \
661 -width 40 -height 20 \
662 -font $difffont \
663 -xscrollcommand {.vpane.diff.body.sbx set} \
664 -yscrollcommand {.vpane.diff.body.sby set} \
665 -cursor $maincursor \
666 -state disabled
667 scrollbar .vpane.diff.body.sbx -orient horizontal \
668 -command [list $ui_diff xview]
669 scrollbar .vpane.diff.body.sby -orient vertical \
670 -command [list $ui_diff yview]
671 pack .vpane.diff.body.sbx -side bottom -fill x
672 pack .vpane.diff.body.sby -side right -fill y
673 pack $ui_diff -side left -fill both -expand 1
674 pack .vpane.diff.header -side top -fill x
675 pack .vpane.diff.body -side bottom -fill both -expand 1
676 .vpane add .vpane.diff -stick nsew
678 $ui_diff tag conf dm -foreground red
679 $ui_diff tag conf dp -foreground blue
680 $ui_diff tag conf da -font [concat $difffont bold]
681 $ui_diff tag conf di -foreground "#00a000"
682 $ui_diff tag conf dni -foreground "#a000a0"
683 $ui_diff tag conf bold -font [concat $difffont bold]
685 # -- Commit Area
686 frame .vpane.commarea -height 50
687 .vpane add .vpane.commarea -stick nsew
689 # -- Commit Area Buttons
690 frame .vpane.commarea.buttons
691 label .vpane.commarea.buttons.l -text {} \
692 -anchor w \
693 -justify left \
694 -font $mainfont
695 pack .vpane.commarea.buttons.l -side top -fill x
696 button .vpane.commarea.buttons.rescan -text {Rescan} \
697 -command do_rescan \
698 -font $mainfont
699 pack .vpane.commarea.buttons.rescan -side top -fill x
700 button .vpane.commarea.buttons.ciall -text {Check-in All} \
701 -command do_checkin_all \
702 -font $mainfont
703 pack .vpane.commarea.buttons.ciall -side top -fill x
704 button .vpane.commarea.buttons.commit -text {Commit} \
705 -command do_commit \
706 -font $mainfont
707 pack .vpane.commarea.buttons.commit -side top -fill x
708 pack .vpane.commarea.buttons -side left -fill y
710 # -- Commit Message Buffer
711 frame .vpane.commarea.buffer
712 set ui_comm .vpane.commarea.buffer.t
713 label .vpane.commarea.buffer.l -text {Commit Message:} \
714 -anchor w \
715 -justify left \
716 -font $mainfont
717 text $ui_comm -background white -borderwidth 1 \
718 -relief sunken \
719 -width 75 -height 10 -wrap none \
720 -font $difffont \
721 -yscrollcommand {.vpane.commarea.buffer.sby set} \
722 -cursor $maincursor
723 scrollbar .vpane.commarea.buffer.sby -command [list $ui_comm yview]
724 pack .vpane.commarea.buffer.l -side top -fill x
725 pack .vpane.commarea.buffer.sby -side right -fill y
726 pack $ui_comm -side left -fill y
727 pack .vpane.commarea.buffer -side left -fill y
729 # -- Status Bar
730 set ui_status_value {Initializing...}
731 label .status -textvariable ui_status_value \
732 -anchor w \
733 -justify left \
734 -borderwidth 1 \
735 -relief sunken \
736 -font $mainfont
737 pack .status -anchor w -side bottom -fill x
739 # -- Key Bindings
740 bind . <Destroy> do_quit
741 bind . <Key-F5> do_rescan
742 bind . <M1-Key-r> do_rescan
743 bind . <M1-Key-R> do_rescan
744 bind . <M1-Key-q> do_quit
745 bind . <M1-Key-Q> do_quit
746 foreach i [list $ui_index $ui_other] {
747 bind $i <Button-1> {click %W %x %y 1 %X %Y; break}
748 bind $i <Button-3> {click %W %x %y 3 %X %Y; break}
749 bind $i <ButtonRelease-1> {unclick %W %x %y; break}
751 unset i
753 ######################################################################
755 ## main
757 if {[catch {set gitdir [exec git rev-parse --git-dir]} err]} {
758 show_msg {} . "Cannot find the git directory: $err"
759 exit 1
762 wm title . "git-ui ([file normalize [file dirname $gitdir]])"
763 focus -force $ui_comm
764 update_status