git/list[1] front-page[2] threads[3] people[4] search[5] about
 

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

From
Alexander Gavrilov <angavrilov@gmail.com>
Date
Feb 7, 2009, 16:24 UTC
Message-ID
<200902071924.02419.angavrilov@gmail.com>

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 counter to track the auto-rescans. The variable is reset whenever a non-empty diff is displayed.

Another suggested approach, which is based on giving the --exit-code argument to git diff, cannot be used, because diff-files seems to trust the timestamps in the index, and returns a non-zero code even if the file is actually unchanged, which essentially defeats the purpose of the auto-rescan logic.

Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>
---
	Apparently git-diff also has a small crlf-related bug.
	It can be reproduced using the following commands:
	$ rm -rf .git *
	$ git init
	$ echo > foo
	$ git add foo && git commit -m init
	$ git diff-files -p --exit-code && echo unchanged
	unchanged
	$ git diff --exit-code && echo unchanged
	unchanged
	$ touch foo
	$ git diff-files -p --exit-code && echo unchanged
	diff --git a/foo b/foo
	$ git diff --exit-code && echo unchanged
	unchanged
	    Without autocrlf git-diff recognizes that
	    the file is unchanged.
	$ rm -rf .git *
	$ git init
	$ git config core.autocrlf true
	$ echo > foo
	$ unix2dos -o foo
	$ git add foo && git commit -m init
	$ git diff-files -p --exit-code && echo unchanged
	unchanged
	$ git diff --exit-code && echo unchanged
	unchanged
	$ touch foo
	$ git diff-files -p --exit-code && echo unchanged
	diff --git a/foo b/foo
	$ git diff --exit-code && echo unchanged
	diff --git a/foo b/foo
	    With crlf it prints an empty diff and says
	    that there are some changes.
	I don't think that this behavior should depend
	on the autocrlf setting.
	-- Alexander
 lib/diff.tcl |    9 +++++++++
 1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/lib/diff.tcl b/lib/diff.tcl
index bbbf15c..925b3f5 100644
--- a/lib/diff.tcl
+++ b/lib/diff.tcl
@@ -51,11 +51,16 @@ proc force_diff_encoding {enc} {
 
 proc handle_empty_diff {} {
 	global current_diff_path file_states file_lists
+	global diff_empty_count
 
 	set path $current_diff_path
 	set s $file_states($path)
 	if {[lindex $s 0] ne {_M}} return
 
+	# Prevent infinite rescan loops
+	incr diff_empty_count
+	if {$diff_empty_count > 1} return
+
 	info_popup [mc "No differences detected.
 
 %s has no changes.
@@ -310,6 +315,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 diff_empty_count
 
 	$ui_diff conf -state normal
 	while {[gets $fd line] >= 0} {
@@ -415,7 +421,10 @@ proc read_diff {fd cont_info} {
 
 		if {[$ui_diff index end] eq {2.0}} {
 			handle_empty_diff
+		} else {
+			set diff_empty_count 0
 		}
+
 		set callback [lindex $cont_info 1]
 		if {$callback ne {}} {
 			eval $callback
-- 
1.6.1.63.g950db
Message 1 of 1 in “git-gui: Avoid an infinite rescan loop in handle_empty_diff.”
  1. git-gui: Avoid an infinite rescan loop in handle_empty_diff.Alexander Gavrilov, Feb 7, 2009

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.