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

Re: [PATCH 0/3] built-in add -p: support diff-so-fancy better

From
Johannes Schindelin <johannes.schindelin@gmx.de>
Date
Aug 24, 2022, 21:05 UTC
Message-ID
<34qs5607-001o-0n6o-rson-9587q8r909qn@tzk.qr>
In-Reply-To
<xmqqmtbt7b5p.fsf@gitster.g>
Hi Junio & Philippe,
On Wed, 24 Aug 2022, Junio C Hamano wrote:
Show 24 quoted lines
> Philippe Blain <levraiphilippeblain@gmail.com> writes:
>
> >>>> However, I've tried it on a more "real-life" example, and then I get:
> >>>>
> >>>>     error: mismatched output from interactive.diffFilter
> >>>>     hint: Your filter must maintain a one-to-one correspondence
> >>>>     hint: between its input and output lines.
> >>>>
> >>>> This is despite using "diff-so-fancy --patch" as interactive.diffFilter, which should
> >>>> keep the number of lines the same.
> >>>
> >>> Would you mind sharing the example with me?
> >>
> >> In trying to write a reproducer, I realize that this is in fact a separate "bug".
> >> I happened to have a submodule in the repository I was testing, and it had modified
> >> content. This is what was causing the "mismatched output" error, although I'm not
> >> sure why. If I use a pathspec that does not include the submodule when invoking
> >> 'git add -p', it works correctly.
> >>
> >> I'm a bit out of time now but I'll try to write a separate
> >> reproducer for this later today.
> >
> > So in trying to write a new reproducer, I found the cause of the
> > bug. ...
Ah. Submodules. The gift that keeps on giving.

I'm not _really_ complaining, though. It seems that with beautiful regularity, submodules come up as crucial parts of attack vectors in exploits that are reported to the git-security mailing list, requiring somebody with my abilities to implement fixes. Therefore, submodules award me with a sort of job security. :-)

> I somehow had an impression that that the C reimplementation was
> designed to be a bug-for-bug compatible faithful rewrite of the
> original scripted version,

Yes, it was designed as that, with a few things done differently, though, such as avoiding unnecessary `git diff` invocations, and using C-native data structures and memory management.

One unfortunate consequence of avoiding the `git diff` invocations of `git-add--interactive.perl` that are not actually necessary is that I missed that one of those invocations specifically ignores dirty submodules, and that the Perl script then only processes files whose numstat shows up in _that_ diff output.

Fortunately, the fix is easy: simply ignore dirty submodules in _all_ `git diff` invocations of `add -p`.

I will submit the next iteration as soon as the PR builds pass.
> but looking at the way how this bug is handled, I am not sure (it looks
> as if the initial fix was to patch the code to match the symptom, not to
> make the code to behave more faithfully to the scripted version).

The built-in `add -p` does something slightly different from the Perl version when it comes to the line ranges in hunk headers: instead of storing stringified versions of them and parsing & re-rendering them when the hunks are modified, the C version stores the actual numbers, adjusts them as needed (e.g. when hunks are split), and, crucially, renders them on the fly when displaying the hunks.

That means that also the colorized hunk headers are generated on the fly whenever the hunks are displayed, and they are never stored in rendered form, neither while parsing diffs nor when hunks are split or otherwise edited. That's why the built-in `add -p` looked for a `@@ ... @@` part in the colorized diff, so that it can display the remainder of that line after showing the rendered line range.

And yes, this is a deviation from the bug-for-bug principle I follow for conversions from scripted commands to built-in C code, but it was for a good reason: memory management in C is less trivial than in Perl (where one essentially YOLOs memory management), and I was not prepared to invent a rope data structure just to be able to replace parts of a long string buffer with rendered text of a different length, nor was I prepared to call `memmove()` tons of times.

Note that the Perl version does something slightly iffy, too: if a diff colorizer is configured, it initially shows the original hunk headers (e.g. "@ file:16 @" in the `diff-so-fancy` case) but when the hunk is modified in any way, it generates "@@ -1,6 +1,7 @@"-style hunk headers and does not show the ones generated by the diff colorizer _at all_ anymore.

In this patch series, I teach the built-in `add -p` to be more lenient and simply show the entire original hunk header after the rendered line range if no `@@ ... @@` part was found. If that part was found, we still replace it with the rendered line range.

Yes, it is a deviation from what the Perl version does. I consider it an improvement, though.

Show 9 quoted lines
> As with any big rewrite, a complete re-implementation always has risks
> to introduce unintended regressions and that is why starting with
> faithful rewrite with the staged transition plan is valuable.
>
> In this case, the staged transition plan, the step to flip the
> default without before remove the old one, is working beautifully.
> And it was only made possible with the actual users reporting issues
> before they say "the new one is broken, so let's use the knob to
> retain the old implementation".

Indeed, and thank you, Philippe, for bringing this to the Git mailing list so that I could do something about the bug.

Ciao, Dscho

Previous: Junio C HamanoNext: Junio C Hamano
Message 10 of 67 in “built-in add -p: support diff-so-fancy better”
  1. 0/3 built-in add -p: support diff-so-fancy betterJohannes Schindelin via GitGitGadget, Aug 23, 2022
  2. 3/3 add -p: handle `diff-so-fancy`'s hunk headers betterJohannes Schindelin via GitGitGadget, Aug 23, 2022
  3. 1/3 t3701: redefine what is "bogus" output of a diff filterJohannes Schindelin via GitGitGadget, Aug 23, 2022
  4. 2/3 add -p: gracefully ignore unparseable hunk headers in colored diffsJohannes Schindelin via GitGitGadget, Aug 23, 2022
  5. Philippe BlainAug 24, 2022
  6. Johannes SchindelinAug 24, 2022
  7. Philippe BlainAug 24, 2022
  8. Philippe BlainAug 24, 2022
  9. Junio C HamanoAug 24, 2022
  10. Johannes SchindelinAug 24, 2022
  11. Junio C HamanoAug 24, 2022
  12. 0/4 built-in add -p: support diff-so-fancy betterJohannes Schindelin via GitGitGadget, Aug 24, 2022
  13. 1/4 t3701: redefine what is "bogus" output of a diff filterJohannes Schindelin via GitGitGadget, Aug 24, 2022
  14. 2/4 add -p: gracefully ignore unparseable hunk headers in colored diffsJohannes Schindelin via GitGitGadget, Aug 24, 2022
  15. Junio C HamanoAug 29, 2022
  16. 3/4 add -p: handle `diff-so-fancy`'s hunk headers betterJohannes Schindelin via GitGitGadget, Aug 24, 2022
  17. Junio C HamanoAug 29, 2022
  18. Johannes SchindelinAug 29, 2022
  19. Junio C HamanoAug 29, 2022
  20. Johannes SchindelinAug 30, 2022
  21. 4/4 add -p: ignore dirty submodulesJohannes Schindelin via GitGitGadget, Aug 24, 2022
  22. Junio C HamanoAug 24, 2022
  23. Philippe BlainAug 25, 2022
  24. Johannes SchindelinAug 26, 2022
  25. Philippe BlainAug 26, 2022
  26. 0/5 built-in add -p: support diff-so-fancy betterJohannes Schindelin via GitGitGadget, Aug 29, 2022
  27. 1/5 t3701: redefine what is "bogus" output of a diff filterJohannes Schindelin via GitGitGadget, Aug 29, 2022
  28. Phillip WoodAug 30, 2022
  29. Junio C HamanoAug 30, 2022
  30. Phillip WoodAug 31, 2022
  31. Jeff KingAug 31, 2022
  32. Jeff KingAug 31, 2022
  33. Johannes SchindelinAug 31, 2022
  34. 2/5 add -p: gracefully ignore unparseable hunk headers in colored diffsJohannes Schindelin via GitGitGadget, Aug 29, 2022
  35. 4/5 add -p: handle `diff-so-fancy`'s hunk headers betterJohannes Schindelin via GitGitGadget, Aug 29, 2022
  36. Phillip WoodAug 30, 2022
  37. 3/5 add -p: insert space in colored hunk header as neededJohannes Schindelin via GitGitGadget, Aug 29, 2022
  38. 5/5 add -p: ignore dirty submodulesJohannes Schindelin via GitGitGadget, Aug 29, 2022
  39. Phillip WoodAug 30, 2022
  40. Johannes SchindelinAug 31, 2022
  41. Junio C HamanoAug 31, 2022
  42. Johannes SchindelinAug 31, 2022
  43. Junio C HamanoAug 29, 2022
  44. Johannes SchindelinAug 30, 2022
  45. Phillip WoodAug 30, 2022
  46. Johannes SchindelinAug 31, 2022
  47. 0/3 built-in add -p: support diff-so-fancy betterJohannes Schindelin via GitGitGadget, Aug 31, 2022
  48. 2/3 add -p: gracefully handle unparseable hunk headers in colored diffsJohannes Schindelin via GitGitGadget, Aug 31, 2022
  49. Phillip WoodSep 1, 2022
  50. Johannes SchindelinSep 1, 2022
  51. 3/3 add -p: ignore dirty submodulesJohannes Schindelin via GitGitGadget, Aug 31, 2022
  52. Jeff KingSep 1, 2022
  53. Jeff KingSep 1, 2022
  54. Junio C HamanoSep 1, 2022
  55. Johannes SchindelinSep 2, 2022
  56. 1/3 add -p: detect more mismatches between plain vs colored diffsJohannes Schindelin via GitGitGadget, Aug 31, 2022
  57. Phillip WoodSep 1, 2022
  58. Phillip WoodSep 1, 2022
  59. Junio C HamanoSep 1, 2022
  60. 0/3 built-in add -p: support diff-so-fancy betterJohannes Schindelin via GitGitGadget, Sep 1, 2022
  61. 1/3 add -p: detect more mismatches between plain vs colored diffsJohannes Schindelin via GitGitGadget, Sep 1, 2022
  62. 3/3 add -p: ignore dirty submodulesJohannes Schindelin via GitGitGadget, Sep 1, 2022
  63. Junio C HamanoSep 1, 2022
  64. 2/3 add -p: gracefully handle unparseable hunk headers in colored diffsJohannes Schindelin via GitGitGadget, Sep 1, 2022
  65. Phillip WoodSep 1, 2022
  66. Phillip WoodSep 1, 2022
  67. Junio C HamanoSep 1, 2022

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.