'Does `git add -p` check one-to-one correspondence only MetaHead but not sentences after HunkHeader?

I'm digging into Git code, however, there is mystery.

When I look into https://github.com/git/git/blob/master/add-patch.c#L440-L455, I thought git add -p compares below input and output.

# input
git diff-files -p --no-color

# output
git diff-files -p --color | {something you defined in interactive.diffFilter}

However, it seems they compare only MetaHead(before @@), and doesn't compare after HunkHeaders(@@ and after @@).

# input
❯ git diff-files --no-color -p
diff --git a/src/options/set.rs b/src/options/set.rs
index a9ca6be..1a32706 100644
--- a/src/options/set.rs
+++ b/src/options/set.rs
@@ -196,7 +196,7 @@ pub fn set_options(
         opt.commit_style = "raw".to_string();
         opt.hunk_header_style = "raw".to_string();
         opt.hunk_header_decoration_style = "none".to_string();
-    }
+    } //aa
 }


# output
❯ git diff-files --color -p | delta --color-only
diff --git a/src/options/set.rs b/src/options/set.rs
index a9ca6be..1a32706 100644
--- a/src/options/set.rs
+++ b/src/options/set.rs
@@ -196,7 +196,7 @@ pub fn set_options( hogehogetest
196 ⋮196 │         opt.commit_style = "raw".to_string();
197 ⋮197 │         opt.hunk_header_style = "raw".to_string();
198 ⋮198 │         opt.hunk_header_decoration_style = "none".to_string();
199 ⋮    │-    }
    ⋮199 │+    } //aa
200 ⋮200 │ }

As you see, it's completely different, however, git -c 'interactive.diffFilter=delta --color-only' add -p works.

If I edit output like,

diff --git a/src/options/set.rs b/src/options/set.rs
index a9ca6be..1a32706 100644
--- a/src/options/set.rs
+++ b/src/options/set.rs
   ### <- insert break line
@@ -196,7 +196,7 @@ pub fn set_options(
         opt.commit_style = "raw".to_string();
         opt.hunk_header_style = "raw".to_string();
         opt.hunk_header_decoration_style = "none".to_string();
-    }
+    } //aa
 }

git add -p now errors like below as expected.

fatal: mismatched output from interactive.diffFilter
hint: Your filter must maintain a one-to-one correspondence
hint: between its input and output lines.

I am really curious, why? The Git code I looked for is wrong...?



Solution 1:[1]

Ah, no.

color_p and color_pend was just a line-count-number. They don't look inside, they just compare line-count-number.

Solution 2:[2]

Note that the code changed again for "git add -p"(man) (rewritten in C): it had regressed hunk splitting in some cases, which has been corrected with Git 2.36 (Q2 2022).

See commit 7008ddc, commit d16632f (11 Jan 2022) by Phillip Wood (phillipwood).
(Merged by Junio C Hamano -- gitster -- in commit ec4f70e, 09 Feb 2022)

builtin add -p: fix hunk splitting

Reproted-by: SZEDER Gábor
Signed-off-by: Phillip Wood

The C reimplementation of "add -p" fails to split the last hunk in a file if hunk ends with an addition or deletion without any post context line unless it is the last file to be processed.

To determine whether a hunk can be split a counter is incremented each time a context line follows an insertion or deletion.
If at the end of the hunk the value of this counter is greater than one then the hunk can be split into that number of smaller hunks.

If the last hunk in a file ends with an insertion or deletion then there is no following context line and the counter will not be incremented.
This case is already handled at the end of the loop where counter is incremented if the last hunk ended with an insertion or deletion.

Unfortunately there is no similar check between files (likely because the perl version only ever parses one diff at a time).
Fix this by checking if the last hunk ended with an insertion or deletion when we see the diff header of a new file and extend the existing regression test.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 eeeeeeeeengo
Solution 2 VonC