{"thread":{"id":"61843","subject":"Bug: Git GUI \"No differences detected\"","startedAt":"2024-07-25T10:38:23Z","lastAt":"2024-12-21T13:52:55Z","messageCount":4,"participants":["Steve","Johannes Sixt"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"499329","messageId":"CAAQS9UL14d_LxTKFMghGvQQWS6dfj1RhTJYyKsz0PKoFot8v5w@mail.gmail.com","threadId":"61843","inReplyTo":null,"subject":"Bug: Git GUI \"No differences detected\"","fromName":"Steve","fromEmail":"steves.sk@gmail.com","sentAt":"2024-07-25T10:37:44Z","receivedAt":"2024-07-25T10:38:23Z","isPatch":false,"sender":{"key":"steves.sk@gmail.com","avatar":null},"body":"Hi, I want to ask you about a bug that Git has had for years. It's\ntracked on pages like\nhttps://stackoverflow.com/questions/57556917/git-gui-no-diffferences-detected\nbut I still haven't been able to find a solution to prevent this from\noccurring.\n\nProblem:\nGit GUI shows a \"No differences detected\" popup when clicking on a\nfile, and it returns back to the same state after closing the popup.\nWhen I do `git status`, the file is listed there, but `git diff` (with\nany line-ending-related switches inspired by stackoverflow) doesn't\nshow anything for the file.\n\nCause:\nI assume it's typically due to LF/CRLF changes.\n\nWorkaround:\nManually add the file, which makes the diff disappear.\n\nComplaint:\nIt's extremely annoying to click so many times on GUI for every such\nfile. Files have to be frequently added just to satisfy the status\ncheck, really disrupting your workflow when preparing commits and\nreviewing diffs one by one.\n\nAttempted settings:\nI tried all the autocrlf options, and even fileMode (though I'm on\nWindows); nothing helps to remove the file from status...\n\nReasons triggering the symptom:\nI have some application that periodically modifies tracked files in\nsome way, causing this issue to regularly re-appear for the same set\nof files. Over the years, I had it happen from various sources, it's\none of the issues that follows you the entire life...\n\nRequest:\nIt needs to be recognized as a frequently occurring bug that doesn't\nhave a permanent solution yet. It should be fixed either on the Git\nGUI side by automatically hiding these files (or at least hiding the\nannoying pop-up), or the git status itself could recognize that the\nfile has in fact not changed. If there is any actual change in the\nline endings, its diff should be displayed, because that would be\ndefinitely an actual modification to the file, which we may want to\nreview and push upstream. The current design of hiding CR/LF changes\nfrom a user is flawed anyway.\n\nThanks, I'm really hoping this can be officially tracked and reported\non; a reliance on StackOverflow articles as an issue tracker is\ninsufficient and hides our sentiment of how many hours of productivity\nwe're wasting on it.\n"},{"id":"499638","messageId":"2d7d6b38-b3f1-45f5-a6f0-54bd8a0d64d0@kdbg.org","threadId":"61843","inReplyTo":"CAAQS9UL14d_LxTKFMghGvQQWS6dfj1RhTJYyKsz0PKoFot8v5w@mail.gmail.com","subject":"Re: Bug: Git GUI \"No differences detected\"","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2024-07-30T19:27:45Z","receivedAt":"2024-07-30T20:02:22Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 25.07.24 um 12:37 schrieb Steve:\n> Problem:\n> Git GUI shows a \"No differences detected\" popup when clicking on a\n> file, and it returns back to the same state after closing the popup.\n> When I do `git status`, the file is listed there, but `git diff` (with\n> any line-ending-related switches inspired by stackoverflow) doesn't\n> show anything for the file.\n> \n> Cause:\n> I assume it's typically due to LF/CRLF changes.\n> \n> Workaround:\n> Manually add the file, which makes the diff disappear.\n\nBack in 2006, the only case where a file could be listed as modified,\nbut then not have any changes was when the timestamp (and perhaps other\nstat information) was modified, but not the content. Such false\npositives can be rectified by running git update-index --refresh,\ntherefore, Git GUI does so by default. For this reason, users generally\ndo not see false positives in the unstaged files list.\n\nHowever, in large repositories git update-index --refresh can be so\nexpensive that it becomes annoying. For this reason, the option \"trust\nfile modification times\" was invented that, when enabled, skips this\nexpensive step. On the flip side, there can now be files listed as\nmodified that are actually not. As a work-around, the popup message was\ninvented to notify the user that a --refresh step is performed to remove\nall false positives.\n\nThis worked sufficiently well. Until core.autocrlf was invented in 2007.\n\nEnabling this option introduced a new case that can trigger false\npositives. But this time, git update-index --refresh does *not* clear\nthe files that are falsly marked as modified. And we end up in the loop\nthat you described and that requires the file to be staged (git add) to\nbe recognized as unmodified.\n\nI suggest the following changes to Git GUI:\n\n1. Remove the popup.\n\n2. Write a message in the diff pane when the diff is empty saying that\nno differences where found and that the file should be staged to remove\nit from the unstaged file list.\n\n3. If the option \"trust file modification times\" is set, extend the\nmessage with an hyperlink that, when clicked, runs the --refresh stage,\ni.e., the action that currently happens when the popup is dismissed.\n\nStep 2 effectively makes the workaround the official solution. Would\nthat work for you?\n\n-- Hannes\n"},{"id":"499686","messageId":"CAAQS9UK7ynd7H6z4_+HN-ayGmR9jG0Aus77TN7rh-_1SCd9=4w@mail.gmail.com","threadId":"61843","inReplyTo":"2d7d6b38-b3f1-45f5-a6f0-54bd8a0d64d0@kdbg.org","subject":"Re: Bug: Git GUI \"No differences detected\"","fromName":"Steve","fromEmail":"steves.sk@gmail.com","sentAt":"2024-07-31T11:01:12Z","receivedAt":"2024-07-31T11:01:51Z","isPatch":false,"sender":{"key":"steves.sk@gmail.com","avatar":null},"body":"Change #2 would still require us to manually stage dozens of files\neach time this happens, so I'm hoping a root cause solution can be\nfound to prevent the changed file from appearing in status at all. But\nyeah, removing the popup would at least reduce the number of clicks by\nhalf.\n\nut 30. 7. 2024 o 21:27 Johannes Sixt <j6t@kdbg.org> napísal(a):\n>\n> Am 25.07.24 um 12:37 schrieb Steve:\n> > Problem:\n> > Git GUI shows a \"No differences detected\" popup when clicking on a\n> > file, and it returns back to the same state after closing the popup.\n> > When I do `git status`, the file is listed there, but `git diff` (with\n> > any line-ending-related switches inspired by stackoverflow) doesn't\n> > show anything for the file.\n> >\n> > Cause:\n> > I assume it's typically due to LF/CRLF changes.\n> >\n> > Workaround:\n> > Manually add the file, which makes the diff disappear.\n>\n> Back in 2006, the only case where a file could be listed as modified,\n> but then not have any changes was when the timestamp (and perhaps other\n> stat information) was modified, but not the content. Such false\n> positives can be rectified by running git update-index --refresh,\n> therefore, Git GUI does so by default. For this reason, users generally\n> do not see false positives in the unstaged files list.\n>\n> However, in large repositories git update-index --refresh can be so\n> expensive that it becomes annoying. For this reason, the option \"trust\n> file modification times\" was invented that, when enabled, skips this\n> expensive step. On the flip side, there can now be files listed as\n> modified that are actually not. As a work-around, the popup message was\n> invented to notify the user that a --refresh step is performed to remove\n> all false positives.\n>\n> This worked sufficiently well. Until core.autocrlf was invented in 2007.\n>\n> Enabling this option introduced a new case that can trigger false\n> positives. But this time, git update-index --refresh does *not* clear\n> the files that are falsly marked as modified. And we end up in the loop\n> that you described and that requires the file to be staged (git add) to\n> be recognized as unmodified.\n>\n> I suggest the following changes to Git GUI:\n>\n> 1. Remove the popup.\n>\n> 2. Write a message in the diff pane when the diff is empty saying that\n> no differences where found and that the file should be staged to remove\n> it from the unstaged file list.\n>\n> 3. If the option \"trust file modification times\" is set, extend the\n> message with an hyperlink that, when clicked, runs the --refresh stage,\n> i.e., the action that currently happens when the popup is dismissed.\n>\n> Step 2 effectively makes the workaround the official solution. Would\n> that work for you?\n>\n> -- Hannes\n"},{"id":"509473","messageId":"8fbaa0d6-b7f5-4799-a579-ee9fa72a743d@kdbg.org","threadId":"61843","inReplyTo":"2d7d6b38-b3f1-45f5-a6f0-54bd8a0d64d0@kdbg.org","subject":"Re: Bug: Git GUI \"No differences detected\"","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2024-12-21T13:05:14Z","receivedAt":"2024-12-21T13:52:55Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 30.07.24 um 21:27 schrieb Johannes Sixt:\n> Am 25.07.24 um 12:37 schrieb Steve:\n>> Problem:\n>> Git GUI shows a \"No differences detected\" popup when clicking on a\n>> file, and it returns back to the same state after closing the popup.\n>> When I do `git status`, the file is listed there, but `git diff` (with\n>> any line-ending-related switches inspired by stackoverflow) doesn't\n>> show anything for the file.\n\n> I suggest the following changes to Git GUI:\n> \n> 1. Remove the popup.\n> \n> 2. Write a message in the diff pane when the diff is empty saying that\n> no differences where found and that the file should be staged to remove\n> it from the unstaged file list.\n> \n> 3. If the option \"trust file modification times\" is set, extend the\n> message with an hyperlink that, when clicked, runs the --refresh stage,\n> i.e., the action that currently happens when the popup is dismissed.\n\nJust these days I stumbled over a similar case of 'no differences\ndetect' while I was operating a Git GUI that has the below patch, and it\nworked very well for me. I'll include it in the next release.\n\n---- 8< ----\nFrom: Johannes Sixt <j6t@kdbg.org>\nSubject: [PATCH] git-gui: Remove forced rescan of stat-dirty files.\n\nIt is possible that stat information of tracked files is modified without\nactually modifying the content. Plumbing commands would detect such files\nas modified, so that Git GUI runs `git update-info --refresh` in order to\nsynchronize the cached stat info with the reality. However, this can be\nan expensive operation in large repositories. As remediation,\ne534f3a88676 (git-gui: Allow the user to disable update-index --refresh\nduring rescan, 2006-11-07) introduced an option to skip the expensive\npart.\n\nThe option was named \"trust file modification timestamp\". But the catch\nis that sometimes file timestamps can't be trusted. In this case, a file\nwould remain listed in Unstaged Changes although there are no changes.\nSo 16403d0b1f9d (git-gui: Refresh a file if it has an empty diff,\n2006-11-11) introduced a popup message informing the user about the\nsituation and then removed the file from the Unstaged Changes list.\n\nNow users had to click away the message box for every file that was\nstat-dirty. Under the assumption that a file in such a state is not\nthe only one, 124355d32c06 (git-gui: Always start a rescan on an empty\ndiff, 2007-01-22) introduced a forced (potentially expensive) refresh\nthat would de-list all stat-dirty files after the first notification was\ndismissed.\n\nAlong came 6c510bee2013 (Lazy man's auto-CRLF, 2007-02-13) in Git. It\nintroduced a new case where a file in the worktree can have no essential\ndifferences to the staged version, but still be detected as modified by\nplumbing commands. This time, however, the index cannot be synchronized\nfully by `git update-index --refresh`, so that the file remains listed\nin Unstaged Changes until it is staged manually.\n\nNeedless to say that the message box now becomes an annoyance, because\nit must be dismissed every time an affected file is selected, and the\nfile remains listed nevertheless.\n\nRemove the message box. Write the notice that no differences were found\nin the diff panel instead. Also include a link that, when clicked,\ninitiates the rescan. With this scheme, the rescan does not happen\nautomatically anymore, but requires an additional click. (This is now\ntwo clicks in total for users who encounter stat-dirty files after\nenabling the \"trust file modification timestamps\" option.) However,\nusers whom the rescan does not help (autocrlf-related dirty files) save\nhalf the clicks because there is no message box to dismiss.\n\nSigned-off-by: Johannes Sixt <j6t@kdbg.org>\n---\n git-gui.sh   |  3 ++-\n lib/diff.tcl | 26 ++++++--------------------\n 2 files changed, 8 insertions(+), 21 deletions(-)\n\ndiff --git a/git-gui.sh b/git-gui.sh\nindex 8fe7538..887d6d5 100755\n--- a/git-gui.sh\n+++ b/git-gui.sh\n@@ -1357,7 +1357,6 @@ set current_diff_path {}\n set is_3way_diff 0\n set is_submodule_diff 0\n set is_conflict_diff 0\n-set diff_empty_count 0\n set last_revert {}\n set last_revert_enc {}\n \n@@ -3594,6 +3593,8 @@ $ui_diff tag configure clr1 -font font_diffbold\n $ui_diff tag configure clr4 -underline 1\n \n $ui_diff tag conf d_info -foreground blue -font font_diffbold\n+$ui_diff tag conf d_rescan -foreground blue -underline 1 -font font_diffbold\n+$ui_diff tag bind d_rescan <Button-1> { clear_diff; rescan ui_ready 0 }\n \n $ui_diff tag conf d_cr -elide true\n $ui_diff tag conf d_@ -font font_diffbold\ndiff --git a/lib/diff.tcl b/lib/diff.tcl\nindex 871ad48..d657bfe 100644\n--- a/lib/diff.tcl\n+++ b/lib/diff.tcl\n@@ -63,28 +63,17 @@ proc force_diff_encoding {enc} {\n }\n \n proc handle_empty_diff {} {\n-\tglobal current_diff_path file_states file_lists\n-\tglobal diff_empty_count\n+\tglobal current_diff_path file_states\n+\tglobal ui_diff\n \n \tset path $current_diff_path\n \tset s $file_states($path)\n \tif {[lindex $s 0] ne {_M} || [has_textconv $path]} return\n \n-\t# Prevent infinite rescan loops\n-\tincr diff_empty_count\n-\tif {$diff_empty_count > 1} return\n-\n-\tinfo_popup [mc \"No differences detected.\n-\n-%s has no changes.\n-\n-The modification date of this file was updated by another application, but the content within the file was not changed.\n-\n-A rescan will be automatically started to find other files which may have the same state.\" [short_path $path]]\n-\n-\tclear_diff\n-\tdisplay_file $path __\n-\trescan ui_ready 0\n+\t$ui_diff conf -state normal\n+\t$ui_diff insert end [mc \"* No differences detected; stage the file to de-list it from Unstaged Changes.\\n\"] d_info\n+\t$ui_diff insert end [mc \"* Click to find other files that may have the same state.\\n\"] d_rescan\n+\t$ui_diff conf -state disabled\n }\n \n proc show_diff {path w {lno {}} {scroll_pos {}} {callback {}}} {\n@@ -387,7 +376,6 @@ proc read_diff {fd conflict_size cont_info} {\n \tglobal ui_diff diff_active is_submodule_diff\n \tglobal is_3way_diff is_conflict_diff current_diff_header\n \tglobal current_diff_queue\n-\tglobal diff_empty_count\n \n \t$ui_diff conf -state normal\n \twhile {[gets $fd line] >= 0} {\n@@ -559,8 +547,6 @@ proc read_diff {fd conflict_size cont_info} {\n \n \t\tif {[$ui_diff index end] eq {2.0}} {\n \t\t\thandle_empty_diff\n-\t\t} else {\n-\t\t\tset diff_empty_count 0\n \t\t}\n \n \t\tset callback [lindex $cont_info 1]\n-- \n2.48.0.rc0.201.g092d4fe2cc\n\n"}]}