If the index update machinery and git diff happen to disagree on whether a particular file is modified, it may cause git-gui to enter an infinite index rescan loop, where an empty diff starts a rescan, which finds the same set of files modified, and tries to display the diff for the first one, which happens to be the empty one. A current example of a possible disagreement point is the autocrlf filter. This patch breaks the loop by using a global variable to track the auto-rescans. The variable is reset whenever a non-empty diff is displayed. As a way to work around the malfunctioning index rescan command, it resurrects the pre-0.6.0 code that directly updates only the affected file. Signed-off-by: Alexander Gavrilov <angavrilov@xxxxxxxxx> --- Note that if the file is actually modified, and the bug is either in git-diff or the way git-gui calls it, this patch will stage the file without displaying it in the UI. Thus, it may be better to simply do nothing if the loop prevention logic triggers. On Jan 22, 11:31 pm, kbro <kevin.broa...@xxxxxxxxxxxxxx> wrote: > However, for me it was worse as the "No differences" message popped up > as soon as I opened git-gui, and the dialog said it would run a rescan > to find all files in a similar state. The rescan caused the same > error to be detected again, so I could never get the dialog box to go > away. On Friday 23 January 2009 02:56:23 Andy Davey wrote: > I had the exact same problem you described running git-1.6.1- > preview20081227 on Windows XP as well. (the endless loop of dialog box > is very frustrating). P.S. Steps to reproduce the autocrlf handling mismatch on Linux: $ git init $ echo > foo $ git add foo && git commit -m init $ unix2dos -o foo $ git config core.autocrlf true $ git status # On branch master # Changed but not updated: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: foo # no changes added to commit (use "git add" and/or "git commit -a") $ git diff foo diff --git a/foo b/foo It happens because git-status assumes that a change in file size always means that the file contents have changed. Content filters like autocrlf may invalidate this assumption. lib/diff.tcl | 16 +++++++++++++++- 1 files changed, 15 insertions(+), 1 deletions(-) diff --git a/lib/diff.tcl b/lib/diff.tcl index bbbf15c..e5abb49 100644 --- a/lib/diff.tcl +++ b/lib/diff.tcl @@ -51,6 +51,7 @@ proc force_diff_encoding {enc} { proc handle_empty_diff {} { global current_diff_path file_states file_lists + global last_empty_diff set path $current_diff_path set s $file_states($path) @@ -66,7 +67,17 @@ A rescan will be automatically started to find other files which may have the sa clear_diff display_file $path __ - rescan ui_ready 0 + + if {![info exists last_empty_diff]} { + set last_empty_diff $path + rescan ui_ready 0 + } else { + # We already tried rescanning recently, and it failed, + # so resort to updating this particular file. + if {[catch {git update-index -- $path} err]} { + error_popup [mc "Failed to refresh index:\n\n%s" $err] + } + } } proc show_diff {path w {lno {}} {scroll_pos {}} {callback {}}} { @@ -310,6 +321,7 @@ proc read_diff {fd cont_info} { global ui_diff diff_active global is_3way_diff is_conflict_diff current_diff_header global current_diff_queue + global last_empty_diff $ui_diff conf -state normal while {[gets $fd line] >= 0} { @@ -415,6 +427,8 @@ proc read_diff {fd cont_info} { if {[$ui_diff index end] eq {2.0}} { handle_empty_diff + } else { + catch { unset last_empty_diff } } set callback [lindex $cont_info 1] if {$callback ne {}} { -- 1.6.1.63.g950db -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html