[RFC PATCH (GIT-GUI/CORE BUG)] git-gui: Avoid an infinite rescan loop in handle_empty_diff.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux