From fce89e466ae75961018ab88fec7000568f981d46 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 13 Nov 2006 00:48:44 -0500 Subject: [PATCH 01/16] git-gui: Reverted file name text field to a label. So although a text field with a flat relief looks like a label on Windows it doesn't on Mac OS X. The Aqua version of Tk is still drawing a border around the text field and that makes the diff pane header look pretty ugly. Earlier I had made the file name area into a text widget so the user could highlight parts of it and copy them onto the clipboard; but with the context menu being present this isn't quite as necessary as the user can copy the file name to the clipboard using that instead. So although this is a small loss in functionality for non-Mac OS X systems I think it is still reasonable. Signed-off-by: Shawn O. Pearce --- git-gui | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/git-gui b/git-gui index fbbc0caaac..ca7f8dbc41 100755 --- a/git-gui +++ b/git-gui @@ -2290,33 +2290,23 @@ label .vpane.lower.diff.header.l1 -text {File:} \ -background orange \ -font font_ui set ui_fname .vpane.lower.diff.header.l2 -text $ui_fname \ +label $ui_fname \ + -textvariable ui_fname_value \ -background orange \ - -height 1 \ - -wrap none \ - -relief flat \ - -state disabled \ + -anchor w \ + -justify left \ -font font_ui menu $ui_fname.ctxm -tearoff 0 -$ui_fname.ctxm add command -label "Copy Only Selection" \ +$ui_fname.ctxm add command -label "Copy" \ -font font_ui \ - -command "tk_textCopy $ui_fname" -$ui_fname.ctxm add command -label "Copy Complete Name" \ - -font font_ui \ - -command " - $ui_fname tag add sel 0.0 {end -1c} - tk_textCopy $ui_fname - $ui_fname tag remove sel 0.0 end - " + -command { + clipboard clear + clipboard append \ + -format STRING \ + -type STRING \ + -- $ui_fname_value + } bind_button3 $ui_fname "tk_popup $ui_fname.ctxm %X %Y" -trace add variable ui_fname_value write $ui_fname.update -proc $ui_fname.update {varname args} { - global ui_fname ui_fname_value - $ui_fname configure -state normal - $ui_fname delete 0.0 end - $ui_fname insert end [escape_path $ui_fname_value] - $ui_fname configure -state disabled -} pack .vpane.lower.diff.header.l4 -side left pack .vpane.lower.diff.header.l1 -side left pack $ui_fname -fill x -- 2.49.0 From f7f8d32226595c22cb4f28f8e9e139cf42e1e640 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 13 Nov 2006 04:22:42 -0500 Subject: [PATCH 02/16] git-gui: By default don't allow partially included files. The concept of the Git index is confusing for many users, especially those who are newer to Git. Since git-gui is (at least partially) intended to be used by newer users who don't need the complexity of the index to be put in front of them early on, we should hide it by making any partially included file fully included as soon as we identify it. To do this we just run a quick update_index pass on any file which differs both in the index and the working directory, as these files have already been at least partially included by the user. A new option has been added in the options dialog (gui.partialinclude) which lets the user enable accessing the index from git-gui. This just disables the automatic update_index pass on partially included files. Signed-off-by: Shawn O. Pearce --- git-gui | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/git-gui b/git-gui index ca7f8dbc41..3e3a535326 100755 --- a/git-gui +++ b/git-gui @@ -406,19 +406,33 @@ proc read_ls_others {fd final} { proc status_eof {fd buf final} { global status_active ui_status_value + global file_states repo_config upvar $buf to_clear - if {[eof $fd]} { - set to_clear {} - close $fd + if {![eof $fd]} return + set to_clear {} + close $fd + if {[incr status_active -1] > 0} return - if {[incr status_active -1] == 0} { - display_all_files - unlock_index - reshow_diff - set ui_status_value $final + unlock_index + display_all_files + + if {$repo_config(gui.partialinclude) ne {true}} { + set pathList [list] + foreach path [array names file_states] { + switch -- [lindex $file_states($path) 0] { + AM - + MM {lappend pathList $path} + } + } + if {$pathList ne {}} { + update_index $pathList + return } } + + reshow_diff + set ui_status_value $final } ###################################################################### @@ -1164,7 +1178,6 @@ proc update_index {pathList} { set batch [expr {int($totalCnt * .01) + 1}] if {$batch > 25} {set batch 25} - set ui_status_value "Including files ... 0/$totalCnt 0%" set ui_status_value [format \ "Including files ... %i/%i files (%.2f%%)" \ $update_index_cp \ @@ -1192,10 +1205,9 @@ proc write_update_index {fd pathList totalCnt batch} { if {$update_index_cp >= $totalCnt} { close $fd unlock_index + set ui_status_value {Ready.} if {$update_index_rsd} { reshow_diff - } else { - set ui_status_value {Ready.} } return } @@ -1823,6 +1835,7 @@ proc do_options {} { pack $w.global -side right -fill both -expand 1 -pady 5 -padx 5 foreach option { + {b partialinclude {Allow Partially Included Files}} {b pullsummary {Show Pull Summary}} {b trustmtime {Trust File Modification Timestamps}} {i diffcontext {Number of Diff Context Lines}} @@ -2000,6 +2013,7 @@ proc apply_config {} { set default_config(gui.trustmtime) false set default_config(gui.pullsummary) true +set default_config(gui.partialinclude) false set default_config(gui.diffcontext) 5 set default_config(gui.fontui) [font configure font_ui] set default_config(gui.fontdiff) [font configure font_diff] -- 2.49.0 From 7d0d289e457eb643b8638b6385a0ce056f1f5a97 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 13 Nov 2006 14:25:53 -0500 Subject: [PATCH 03/16] git-gui: Refactor mouse clicking on file names/icons. I'm not a huge fan of putting the left and right mouse actions into the same procedure. Originally this is how Paul had implemented the logic in gitool and I had carried some of that over into git-gui, but now that I'm getting ready to implement right mouse click features to act on files I really should split this apart. Signed-off-by: Shawn O. Pearce --- git-gui | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/git-gui b/git-gui index 3e3a535326..b8ebe31777 100755 --- a/git-gui +++ b/git-gui @@ -1935,10 +1935,8 @@ proc do_save_config {w} { destroy $w } -# shift == 1: left click -# 3: right click -proc click {w x y shift wx wy} { - global ui_index ui_other file_lists +proc file_left_click {w x y} { + global file_lists set pos [split [$w index @$x,$y] .] set lno [lindex $pos 0] @@ -1946,12 +1944,12 @@ proc click {w x y shift wx wy} { set path [lindex $file_lists($w) [expr $lno - 1]] if {$path eq {}} return - if {$col > 0 && $shift == 1} { + if {$col > 0} { show_diff $path $w $lno } } -proc unclick {w x y} { +proc file_left_unclick {w x y} { global file_lists set pos [split [$w index @$x,$y] .] @@ -2457,9 +2455,8 @@ 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_other] { - bind $i {click %W %x %y 1 %X %Y; break} - bind $i {unclick %W %x %y; break} - bind_button3 $i {click %W %x %y 3 %X %Y; break} + bind $i {file_left_click %W %x %y; break} + bind $i {file_left_unclick %W %x %y; break} } unset i -- 2.49.0 From a37eee4406ff965fda4d234759aa58526657cbe3 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 13 Nov 2006 14:37:41 -0500 Subject: [PATCH 04/16] git-gui: Narrow the no differences information message. On Mac OS X the no differences informational message was linewrapped at the wrong points due to the limited width of the system dialog, yet the LFs embedded in the message (where I linewrapped it manually) were also being honored. This resulted in a very difficult to read paragraph of text. So this narrows the text down by another 10 columns or so, making it more readable. Signed-off-by: Shawn O. Pearce --- git-gui | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/git-gui b/git-gui index b8ebe31777..6b8d25e9aa 100755 --- a/git-gui +++ b/git-gui @@ -475,13 +475,15 @@ proc handle_empty_diff {} { [short_path $path] has no changes. -The modification date of this file was updated by another -application and you currently have the Trust File Modification -Timestamps option enabled, so Git did not automatically detect -that there are no content differences in this file. - -This file will now be removed from the modified files list, to -prevent possible confusion. +The modification date of this file was updated +by another application and you currently have +the Trust File Modification Timestamps option +enabled, so Git did not automatically detect +that there are no content differences in this +file. + +This file will now be removed from the modified +files list, to prevent possible confusion. " if {[catch {exec git update-index -- $path} err]} { error_popup "Failed to refresh index:\n\n$err" -- 2.49.0 From 24263b77165edfd438045ed3c25ec6669b3e76d4 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 13 Nov 2006 16:06:38 -0500 Subject: [PATCH 05/16] git-gui: Implemented multiple selection in file lists. Because I want to let users apply actions to more than one file at a time we really needed a concept of "the current selection" from the two file lists. Since I'm abusing a Tk text widget for the file displays I can't really use the Tk selection to track which files are picked and which aren't. So instead we keep this in an array to tell us which paths are currently selected and we use an inverse fg/bg for the selected file display. This is common most operating systems as a selection indicator. The selection works like most users would expect; single click will clear the selection and pick only that file, M1-click (aka Ctrl-click or Cmd-click) will toggle the one file in/out of the selection, and Shift-click will select the range between the last clicked file and the currently clicked file. Signed-off-by: Shawn O. Pearce --- git-gui | 136 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 111 insertions(+), 25 deletions(-) diff --git a/git-gui b/git-gui index 6b8d25e9aa..a60bf1c8a3 100755 --- a/git-gui +++ b/git-gui @@ -183,6 +183,7 @@ if {$appname eq {git-citool}} { set status_active 0 set diff_active 0 +set last_clicked {} set disable_on_lock [list] set index_lock_type none @@ -351,7 +352,7 @@ proc read_diff_index {fd final} { incr z2 -1 display_file \ [string range $buf_rdi $z1 $z2] \ - [string index $buf_rdi [expr $z1 - 2]]_ + [string index $buf_rdi [expr {$z1 - 2}]]_ incr c } if {$c < $n} { @@ -380,7 +381,7 @@ proc read_diff_files {fd final} { incr z2 -1 display_file \ [string range $buf_rdf $z1 $z2] \ - _[string index $buf_rdf [expr $z1 - 2]] + _[string index $buf_rdf [expr {$z1 - 2}]] incr c } if {$c < $n} { @@ -414,6 +415,7 @@ proc status_eof {fd buf final} { close $fd if {[incr status_active -1] > 0} return + prune_selection unlock_index display_all_files @@ -435,6 +437,16 @@ proc status_eof {fd buf final} { set ui_status_value $final } +proc prune_selection {} { + global file_states selected_paths + + foreach path [array names selected_paths] { + if {[catch {set still_here $file_states($path)}]} { + unset selected_paths($path) + } + } +} + ###################################################################### ## ## diff @@ -497,7 +509,7 @@ files list, to prevent possible confusion. [lreplace $file_lists($old_w) $lno $lno] incr lno $old_w conf -state normal - $old_w delete $lno.0 [expr $lno + 1].0 + $old_w delete $lno.0 [expr {$lno + 1}].0 $old_w conf -state disabled } } @@ -520,7 +532,7 @@ proc show_diff {path {w {}} {lno {}}} { } } if {$w ne {} && $lno >= 1} { - $w tag add in_diff $lno.0 [expr $lno + 1].0 + $w tag add in_diff $lno.0 [expr {$lno + 1}].0 } set s $file_states($path) @@ -821,7 +833,7 @@ proc commit_stage2 {curHEAD msg} { proc commit_stage3 {fd_wt curHEAD msg} { global single_commit gitdir HEAD PARENT commit_type tcl_platform global ui_status_value ui_comm - global file_states + global file_states selected_paths gets $fd_wt tree_id if {$tree_id eq {} || [catch {close $fd_wt} err]} { @@ -871,7 +883,7 @@ proc commit_stage3 {fd_wt curHEAD msg} { } set i [string first "\n" $msg] if {$i >= 0} { - append reflogm {: } [string range $msg 0 [expr $i - 1]] + append reflogm {: } [string range $msg 0 [expr {$i - 1}]] } else { append reflogm {: } $msg } @@ -934,6 +946,7 @@ proc commit_stage3 {fd_wt curHEAD msg} { if {$m eq {__}} { unset file_states($path) + catch {unset selected_paths($path)} } else { lset file_states($path) 0 $m } @@ -1102,7 +1115,7 @@ proc merge_state {path new_state} { } proc display_file {path state} { - global file_states file_lists status_active + global file_states file_lists selected_paths status_active set old_m [merge_state $path $state] if {$status_active} return @@ -1118,7 +1131,7 @@ proc display_file {path state} { if {$lno >= 0} { incr lno $old_w conf -state normal - $old_w delete $lno.0 [expr $lno + 1].0 + $old_w delete $lno.0 [expr {$lno + 1}].0 $old_w conf -state disabled } @@ -1132,6 +1145,12 @@ proc display_file {path state} { -name [lindex $s 1] \ -image $new_icon $new_w insert $lno.1 "[escape_path $path]\n" + if {[catch {set in_sel $selected_paths($path)}]} { + set in_sel 0 + } + if {$in_sel} { + $new_w tag add in_sel $lno.0 [expr {$lno + 1}].0 + } $new_w conf -state disabled } elseif {$new_icon ne [mapicon $old_m $path]} { $new_w conf -state normal @@ -1141,13 +1160,16 @@ proc display_file {path state} { } proc display_all_files {} { - global ui_index ui_other file_states file_lists + global ui_index ui_other + global file_states file_lists + global last_clicked selected_paths $ui_index conf -state normal $ui_other conf -state normal $ui_index delete 0.0 end $ui_other delete 0.0 end + set last_clicked {} set file_lists($ui_index) [list] set file_lists($ui_other) [list] @@ -1157,11 +1179,18 @@ proc display_all_files {} { set m [lindex $s 0] set w [mapcol $m $path] lappend file_lists($w) $path + set lno [expr {[lindex [split [$w index end] .] 0] - 1}] $w image create end \ -align center -padx 5 -pady 1 \ -name [lindex $s 1] \ -image [mapicon $m $path] $w insert end "[escape_path $path]\n" + if {[catch {set in_sel $selected_paths($path)}]} { + set in_sel 0 + } + if {$in_sel} { + $w tag add in_sel $lno.0 [expr {$lno + 1}].0 + } } $ui_index conf -state disabled @@ -1603,8 +1632,8 @@ proc console_read {w fd after} { while {$c < $n} { set cr [string first "\r" $buf $c] set lf [string first "\n" $buf $c] - if {$cr < 0} {set cr [expr $n + 1]} - if {$lf < 0} {set lf [expr $n + 1]} + if {$cr < 0} {set cr [expr {$n + 1}]} + if {$lf < 0} {set lf [expr {$n + 1}]} if {$lf < $cr} { $w.m.t insert end [string range $buf $c $lf] @@ -1937,32 +1966,83 @@ proc do_save_config {w} { destroy $w } -proc file_left_click {w x y} { - global file_lists +proc toggle_or_diff {w x y} { + global file_lists ui_index ui_other + global last_clicked selected_paths set pos [split [$w index @$x,$y] .] set lno [lindex $pos 0] set col [lindex $pos 1] - set path [lindex $file_lists($w) [expr $lno - 1]] - if {$path eq {}} return + set path [lindex $file_lists($w) [expr {$lno - 1}]] + if {$path eq {}} { + set last_clicked {} + return + } + + set last_clicked [list $w $lno] + array unset selected_paths + $ui_index tag remove in_sel 0.0 end + $ui_other tag remove in_sel 0.0 end - if {$col > 0} { + if {$col == 0} { + update_index [list $path] + } else { show_diff $path $w $lno } } -proc file_left_unclick {w x y} { +proc add_one_to_selection {w x y} { global file_lists + global last_clicked selected_paths set pos [split [$w index @$x,$y] .] set lno [lindex $pos 0] set col [lindex $pos 1] - set path [lindex $file_lists($w) [expr $lno - 1]] - if {$path eq {}} return + set path [lindex $file_lists($w) [expr {$lno - 1}]] + if {$path eq {}} { + set last_clicked {} + return + } - if {$col == 0} { - update_index [list $path] + set last_clicked [list $w $lno] + if {[catch {set in_sel $selected_paths($path)}]} { + set in_sel 0 + } + if {$in_sel} { + unset selected_paths($path) + $w tag remove in_sel $lno.0 [expr {$lno + 1}].0 + } else { + set selected_paths($path) 1 + $w tag add in_sel $lno.0 [expr {$lno + 1}].0 + } +} + +proc add_range_to_selection {w x y} { + global file_lists + global last_clicked selected_paths + + if {[lindex $last_clicked 0] ne $w} { + toggle_or_diff $w $x $y + return } + + set pos [split [$w index @$x,$y] .] + set lno [lindex $pos 0] + set lc [lindex $last_clicked 1] + if {$lc < $lno} { + set begin $lc + set end $lno + } else { + set begin $lno + set end $lc + } + + foreach path [lrange $file_lists($w) \ + [expr {$begin - 1}] \ + [expr {$end - 1}]] { + set selected_paths($path) 1 + } + $w tag add in_sel $begin.0 [expr {$end + 1}].0 } ###################################################################### @@ -2174,8 +2254,13 @@ pack .vpane.files.other.sb -side right -fill y pack $ui_other -side left -fill both -expand 1 .vpane.files add .vpane.files.other -sticky nsew -$ui_index tag conf in_diff -font font_uibold -$ui_other tag conf in_diff -font font_uibold +foreach i [list $ui_index $ui_other] { + $i tag conf in_diff -font font_uibold + $i tag conf in_sel \ + -background [$i cget -foreground] \ + -foreground [$i cget -background] +} +unset i # -- Diff and Commit Area frame .vpane.lower -height 300 -width 400 @@ -2457,8 +2542,9 @@ 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_other] { - bind $i {file_left_click %W %x %y; break} - bind $i {file_left_unclick %W %x %y; break} + bind $i "toggle_or_diff $i %x %y; break" + bind $i <$M1B-Button-1> "add_one_to_selection $i %x %y; break" + bind $i "add_range_to_selection $i %x %y; break" } unset i -- 2.49.0 From 99058720df7981aaaaf64e9a0d2c658d90b82340 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 14 Nov 2006 01:19:03 -0500 Subject: [PATCH 06/16] git-gui: Refactor update_status -> rescan. Since we refer to the act of updating our memory structures with index and working directory differences as a rescan in the UI its probably a good idea to make the related procedures have the same name. Signed-off-by: Shawn O. Pearce --- git-gui | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/git-gui b/git-gui index a60bf1c8a3..a1266fe7a7 100755 --- a/git-gui +++ b/git-gui @@ -234,7 +234,7 @@ proc repository_state {hdvar ctvar} { } } -proc update_status {{final Ready.}} { +proc rescan {{final Ready.}} { global HEAD PARENT commit_type global ui_index ui_other ui_status_value ui_comm global status_active file_states @@ -265,7 +265,7 @@ proc update_status {{final Ready.}} { } if {$repo_config(gui.trustmtime) eq {true}} { - update_status_stage2 {} $final + rescan_stage2 {} $final } else { set status_active 1 set ui_status_value {Refreshing file status...} @@ -277,11 +277,11 @@ proc update_status {{final Ready.}} { set fd_rf [open "| $cmd" r] fconfigure $fd_rf -blocking 0 -translation binary fileevent $fd_rf readable \ - [list update_status_stage2 $fd_rf $final] + [list rescan_stage2 $fd_rf $final] } } -proc update_status_stage2 {fd final} { +proc rescan_stage2 {fd final} { global gitdir PARENT commit_type global ui_index ui_other ui_status_value ui_comm global status_active @@ -684,7 +684,7 @@ proc load_last_commit {} { set commit_type amend set HEAD {} set PARENT {} - update_status + rescan } elseif {$parent_count == 1} { set commit_type amend set PARENT $parent @@ -692,7 +692,7 @@ proc load_last_commit {} { $ui_comm insert end $msg $ui_comm edit modified false $ui_comm edit reset - update_status + rescan } else { error_popup {You can't amend a merge commit.} return @@ -720,7 +720,7 @@ repository since our last scan. A rescan is required before committing. } unlock_index - update_status + rescan return } @@ -987,7 +987,7 @@ repository since our last scan. A rescan is required before a pull can be started. } unlock_index - update_status + rescan return } @@ -1026,7 +1026,7 @@ proc post_pull_remote {remote branch success} { set PARENT $HEAD set $ui_status_value {Ready.} } else { - update_status \ + rescan \ "Conflicts detected while pulling $branch from $remote." } } @@ -1744,7 +1744,7 @@ proc do_quit {} { } proc do_rescan {} { - update_status + rescan } proc do_include_all {} { @@ -2559,4 +2559,4 @@ if {!$single_commit} { populate_remote_menu .mbar.push To push_to populate_pull_menu .mbar.pull } -after 1 update_status +after 1 rescan -- 2.49.0 From 8f52548a9ed078d581379ad526a4259920f80a88 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 14 Nov 2006 01:29:32 -0500 Subject: [PATCH 07/16] git-gui: Provide an after-rescan script to rescan. There are some situations where we need to run rescan and have it do more than just updating the status in the UI when its complete. To help with that this changes the rescan procedure to take a script which it will run at the global level as soon as the rescan is done and the UI has finished updating with the results. This is useful for example if we performed a rescan as part of a commit operation; we can go back to the commit where we left off when the rescan got initiated. Signed-off-by: Shawn O. Pearce --- git-gui | 68 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/git-gui b/git-gui index a1266fe7a7..2c8501eebf 100755 --- a/git-gui +++ b/git-gui @@ -181,7 +181,7 @@ if {$appname eq {git-citool}} { ## ## task management -set status_active 0 +set rescan_active 0 set diff_active 0 set last_clicked {} @@ -234,13 +234,13 @@ proc repository_state {hdvar ctvar} { } } -proc rescan {{final Ready.}} { +proc rescan {after} { global HEAD PARENT commit_type global ui_index ui_other ui_status_value ui_comm - global status_active file_states + global rescan_active file_states global repo_config - if {$status_active || ![lock_index read]} return + if {$rescan_active > 0 || ![lock_index read]} return repository_state new_HEAD new_type if {$commit_type eq {amend} @@ -265,9 +265,9 @@ proc rescan {{final Ready.}} { } if {$repo_config(gui.trustmtime) eq {true}} { - rescan_stage2 {} $final + rescan_stage2 {} $after } else { - set status_active 1 + set rescan_active 1 set ui_status_value {Refreshing file status...} set cmd [list git update-index] lappend cmd -q @@ -277,14 +277,14 @@ proc rescan {{final Ready.}} { set fd_rf [open "| $cmd" r] fconfigure $fd_rf -blocking 0 -translation binary fileevent $fd_rf readable \ - [list rescan_stage2 $fd_rf $final] + [list rescan_stage2 $fd_rf $after] } } -proc rescan_stage2 {fd final} { +proc rescan_stage2 {fd after} { global gitdir PARENT commit_type global ui_index ui_other ui_status_value ui_comm - global status_active + global rescan_active global buf_rdi buf_rdf buf_rlo if {$fd ne {}} { @@ -304,7 +304,7 @@ proc rescan_stage2 {fd final} { set buf_rdf {} set buf_rlo {} - set status_active 3 + set rescan_active 3 set ui_status_value {Scanning for modified files ...} set fd_di [open "| git diff-index --cached -z $PARENT" r] set fd_df [open "| git diff-files -z" r] @@ -313,9 +313,9 @@ proc rescan_stage2 {fd final} { fconfigure $fd_di -blocking 0 -translation binary fconfigure $fd_df -blocking 0 -translation binary fconfigure $fd_lo -blocking 0 -translation binary - fileevent $fd_di readable [list read_diff_index $fd_di $final] - fileevent $fd_df readable [list read_diff_files $fd_df $final] - fileevent $fd_lo readable [list read_ls_others $fd_lo $final] + fileevent $fd_di readable [list read_diff_index $fd_di $after] + fileevent $fd_df readable [list read_diff_files $fd_df $after] + fileevent $fd_lo readable [list read_ls_others $fd_lo $after] } proc load_message {file} { @@ -335,7 +335,7 @@ proc load_message {file} { return 0 } -proc read_diff_index {fd final} { +proc read_diff_index {fd after} { global buf_rdi append buf_rdi [read $fd] @@ -361,10 +361,10 @@ proc read_diff_index {fd final} { set buf_rdi {} } - status_eof $fd buf_rdi $final + rescan_done $fd buf_rdi $after } -proc read_diff_files {fd final} { +proc read_diff_files {fd after} { global buf_rdf append buf_rdf [read $fd] @@ -390,10 +390,10 @@ proc read_diff_files {fd final} { set buf_rdf {} } - status_eof $fd buf_rdf $final + rescan_done $fd buf_rdf $after } -proc read_ls_others {fd final} { +proc read_ls_others {fd after} { global buf_rlo append buf_rlo [read $fd] @@ -402,18 +402,18 @@ proc read_ls_others {fd final} { foreach p [lrange $pck 0 end-1] { display_file $p _O } - status_eof $fd buf_rlo $final + rescan_done $fd buf_rlo $after } -proc status_eof {fd buf final} { - global status_active ui_status_value +proc rescan_done {fd buf after} { + global rescan_active global file_states repo_config upvar $buf to_clear if {![eof $fd]} return set to_clear {} close $fd - if {[incr status_active -1] > 0} return + if {[incr rescan_active -1] > 0} return prune_selection unlock_index @@ -434,7 +434,7 @@ proc status_eof {fd buf final} { } reshow_diff - set ui_status_value $final + uplevel #0 $after } proc prune_selection {} { @@ -684,7 +684,7 @@ proc load_last_commit {} { set commit_type amend set HEAD {} set PARENT {} - rescan + rescan {set ui_status_value {Ready.}} } elseif {$parent_count == 1} { set commit_type amend set PARENT $parent @@ -692,7 +692,7 @@ proc load_last_commit {} { $ui_comm insert end $msg $ui_comm edit modified false $ui_comm edit reset - rescan + rescan {set ui_status_value {Ready.}} } else { error_popup {You can't amend a merge commit.} return @@ -720,7 +720,7 @@ repository since our last scan. A rescan is required before committing. } unlock_index - rescan + rescan {set ui_status_value {Ready.}} return } @@ -987,7 +987,7 @@ repository since our last scan. A rescan is required before a pull can be started. } unlock_index - rescan + rescan {set ui_status_value {Ready.}} return } @@ -1024,10 +1024,10 @@ proc post_pull_remote {remote branch success} { if {$success} { repository_state HEAD commit_type set PARENT $HEAD - set $ui_status_value {Ready.} + set $ui_status_value "Pulling $branch from $remote complete." } else { - rescan \ - "Conflicts detected while pulling $branch from $remote." + set m "Conflicts detected while pulling $branch from $remote." + rescan "set ui_status_value {$m}" } } @@ -1115,10 +1115,10 @@ proc merge_state {path new_state} { } proc display_file {path state} { - global file_states file_lists selected_paths status_active + global file_states file_lists selected_paths rescan_active set old_m [merge_state $path $state] - if {$status_active} return + if {$rescan_active > 0} return set s $file_states($path) set new_m [lindex $s 0] @@ -1744,7 +1744,7 @@ proc do_quit {} { } proc do_rescan {} { - rescan + rescan {set ui_status_value {Ready.}} } proc do_include_all {} { @@ -2559,4 +2559,4 @@ if {!$single_commit} { populate_remote_menu .mbar.push To push_to populate_pull_menu .mbar.pull } -after 1 rescan +after 1 do_rescan -- 2.49.0 From 04b393824ff57b5fcb881a00466e513cd4ad2a7f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 14 Nov 2006 01:42:32 -0500 Subject: [PATCH 08/16] git-gui: Allow update_index to also run a script when it completes. Like rescan we also have cases where we need to perform a script after we have finished updating a number of files in the index. By changing the parameter structure of update_index we can easily pass through any script we need to run afterwards, such as picking up in the middle of a commit, or finishing what is left of a rescan. Signed-off-by: Shawn O. Pearce --- git-gui | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/git-gui b/git-gui index 2c8501eebf..be42b91067 100755 --- a/git-gui +++ b/git-gui @@ -428,7 +428,10 @@ proc rescan_done {fd buf after} { } } if {$pathList ne {}} { - update_index $pathList + update_index \ + "Updating included files" \ + $pathList \ + [concat {reshow_diff;} $after] return } } @@ -1197,7 +1200,7 @@ proc display_all_files {} { $ui_other conf -state disabled } -proc update_index {pathList} { +proc update_index {msg pathList after} { global update_index_cp update_index_rsd ui_status_value if {![lock_index update]} return @@ -1210,7 +1213,7 @@ proc update_index {pathList} { if {$batch > 25} {set batch 25} set ui_status_value [format \ - "Including files ... %i/%i files (%.2f%%)" \ + "$msg... %i/%i files (%.2f%%)" \ $update_index_cp \ $totalCnt \ 0.0] @@ -1226,20 +1229,20 @@ proc update_index {pathList} { $pathList \ $totalCnt \ $batch \ + $msg \ + $after \ ] } -proc write_update_index {fd pathList totalCnt batch} { +proc write_update_index {fd pathList totalCnt batch msg after} { global update_index_cp update_index_rsd ui_status_value global file_states ui_fname_value if {$update_index_cp >= $totalCnt} { close $fd unlock_index - set ui_status_value {Ready.} - if {$update_index_rsd} { - reshow_diff - } + if {$update_index_rsd} reshow_diff + uplevel #0 $after return } @@ -1268,7 +1271,7 @@ proc write_update_index {fd pathList totalCnt batch} { } set ui_status_value [format \ - "Including files ... %i/%i files (%.2f%%)" \ + "$msg... %i/%i files (%.2f%%)" \ $update_index_cp \ $totalCnt \ [expr {100.0 * $update_index_cp / $totalCnt}]] @@ -1766,7 +1769,10 @@ proc do_include_all {} { if {$pathList eq {}} { unlock_index } else { - update_index $pathList + update_index \ + "Including all modified files" \ + $pathList \ + {set ui_status_value {Ready to commit.}} } } @@ -1985,7 +1991,10 @@ proc toggle_or_diff {w x y} { $ui_other tag remove in_sel 0.0 end if {$col == 0} { - update_index [list $path] + update_index \ + "Including [short_path $path]" \ + [list $path] \ + {set ui_status_value {Ready.}} } else { show_diff $path $w $lno } -- 2.49.0 From bbe3b3b9b93763ff4eff4fbb638b1c6a4bed8c95 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 15 Nov 2006 18:06:29 -0500 Subject: [PATCH 09/16] git-gui: Automatically update-index all included files before commit. If the user has "Allow Partially Included Files" disabled (and most probably will as its the default setting) we should run update-index on every included file before commit to make sure that any changes made by the user since the last rescan will still be part of this commit. If we don't update-index every modified file the user will likely become confused when part of their changes were committed and other parts weren't; and those other parts won't show up until a later rescan occurs. Since we don't rescan immediately after a commit this may be a while. Signed-off-by: Shawn O. Pearce --- git-gui | 101 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 66 insertions(+), 35 deletions(-) diff --git a/git-gui b/git-gui index be42b91067..9a6953e970 100755 --- a/git-gui +++ b/git-gui @@ -420,7 +420,7 @@ proc rescan_done {fd buf after} { display_all_files if {$repo_config(gui.partialinclude) ne {true}} { - set pathList [list] + set pathList [list] foreach path [array names file_states] { switch -- [lindex $file_states($path) 0] { AM - @@ -703,9 +703,7 @@ proc load_last_commit {} { } proc commit_tree {} { - global tcl_platform HEAD gitdir commit_type file_states - global pch_error - global ui_status_value ui_comm + global HEAD commit_type file_states ui_comm repo_config if {![lock_index update]} return @@ -719,8 +717,10 @@ proc commit_tree {} { error_popup {Last scanned state does not match repository state. Its highly likely that another Git program modified the -repository since our last scan. A rescan is required +repository since the last scan. A rescan is required before committing. + +A rescan will be automatically started now. } unlock_index rescan {set ui_status_value {Ready.}} @@ -731,8 +731,7 @@ before committing. # set files_ready 0 foreach path [array names file_states] { - set s $file_states($path) - switch -glob -- [lindex $s 0] { + switch -glob -- [lindex $file_states($path) 0] { _? {continue} A? - D? - @@ -779,10 +778,39 @@ A good commit message has the following format: return } - # -- Ask the pre-commit hook for the go-ahead. + # -- Update included files if partialincludes are off. # + if {$repo_config(gui.partialinclude) ne {true}} { + set pathList [list] + foreach path [array names file_states] { + switch -glob -- [lindex $file_states($path) 0] { + A? - + M? {lappend pathList $path} + } + } + if {$pathList ne {}} { + unlock_index + update_index \ + "Updating included files" \ + $pathList \ + [concat {lock_index update;} \ + [list commit_prehook $curHEAD $msg]] + return + } + } + + commit_prehook $curHEAD $msg +} + +proc commit_prehook {curHEAD msg} { + global tcl_platform gitdir ui_status_value pch_error + + # On Cygwin [file executable] might lie so we need to ask + # the shell if the hook is executable. Yes that's annoying. + set pchook [file join $gitdir hooks pre-commit] - if {$tcl_platform(platform) eq {windows} && [file isfile $pchook]} { + if {$tcl_platform(platform) eq {windows} + && [file isfile $pchook]} { set pchook [list sh -c [concat \ "if test -x \"$pchook\";" \ "then exec \"$pchook\" 2>&1;" \ @@ -790,21 +818,19 @@ A good commit message has the following format: } elseif {[file executable $pchook]} { set pchook [list $pchook |& cat] } else { - set pchook {} - } - if {$pchook ne {}} { - set ui_status_value {Calling pre-commit hook...} - set pch_error {} - set fd_ph [open "| $pchook" r] - fconfigure $fd_ph -blocking 0 -translation binary - fileevent $fd_ph readable \ - [list commit_stage1 $fd_ph $curHEAD $msg] - } else { - commit_stage2 $curHEAD $msg + commit_writetree $curHEAD $msg + return } + + set ui_status_value {Calling pre-commit hook...} + set pch_error {} + set fd_ph [open "| $pchook" r] + fconfigure $fd_ph -blocking 0 -translation binary + fileevent $fd_ph readable \ + [list commit_prehook_wait $fd_ph $curHEAD $msg] } -proc commit_stage1 {fd_ph curHEAD msg} { +proc commit_prehook_wait {fd_ph curHEAD msg} { global pch_error ui_status_value append pch_error [read $fd_ph] @@ -815,25 +841,24 @@ proc commit_stage1 {fd_ph curHEAD msg} { hook_failed_popup pre-commit $pch_error unlock_index } else { - commit_stage2 $curHEAD $msg + commit_writetree $curHEAD $msg } set pch_error {} - } else { - fconfigure $fd_ph -blocking 0 + return } + fconfigure $fd_ph -blocking 0 } -proc commit_stage2 {curHEAD msg} { +proc commit_writetree {curHEAD msg} { global ui_status_value - # -- Write the tree in the background. - # set ui_status_value {Committing changes...} set fd_wt [open "| git write-tree" r] - fileevent $fd_wt readable [list commit_stage3 $fd_wt $curHEAD $msg] + fileevent $fd_wt readable \ + [list commit_committree $fd_wt $curHEAD $msg] } -proc commit_stage3 {fd_wt curHEAD msg} { +proc commit_committree {fd_wt curHEAD msg} { global single_commit gitdir HEAD PARENT commit_type tcl_platform global ui_status_value ui_comm global file_states selected_paths @@ -1252,14 +1277,20 @@ proc write_update_index {fd pathList totalCnt batch msg after} { set path [lindex $pathList $update_index_cp] incr update_index_cp - switch -- [lindex $file_states($path) 0] { - AM - - _O {set new A*} - _M - - MM {set new M*} + switch -glob -- [lindex $file_states($path) 0] { AD - + MD - _D {set new D*} - default {continue} + + _M - + MM - + M_ {set new M*} + + _O - + AM - + A_ {set new A*} + + ?? {continue} } puts -nonewline $fd $path -- 2.49.0 From e8ab64461968392f126b0a0e2fef4ce8bdcca623 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 15 Nov 2006 18:55:05 -0500 Subject: [PATCH 10/16] git-gui: Disable diff actions when no diff is active. There is no reason why the user should be able to operate on the diff buffer if there is no currently selected diff; likewise the "File:" label text appears rather silly looking all by itself when no diff is being shown in the diff buffer. So now we only enable widgets (like menu items) if there is a diff currently showing, and we disable them when a diff isn't showing. Signed-off-by: Shawn O. Pearce --- git-gui | 186 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 118 insertions(+), 68 deletions(-) diff --git a/git-gui b/git-gui index 9a6953e970..8449664538 100755 --- a/git-gui +++ b/git-gui @@ -455,34 +455,33 @@ proc prune_selection {} { ## diff proc clear_diff {} { - global ui_diff ui_fname_value ui_fstatus_value ui_index ui_other + global ui_diff current_diff ui_index ui_other $ui_diff conf -state normal $ui_diff delete 0.0 end $ui_diff conf -state disabled - set ui_fname_value {} - set ui_fstatus_value {} + set current_diff {} $ui_index tag remove in_diff 0.0 end $ui_other tag remove in_diff 0.0 end } proc reshow_diff {} { - global ui_fname_value ui_status_value file_states + global current_diff ui_status_value file_states - if {$ui_fname_value eq {} - || [catch {set s $file_states($ui_fname_value)}]} { + if {$current_diff eq {} + || [catch {set s $file_states($current_diff)}]} { clear_diff } else { - show_diff $ui_fname_value + show_diff $current_diff } } proc handle_empty_diff {} { - global ui_fname_value file_states file_lists + global current_diff file_states file_lists - set path $ui_fname_value + set path $current_diff set s $file_states($path) if {[lindex $s 0] ne {_M}} return @@ -520,7 +519,7 @@ files list, to prevent possible confusion. proc show_diff {path {w {}} {lno {}}} { global file_states file_lists global PARENT diff_3way diff_active repo_config - global ui_diff ui_fname_value ui_fstatus_value ui_status_value + global ui_diff current_diff ui_status_value if {$diff_active || ![lock_index read]} return @@ -542,8 +541,7 @@ proc show_diff {path {w {}} {lno {}}} { set m [lindex $s 0] set diff_3way 0 set diff_active 1 - set ui_fname_value $path - set ui_fstatus_value [mapdesc $m $path] + set current_diff $path set ui_status_value "Loading diff of [escape_path $path]..." set cmd [list | git diff-index] @@ -1261,7 +1259,7 @@ proc update_index {msg pathList after} { proc write_update_index {fd pathList totalCnt batch msg after} { global update_index_cp update_index_rsd ui_status_value - global file_states ui_fname_value + global file_states current_diff if {$update_index_cp >= $totalCnt} { close $fd @@ -1296,7 +1294,7 @@ proc write_update_index {fd pathList totalCnt batch msg after} { puts -nonewline $fd $path puts -nonewline $fd "\0" display_file $path $new - if {$ui_fname_value eq $path} { + if {$current_diff eq $path} { set update_index_rsd 1 } } @@ -2384,71 +2382,105 @@ pack .vpane.lower.commarea.buffer -side left -fill y # -- Commit Message Buffer Context Menu # -menu $ui_comm.ctxm -tearoff 0 -$ui_comm.ctxm add command -label "Cut" \ +set ctxm .vpane.lower.commarea.buffer.ctxm +menu $ctxm -tearoff 0 +$ctxm add command \ + -label {Cut} \ -font font_ui \ - -command "tk_textCut $ui_comm" -$ui_comm.ctxm add command -label "Copy" \ + -command {tk_textCut $ui_comm} +$ctxm add command \ + -label {Copy} \ -font font_ui \ - -command "tk_textCopy $ui_comm" -$ui_comm.ctxm add command -label "Paste" \ + -command {tk_textCopy $ui_comm} +$ctxm add command \ + -label {Paste} \ -font font_ui \ - -command "tk_textPaste $ui_comm" -$ui_comm.ctxm add command -label "Delete" \ + -command {tk_textPaste $ui_comm} +$ctxm add command \ + -label {Delete} \ -font font_ui \ - -command "$ui_comm delete sel.first sel.last" -$ui_comm.ctxm add separator -$ui_comm.ctxm add command -label "Select All" \ + -command {$ui_comm delete sel.first sel.last} +$ctxm add separator +$ctxm add command \ + -label {Select All} \ -font font_ui \ - -command "$ui_comm tag add sel 0.0 end" -$ui_comm.ctxm add command -label "Copy All" \ + -command {$ui_comm tag add sel 0.0 end} +$ctxm add command \ + -label {Copy All} \ -font font_ui \ - -command " + -command { $ui_comm tag add sel 0.0 end tk_textCopy $ui_comm $ui_comm tag remove sel 0.0 end - " -$ui_comm.ctxm add separator -$ui_comm.ctxm add command -label "Sign Off" \ + } +$ctxm add separator +$ctxm add command \ + -label {Sign Off} \ -font font_ui \ -command do_signoff -bind_button3 $ui_comm "tk_popup $ui_comm.ctxm %X %Y" +bind_button3 $ui_comm "tk_popup $ctxm %X %Y" # -- Diff Header -set ui_fname_value {} -set ui_fstatus_value {} +set current_diff {} +set diff_actions [list] +proc current_diff_trace {varname args} { + global current_diff diff_actions file_states + if {$current_diff eq {}} { + set s {} + set f {} + set p {} + set o disabled + } else { + set p $current_diff + set s [mapdesc [lindex $file_states($p) 0] $p] + set f {File:} + set p [escape_path $p] + set o normal + } + + .vpane.lower.diff.header.status configure -text $s + .vpane.lower.diff.header.file configure -text $f + .vpane.lower.diff.header.path configure -text $p + foreach w $diff_actions { + uplevel #0 $w $o + } +} +trace add variable current_diff write current_diff_trace + frame .vpane.lower.diff.header -background orange -label .vpane.lower.diff.header.l4 \ - -textvariable ui_fstatus_value \ +label .vpane.lower.diff.header.status \ -background orange \ -width $max_status_desc \ -anchor w \ -justify left \ -font font_ui -label .vpane.lower.diff.header.l1 -text {File:} \ +label .vpane.lower.diff.header.file \ -background orange \ + -anchor w \ + -justify left \ -font font_ui -set ui_fname .vpane.lower.diff.header.l2 -label $ui_fname \ - -textvariable ui_fname_value \ +label .vpane.lower.diff.header.path \ -background orange \ -anchor w \ -justify left \ -font font_ui -menu $ui_fname.ctxm -tearoff 0 -$ui_fname.ctxm add command -label "Copy" \ +pack .vpane.lower.diff.header.status -side left +pack .vpane.lower.diff.header.file -side left +pack .vpane.lower.diff.header.path -fill x +set ctxm .vpane.lower.diff.header.ctxm +menu $ctxm -tearoff 0 +$ctxm add command \ + -label {Copy} \ -font font_ui \ -command { clipboard clear clipboard append \ -format STRING \ -type STRING \ - -- $ui_fname_value + -- $current_diff } -bind_button3 $ui_fname "tk_popup $ui_fname.ctxm %X %Y" -pack .vpane.lower.diff.header.l4 -side left -pack .vpane.lower.diff.header.l1 -side left -pack $ui_fname -fill x +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +bind_button3 .vpane.lower.diff.header.path "tk_popup $ctxm %X %Y" # -- Diff Body frame .vpane.lower.diff.body @@ -2478,48 +2510,63 @@ $ui_diff tag conf bold -font font_diffbold # -- Diff Body Context Menu # -menu $ui_diff.ctxm -tearoff 0 -$ui_diff.ctxm add command -label "Copy" \ +set ctxm .vpane.lower.diff.body.ctxm +menu $ctxm -tearoff 0 +$ctxm add command \ + -label {Copy} \ -font font_ui \ - -command "tk_textCopy $ui_diff" -$ui_diff.ctxm add command -label "Select All" \ + -command {tk_textCopy $ui_diff} +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +$ctxm add command \ + -label {Select All} \ -font font_ui \ - -command "$ui_diff tag add sel 0.0 end" -$ui_diff.ctxm add command -label "Copy All" \ + -command {$ui_diff tag add sel 0.0 end} +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +$ctxm add command \ + -label {Copy All} \ -font font_ui \ - -command " + -command { $ui_diff tag add sel 0.0 end tk_textCopy $ui_diff $ui_diff tag remove sel 0.0 end - " -$ui_diff.ctxm add separator -$ui_diff.ctxm add command -label "Decrease Font Size" \ + } +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +$ctxm add separator +$ctxm add command \ + -label {Decrease Font Size} \ -font font_ui \ -command {incr_font_size font_diff -1} -$ui_diff.ctxm add command -label "Increase Font Size" \ +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +$ctxm add command \ + -label {Increase Font Size} \ -font font_ui \ -command {incr_font_size font_diff 1} -$ui_diff.ctxm add separator -$ui_diff.ctxm add command -label "Show Less Context" \ +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +$ctxm add separator +$ctxm add command \ + -label {Show Less Context} \ -font font_ui \ - -command {if {$ui_fname_value ne {} - && $repo_config(gui.diffcontext) >= 2} { + -command {if {$repo_config(gui.diffcontext) >= 2} { incr repo_config(gui.diffcontext) -1 reshow_diff }} -$ui_diff.ctxm add command -label "Show More Context" \ +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +$ctxm add command \ + -label {Show More Context} \ -font font_ui \ - -command {if {$ui_fname_value ne {}} { + -command { incr repo_config(gui.diffcontext) reshow_diff - }} -$ui_diff.ctxm add separator -$ui_diff.ctxm add command -label {Options...} \ + } +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +$ctxm add separator +$ctxm add command -label {Options...} \ -font font_ui \ -command do_options -bind_button3 $ui_diff "tk_popup $ui_diff.ctxm %X %Y" +bind_button3 $ui_diff "tk_popup $ctxm %X %Y" # -- Status Bar +# set ui_status_value {Initializing...} label .status -textvariable ui_status_value \ -anchor w \ @@ -2530,6 +2577,7 @@ label .status -textvariable ui_status_value \ pack .status -anchor w -side bottom -fill x # -- Load geometry +# catch { set gm $repo_config(gui.geometry) wm geometry . [lindex $gm 0] @@ -2543,6 +2591,7 @@ unset gm } # -- Key Bindings +# bind $ui_comm <$M1B-Key-Return> {do_commit;break} bind $ui_comm <$M1B-Key-i> {do_include_all;break} bind $ui_comm <$M1B-Key-I> {do_include_all;break} @@ -2590,6 +2639,7 @@ unset i set file_lists($ui_index) [list] set file_lists($ui_other) [list] +set current_diff {} wm title . "$appname ([file normalize [file dirname $gitdir]])" focus -force $ui_comm -- 2.49.0 From b3678bacbcd2dc0e1c61fd91f4146d0c037e626f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 15 Nov 2006 20:04:17 -0500 Subject: [PATCH 11/16] git-gui: Created makefile to install the program. Since we want to be installed in gitexecdir so that "git gui" works we can guess where that directory is by asking the git wrapper executable and locating ourselves at the same location using the same install rules as core git. Signed-off-by: Shawn O. Pearce --- Makefile | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..e3e871f7c4 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +all: git-gui + +gitexecdir := $(shell git --exec-path) +INSTALL = install + +DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) +gitexecdir_SQ = $(subst ','\'',$(gitexecdir)) + +GITGUI_BUILTIN = git-citool + +install: all + $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(INSTALL) git-gui '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(foreach p,$(GITGUI_BUILTIN), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) -- 2.49.0 From fbee8500a5b64a1c0c6103232879bcecc30f64b4 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 15 Nov 2006 22:13:45 -0500 Subject: [PATCH 12/16] git-gui: Correctly handle GIT_DIR environment variable. Some users may want to start us by running "git --git-dir=... gui" rather than trying to cd into the directory first. This is especially true if they want to just make a shortcut to our executable on Windows and always have that associated with a certain repository. Since Tcl on Windows throws away our environment and doesn't pass it down to the child process correctly we cannot call git-rev-parse to get the GIT_DIR environment variable. So instead we ask for it specifically ourselves; if its not defined then we ask rev-parse. This should actually reduce startup by 1 fork/exec if we were started as "git gui" as GIT_DIR will be set for us. Signed-off-by: Shawn O. Pearce --- git-gui | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/git-gui b/git-gui index 8449664538..7c2f803fec 100755 --- a/git-gui +++ b/git-gui @@ -161,16 +161,17 @@ proc info_popup {msg} { ## ## repository setup -if { [catch {set cdup [exec git rev-parse --show-cdup]} err] - || [catch {set gitdir [exec git rev-parse --git-dir]} err]} { +if { [catch {set gitdir $env(GIT_DIR)}] + && [catch {set gitdir [exec git rev-parse --git-dir]} err]} { catch {wm withdraw .} error_popup "Cannot find the git directory:\n\n$err" exit 1 } -if {$cdup ne ""} { - cd $cdup +if {[catch {cd [file dirname $gitdir]} err]} { + catch {wm withdraw .} + error_popup "No working directory [file dirname $gitdir]:\n\n$err" + exit 1 } -unset cdup set single_commit 0 if {$appname eq {git-citool}} { -- 2.49.0 From 4aca740b3915b35d7fa1707be79b268b0cc94123 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 15 Nov 2006 22:35:26 -0500 Subject: [PATCH 13/16] git-gui: Create Windows shortcut icons for git-gui. If we are running on Windows we now offer a 'Create Desktop Icon' menu item under the Project menu. This pops up a save dialog box letting the user create a .bat file on their desktop (or somewhere else). The .bat script will startup Cygwin with a login shell then launch git-gui in the current working directory. This is very useful for Windows users who have little to no desire to start a command window just to run a git-gui session. Signed-off-by: Shawn O. Pearce --- git-gui | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/git-gui b/git-gui index 7c2f803fec..def6a5e070 100755 --- a/git-gui +++ b/git-gui @@ -2002,6 +2002,54 @@ proc do_save_config {w} { destroy $w } +proc do_windows_shortcut {} { + global gitdir appname argv0 + + set reponame [lindex [file split \ + [file normalize [file dirname $gitdir]]] \ + end] + + if {[catch { + set desktop [exec cygpath \ + --windows \ + --absolute \ + --long-name \ + --desktop] + }]} { + set desktop . + } + set fn [tk_getSaveFile \ + -parent . \ + -title "$appname ($reponame): Create Desktop Icon" \ + -initialdir $desktop \ + -initialfile "Git $reponame.bat"] + if {$fn != {}} { + if {[catch { + set fd [open $fn w] + set sh [exec cygpath \ + --windows \ + --absolute \ + --long-name \ + /bin/sh] + set me [exec cygpath \ + --unix \ + --absolute \ + $argv0] + set gd [exec cygpath \ + --unix \ + --absolute \ + $gitdir] + puts -nonewline $fd "\"$sh\" --login -c \"" + puts -nonewline $fd "GIT_DIR=\\\"$gd\\\"" + puts -nonewline $fd " \\\"$me\\\"" + puts $fd "&\"" + close $fd + } err]} { + error_popup "Cannot write script:\n\n$err" + } + } +} + proc toggle_or_diff {w x y} { global file_lists ui_index ui_other global last_clicked selected_paths @@ -2168,6 +2216,13 @@ if {!$single_commit} { .mbar.project add command -label {Repack Database} \ -command do_repack \ -font font_ui + + if {$tcl_platform(platform) eq {windows}} { + .mbar.project add command \ + -label {Create Desktop Icon} \ + -command do_windows_shortcut \ + -font font_ui + } } .mbar.project add command -label Quit \ -command do_quit \ -- 2.49.0 From dbccbbda4f4c049552495a87b1747b1b2a1e2823 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 15 Nov 2006 22:45:33 -0500 Subject: [PATCH 14/16] git-gui: Protect ourselves from funny GIT_DIR/working directory setups. Since we have some serious problems with the GIT_DIR environment variable on Windows we cannot let the user use a non-standard GIT_DIR with their working directory. So require that the GIT_DIR name is actually ".git", that it exists, and that its parent directory is our working directory. Signed-off-by: Shawn O. Pearce --- git-gui | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/git-gui b/git-gui index def6a5e070..c35c73c8c3 100755 --- a/git-gui +++ b/git-gui @@ -167,6 +167,16 @@ if { [catch {set gitdir $env(GIT_DIR)}] error_popup "Cannot find the git directory:\n\n$err" exit 1 } +if {![file isdirectory $gitdir]} { + catch {wm withdraw .} + error_popup "Git directory not found:\n\n$gitdir" + exit 1 +} +if {[lindex [file split $gitdir] end] ne {.git}} { + catch {wm withdraw .} + error_popup "Cannot use funny .git directory:\n\n$gitdir" + exit 1 +} if {[catch {cd [file dirname $gitdir]} err]} { catch {wm withdraw .} error_popup "No working directory [file dirname $gitdir]:\n\n$err" @@ -2040,8 +2050,8 @@ proc do_windows_shortcut {} { --absolute \ $gitdir] puts -nonewline $fd "\"$sh\" --login -c \"" - puts -nonewline $fd "GIT_DIR=\\\"$gd\\\"" - puts -nonewline $fd " \\\"$me\\\"" + puts -nonewline $fd "GIT_DIR='$gd'" + puts -nonewline $fd " '$me'" puts $fd "&\"" close $fd } err]} { -- 2.49.0 From 306500fc09e7d8be042e8b9abbd9011b80b3300d Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 15 Nov 2006 22:53:53 -0500 Subject: [PATCH 15/16] git-gui: Handle ' within paths when creating Windows shortcuts. Signed-off-by: Shawn O. Pearce --- git-gui | 2 ++ 1 file changed, 2 insertions(+) diff --git a/git-gui b/git-gui index c35c73c8c3..013f21b2e8 100755 --- a/git-gui +++ b/git-gui @@ -2049,6 +2049,8 @@ proc do_windows_shortcut {} { --unix \ --absolute \ $gitdir] + regsub -all ' $me "'\\''" me + regsub -all ' $gd "'\\''" gd puts -nonewline $fd "\"$sh\" --login -c \"" puts -nonewline $fd "GIT_DIR='$gd'" puts -nonewline $fd " '$me'" -- 2.49.0 From c1237ae288aae7e45a18f3d5097b49451293acfe Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 15 Nov 2006 23:52:20 -0500 Subject: [PATCH 16/16] git-gui: Only populate a fetch or push if we have an action. Don't offer to fetch from a remote unless we have at least one Pull: line in its .git/remotes/ file or at least one configuration value for remote..fetch. Ditto for push. Users shouldn't be fetching or pushing branch groups unless they have them configured; anything else is just crazy. Signed-off-by: Shawn O. Pearce --- git-gui | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/git-gui b/git-gui index 013f21b2e8..ea60e327ea 100755 --- a/git-gui +++ b/git-gui @@ -1343,13 +1343,65 @@ proc load_all_remotes {} { set all_remotes [lsort -unique $all_remotes] } -proc populate_remote_menu {m pfx op} { - global all_remotes +proc populate_fetch_menu {m} { + global gitdir all_remotes repo_config - foreach remote $all_remotes { - $m add command -label "$pfx $remote..." \ - -command [list $op $remote] \ - -font font_ui + foreach r $all_remotes { + set enable 0 + if {![catch {set a $repo_config(remote.$r.url)}]} { + if {![catch {set a $repo_config(remote.$r.fetch)}]} { + set enable 1 + } + } else { + catch { + set fd [open [file join $gitdir remotes $r] r] + while {[gets $fd n] >= 0} { + if {[regexp {^Pull:[ \t]*([^:]+):} $n]} { + set enable 1 + break + } + } + close $fd + } + } + + if {$enable} { + $m add command \ + -label "Fetch from $r..." \ + -command [list fetch_from $r] \ + -font font_ui + } + } +} + +proc populate_push_menu {m} { + global gitdir all_remotes repo_config + + foreach r $all_remotes { + set enable 0 + if {![catch {set a $repo_config(remote.$r.url)}]} { + if {![catch {set a $repo_config(remote.$r.push)}]} { + set enable 1 + } + } else { + catch { + set fd [open [file join $gitdir remotes $r] r] + while {[gets $fd n] >= 0} { + if {[regexp {^Push:[ \t]*([^:]+):} $n]} { + set enable 1 + break + } + } + close $fd + } + } + + if {$enable} { + $m add command \ + -label "Push to $r..." \ + -command [list push_to $r] \ + -font font_ui + } } } @@ -2713,8 +2765,8 @@ wm title . "$appname ([file normalize [file dirname $gitdir]])" focus -force $ui_comm if {!$single_commit} { load_all_remotes - populate_remote_menu .mbar.fetch From fetch_from - populate_remote_menu .mbar.push To push_to + populate_fetch_menu .mbar.fetch populate_pull_menu .mbar.pull + populate_push_menu .mbar.push } after 1 do_rescan -- 2.49.0