From fbc0e7ac1479b4262f6090098a4f68c3438aa94b Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 17 Jul 2008 00:12:28 +0400 Subject: Fix pre-commit hooks under MinGW/MSYS Apply the work-around for checking the executable permission of hook files not only on Cygwin, but on Windows in general. Signed-off-by: Alexander Gavrilov Signed-off-by: Shawn O. Pearce diff --git a/git-gui.sh b/git-gui.sh index 940677c..e3b6669 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -473,10 +473,10 @@ proc githook_read {hook_name args} { set pchook [gitdir hooks $hook_name] lappend args 2>@1 - # On Cygwin [file executable] might lie so we need to ask + # On Windows [file executable] might lie so we need to ask # the shell if the hook is executable. Yes that's annoying. # - if {[is_Cygwin]} { + if {[is_Windows]} { upvar #0 _sh interp if {![info exists interp]} { set interp [_which sh] -- cgit v0.10.2-6-g49f6 From 57cae87b77c93e8bdfd11293f11f140ff827269a Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 17 Jul 2008 00:43:48 +0400 Subject: Add options to control the search for copies in blame. On huge repositories, -C -C can be way too slow to be unconditionally enabled, and it can also be useful to control its precision. Signed-off-by: Alexander Gavrilov Signed-off-by: Shawn O. Pearce diff --git a/git-gui.sh b/git-gui.sh index e3b6669..b1ed0ec 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -642,6 +642,8 @@ set default_config(user.email) {} set default_config(gui.matchtrackingbranch) false set default_config(gui.pruneduringfetch) false set default_config(gui.trustmtime) false +set default_config(gui.fastcopyblame) false +set default_config(gui.copyblamethreshold) 40 set default_config(gui.diffcontext) 5 set default_config(gui.commitmsgwidth) 75 set default_config(gui.newbranchtemplate) {} diff --git a/lib/blame.tcl b/lib/blame.tcl index 92fac1b..192505d 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -33,13 +33,6 @@ variable group_colors { #ececec } -# Switches for original location detection -# -variable original_options [list -C -C] -if {[git-version >= 1.5.3]} { - lappend original_options -w ; # ignore indentation changes -} - # Current blame data; cleared/reset on each load # field commit ; # input commit to blame @@ -511,7 +504,6 @@ method _exec_blame {cur_w cur_d options cur_s} { method _read_blame {fd cur_w cur_d} { upvar #0 $cur_d line_data variable group_colors - variable original_options if {$fd ne $current_fd} { catch {close $fd} @@ -684,6 +676,18 @@ method _read_blame {fd cur_w cur_d} { if {[eof $fd]} { close $fd if {$cur_w eq $w_asim} { + # Switches for original location detection + set threshold [get_config gui.copyblamethreshold] + set original_options [list "-C$threshold"] + + if {![is_config_true gui.fastcopyblame]} { + # thorough copy search; insert before the threshold + set original_options [linsert $original_options 0 -C] + } + if {[git-version >= 1.5.3]} { + lappend original_options -w ; # ignore indentation changes + } + _exec_blame $this $w_amov @amov_data \ $original_options \ [mc "Loading original location annotations..."] diff --git a/lib/option.tcl b/lib/option.tcl index 9270512..ffb3f00 100644 --- a/lib/option.tcl +++ b/lib/option.tcl @@ -123,6 +123,8 @@ proc do_options {} { {b gui.trustmtime {mc "Trust File Modification Timestamps"}} {b gui.pruneduringfetch {mc "Prune Tracking Branches During Fetch"}} {b gui.matchtrackingbranch {mc "Match Tracking Branches"}} + {b gui.fastcopyblame {mc "Blame Copy Only On Changed Files"}} + {i-20..200 gui.copyblamethreshold {mc "Minimum Letters To Blame Copy On"}} {i-0..99 gui.diffcontext {mc "Number of Diff Context Lines"}} {i-0..99 gui.commitmsgwidth {mc "Commit Message Text Width"}} {t gui.newbranchtemplate {mc "New Branch Name Template"}} -- cgit v0.10.2-6-g49f6 From e6131d30c21d2c308571078729dc8d2e1b746285 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 17 Jul 2008 00:48:08 +0400 Subject: Kill the blame back-end on window close. Currently 'git-gui blame' does not kill its back-end process, hoping that it will die anyway when the pipe is closed. However, in some cases the process works for a long time without producing any output. This behavior results in a runaway CPU hog. Signed-off-by: Alexander Gavrilov Signed-off-by: Shawn O. Pearce diff --git a/git-gui.sh b/git-gui.sh index b1ed0ec..83e2645 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -497,6 +497,20 @@ proc githook_read {hook_name args} { return {} } +proc kill_file_process {fd} { + set process [pid $fd] + + catch { + if {[is_Windows]} { + # Use a Cygwin-specific flag to allow killing + # native Windows processes + exec kill -f $process + } else { + exec kill $process + } + } +} + proc sq {value} { regsub -all ' $value "'\\''" value return "'$value'" diff --git a/lib/blame.tcl b/lib/blame.tcl index 192505d..2c19048 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -326,19 +326,27 @@ constructor new {i_commit i_path} { bind $w.file_pane \ "if {{$w.file_pane} eq {%W}} {[cb _resize %h]}" + wm protocol $top WM_DELETE_WINDOW "destroy $top" + bind $top [cb _kill] + _load $this {} } +method _kill {} { + if {$current_fd ne {}} { + kill_file_process $current_fd + catch {close $current_fd} + set current_fd {} + } +} + method _load {jump} { variable group_colors _hide_tooltip $this if {$total_lines != 0 || $current_fd ne {}} { - if {$current_fd ne {}} { - catch {close $current_fd} - set current_fd {} - } + _kill $this foreach i $w_columns { $i conf -state normal -- cgit v0.10.2-6-g49f6 From a01fe996a2f70b759b4d94bd3e9985a01d514ad7 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 17 Jul 2008 00:51:20 +0400 Subject: Add a menu item to invoke full copy detection in blame. Add a context menu item to invoke blame -C -C -C on a chunk of the file. The results are used to update the 'original location' column of the blame display. The chunk is computed as the smallest line range that covers both the 'last change' and 'original location' ranges of the line that was clicked to open the menu. Signed-off-by: Alexander Gavrilov Signed-off-by: Shawn O. Pearce diff --git a/lib/blame.tcl b/lib/blame.tcl index 2c19048..b6e42cb 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -256,6 +256,9 @@ constructor new {i_commit i_path} { $w.ctxm add command \ -label [mc "Copy Commit"] \ -command [cb _copycommit] + $w.ctxm add command \ + -label [mc "Do Full Copy Detection"] \ + -command [cb _fullcopyblame] foreach i $w_columns { for {set g 0} {$g < [llength $group_colors]} {incr g} { @@ -708,6 +711,72 @@ method _read_blame {fd cur_w cur_d} { } } ifdeleted { catch {close $fd} } +method _find_commit_bound {data_list start_idx delta} { + upvar #0 $data_list line_data + set pos $start_idx + set limit [expr {[llength $line_data] - 1}] + set base_commit [lindex $line_data $pos 0] + + while {$pos > 0 && $pos < $limit} { + set new_pos [expr {$pos + $delta}] + if {[lindex $line_data $new_pos 0] ne $base_commit} { + return $pos + } + + set pos $new_pos + } + + return $pos +} + +method _fullcopyblame {} { + if {$current_fd ne {}} { + tk_messageBox \ + -icon error \ + -type ok \ + -title [mc "Busy"] \ + -message [mc "Annotation process is already running."] + + return + } + + # Switches for original location detection + set threshold [get_config gui.copyblamethreshold] + set original_options [list -C -C "-C$threshold"] + + if {[git-version >= 1.5.3]} { + lappend original_options -w ; # ignore indentation changes + } + + # Find the line range + set pos @$::cursorX,$::cursorY + set lno [lindex [split [$::cursorW index $pos] .] 0] + set min_amov_lno [_find_commit_bound $this @amov_data $lno -1] + set max_amov_lno [_find_commit_bound $this @amov_data $lno 1] + set min_asim_lno [_find_commit_bound $this @asim_data $lno -1] + set max_asim_lno [_find_commit_bound $this @asim_data $lno 1] + + if {$min_asim_lno < $min_amov_lno} { + set min_amov_lno $min_asim_lno + } + + if {$max_asim_lno > $max_amov_lno} { + set max_amov_lno $max_asim_lno + } + + lappend original_options -L "$min_amov_lno,$max_amov_lno" + + # Clear lines + for {set i $min_amov_lno} {$i <= $max_amov_lno} {incr i} { + lset amov_data $i [list ] + } + + # Start the back-end process + _exec_blame $this $w_amov @amov_data \ + $original_options \ + [mc "Running thorough copy detection..."] +} + method _click {cur_w pos} { set lno [lindex [split [$cur_w index $pos] .] 0] _showcommit $this $cur_w $lno -- cgit v0.10.2-6-g49f6 From 15430be5a1d17b888b45b608daab7573f24cf9f1 Mon Sep 17 00:00:00 2001 From: Abhijit Menon-Sen Date: Thu, 24 Jul 2008 18:58:53 +0530 Subject: git-gui: Look for gitk in $PATH, not $LIBEXEC/git-core Signed-off-by: Abhijit Menon-Sen Signed-off-by: Shawn O. Pearce diff --git a/git-gui.sh b/git-gui.sh index 83e2645..7c27a43 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -1686,10 +1686,10 @@ proc do_gitk {revs} { # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. # - set exe [file join [file dirname $::_git] gitk] + set exe [_which gitk] set cmd [list [info nameofexecutable] $exe] - if {! [file exists $exe]} { - error_popup [mc "Unable to start gitk:\n\n%s does not exist" $exe] + if {$exe eq {}} { + error_popup [mc "Couldn't find gitk in PATH"] } else { global env -- cgit v0.10.2-6-g49f6 From 7838d3fb41ed7d738e2cbdf8e4f40f0367f4f46f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 25 Jul 2008 15:08:33 -0700 Subject: git-gui: Correct 'Visualize Branches' on Mac OS X to start gitk In Git 1.6 and later gitk is in $prefix/bin while git-gui and all of the other commands are in $gitexecdir, which is typically not the same as $prefix/bin. So we cannot launch $gitexecdir/gitk and expect it to actually start gitk properly. By allowing git-gui to locate the script via $PATH and then using exactly that path when we source it during the application start we can correctly run gitk on any Git 1.5 or later. Signed-off-by: Shawn O. Pearce diff --git a/macosx/AppMain.tcl b/macosx/AppMain.tcl index 41ca08e..ddbe633 100644 --- a/macosx/AppMain.tcl +++ b/macosx/AppMain.tcl @@ -7,7 +7,7 @@ if {[string first -psn [lindex $argv 0]] == 0} { } if {[file tail [lindex $argv 0]] eq {gitk}} { - set argv0 [file join $gitexecdir gitk] + set argv0 [lindex $argv 0] set AppMain_source $argv0 } else { set argv0 [file join $gitexecdir [file tail [lindex $argv 0]]] -- cgit v0.10.2-6-g49f6 From fa6b5b3944b74f2ad2430f3dfec517f8f70a6663 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 15 Jul 2008 23:11:00 +0200 Subject: git-gui: Fix "Stage/Unstage Line" with one line of context. To "Stage/Unstage Line" we construct a patch that contains exactly one change (either addition or removal); the hunk header was forged by counting the old side and adjusting the count by +/-1 for the new side. But when we counted the context we never counted the changed line itself. If the hunk had only one removal line and one line of context, like this: @@ -1,3 +1,2 @@ context 1 -removal context 2 We had constructed this patch: @@ -1,2 +1,1 @@ context 1 -removal context 2 which does not apply because git apply deduces that it must apply at the end of the file. ("context 2" is considered garbage and ignored.) The fix is that removal lines must be counted towards the context of the old side. Signed-off-by: Johannes Sixt Signed-off-by: Shawn O. Pearce diff --git a/lib/diff.tcl b/lib/diff.tcl index 96ba949..ee7f391 100644 --- a/lib/diff.tcl +++ b/lib/diff.tcl @@ -423,6 +423,9 @@ proc apply_line {x y} { # the line to stage/unstage set ln [$ui_diff get $i_l $next_l] set patch "$patch$ln" + if {$c1 eq {-}} { + set n [expr $n+1] + } } elseif {$c1 ne {-} && $c1 ne {+}} { # context line set ln [$ui_diff get $i_l $next_l] -- cgit v0.10.2-6-g49f6 From c7f7457026dc2f6979842f81cc17098579fec8d8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 17 Jul 2008 15:21:51 +0200 Subject: git-gui: "Stage Line": Treat independent changes in adjacent lines better Assume that we want to commit these states: Old state == HEAD Intermediate state New state -------------------------------------------------------- context before context before context before old 1 new 1 new 1 old 2 old 2 new 2 context after context after context after that is, want to commit two changes in this order: 1. transform "old 1" into "new 1" 2. transform "old 2" into "new 2" [This discussion and this patch is about this very case and one other case as outlined below; any other intermediate states that one could imagine are not affected by this patch.] Now assume further, that we have not staged and commited anything, but we have already changed the working file to the new state. Then we will see this hunk in the "Unstaged Changes": @@ -1,4 +1,4 @@ context before -old 1 -old 2 +new 1 +new 2 context after The obvious way to stage the intermediate state is to apply "Stage This Line" to "-old 1" and "+new 1". Unfortunately, this resulted in this intermediate state: context before old 2 new 1 context after which is not what we wanted. In fact, it was impossible to stage the intermediate state using "Stage Line". The crux was that if a "+" line was staged, then the "-" lines were converted to context lines and arranged *before* the "+" line in the forged hunk that we fed to 'git apply'. With this patch we now treat "+" lines that are staged differently. In particular, the "-" lines before the "+" block are moved *after* the staged "+" line. Now it is possible to get the correct intermediate state by staging "-old 1" and "+new 1". Problem solved. But there is a catch. Noticing that we didn't get the right intermediate state by staging "-old 1" and "+new 1", we could have had the idea to stage the complete hunk and to *unstage* "-old 2" and "+new 2". But... the result is the same. The reason is that there is the exact symmetric problem with unstaging the last "-" and "+" line that are in adjacent blocks of "-" and "+" lines. This patch does *not* change the way in which "-" lines are *unstaged*. Why? Because if we did (i.e. move "+" lines before the "-" line after converting them to context lines), then it would be impossible to stage this intermediate state: context before old 1 new 2 context after that is, it would be impossible to stage the two independet changes in the opposite order. Let's look at this case a bit further: The obvious way to get this intermediate state would be to apply "Stage This Line" to "-old 2" and "+new 2". Before this patch, this worked as expected. With this patch, it does not work as expected, but it can still be achieved by first staging the entire hunk, then *unstaging* "-old 1" and "+new 1". In summary, this patch makes a common case possible, at the expense that a less common case is made more complicated for the user. Signed-off-by: Johannes Sixt Signed-off-by: Shawn O. Pearce diff --git a/lib/diff.tcl b/lib/diff.tcl index ee7f391..77990c5 100644 --- a/lib/diff.tcl +++ b/lib/diff.tcl @@ -411,6 +411,53 @@ proc apply_line {x y} { set hh [lindex [split $hh ,] 0] set hln [lindex [split $hh -] 1] + # There is a special situation to take care of. Consider this hunk: + # + # @@ -10,4 +10,4 @@ + # context before + # -old 1 + # -old 2 + # +new 1 + # +new 2 + # context after + # + # We used to keep the context lines in the order they appear in the + # hunk. But then it is not possible to correctly stage only + # "-old 1" and "+new 1" - it would result in this staged text: + # + # context before + # old 2 + # new 1 + # context after + # + # (By symmetry it is not possible to *un*stage "old 2" and "new 2".) + # + # We resolve the problem by introducing an asymmetry, namely, when + # a "+" line is *staged*, it is moved in front of the context lines + # that are generated from the "-" lines that are immediately before + # the "+" block. That is, we construct this patch: + # + # @@ -10,4 +10,5 @@ + # context before + # +new 1 + # old 1 + # old 2 + # context after + # + # But we do *not* treat "-" lines that are *un*staged in a special + # way. + # + # With this asymmetry it is possible to stage the change + # "old 1" -> "new 1" directly, and to stage the change + # "old 2" -> "new 2" by first staging the entire hunk and + # then unstaging the change "old 1" -> "new 1". + + # This is non-empty if and only if we are _staging_ changes; + # then it accumulates the consecutive "-" lines (after converting + # them to context lines) in order to be moved after the "+" change + # line. + set pre_context {} + set n 0 set i_l [$ui_diff index "$i_l + 1 lines"] set patch {} @@ -422,19 +469,27 @@ proc apply_line {x y} { [$ui_diff compare $the_l < $next_l]} { # the line to stage/unstage set ln [$ui_diff get $i_l $next_l] - set patch "$patch$ln" if {$c1 eq {-}} { set n [expr $n+1] + set patch "$patch$pre_context$ln" + } else { + set patch "$patch$ln$pre_context" } + set pre_context {} } elseif {$c1 ne {-} && $c1 ne {+}} { # context line set ln [$ui_diff get $i_l $next_l] - set patch "$patch$ln" + set patch "$patch$pre_context$ln" set n [expr $n+1] + set pre_context {} } elseif {$c1 eq $to_context} { # turn change line into context line set ln [$ui_diff get "$i_l + 1 chars" $next_l] - set patch "$patch $ln" + if {$c1 eq {-}} { + set pre_context "$pre_context $ln" + } else { + set patch "$patch $ln" + } set n [expr $n+1] } set i_l $next_l -- cgit v0.10.2-6-g49f6