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

Re: [PATCH v3 3/3] correct ce_compare_data() in a middle of a merge

From
Torsten Bögershausen <tboegi@web.de>
Date
Jun 30, 2016, 16:52 UTC
Message-ID
<62eb3d75-126e-427b-8701-d490e80e3501@web.de>
In-Reply-To
<xmqqh9cc55wm.fsf@gitster.mtv.corp.google.com>
On 29.06.16 18:14, Junio C Hamano wrote:
Show 8 quoted lines
> tboegi@web.de writes:
> 
>> From: Torsten Bögershausen <tboegi@web.de>
>>
>> The following didn't work as expected:
> 
> Sorry for being slow (not in response but in understanding), but
> let's examine the expectation first.

Thanks for the patience. There is one detail missing in my description: The check if a file in the working tree is clean:

static int ce_compare_data(const struct cache_entry *ce, struct stat *st)
{
	int match = -1;
	int fd = open(ce->name, O_RDONLY);
	if (fd >= 0) {
		unsigned char sha1[20];
		unsigned flags = HASH_USE_SHA_NOT_PATH;
------------------
Remove the "new feature":
git diff  read-cache.c
diff --git a/read-cache.c b/read-cache.c
index dd98b36..1f951ea 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -170,7 +170,7 @@ static int ce_compare_data(const struct cache_entry *ce, struct stat *st)
 
        if (fd >= 0) {
                unsigned char sha1[20];
-               unsigned flags = HASH_USE_SHA_NOT_PATH;
+               unsigned flags = 0;//HASH_USE_SHA_NOT_PATH;
                memcpy(sha1, ce->sha1, sizeof(sha1));
                if (!index_fd(sha1, fd, st, OBJ_BLOB, ce->name, flags))
                        match = hashcmp(sha1, ce->sha1);

The the problem can be re-produced, and debugged with help of t6038:

not ok 5 - Merge addition of text=auto eol=CRLF


> 
>>  - In a middle of a merge
>>  - merge.renormalize is true,
> 
> gitattributes(5) tells us that this would make a "virtual check-out
> and check-in of all stages", i.e. each of the three blob objects
> involved is run through convert_to_working_tree(), and the result is
> run through convert_to_git().  Now, what are these two operations
> told to do?
> 
>>  - .gitattributes = "* text=auto"
>>  - core.eol = crlf
> 
> git-config(1) tells us that a text file will be checked out with
> CRLF line endings, so convert_to_working_tree() would work that
> way.  Even though core.eol entry in that manual page does not tell
> us anything, presumably convert_to_git() is expected to turn it back
> to LF line endings.
> 
Yes, the git-config(1) may need improvements, but that can go as a later path.

>> Merge a blob with CRLF "first line\r\nsame line\r\n" and a blob
>> with LF "first line\nsame line\n".
I may have written:
Merge a blob with CRLF "first line\r\nsame line\r\n" 
(which is checked out as
"first line\r\nsame line\r\n" 
in the working tree, and therefore clean)
and a blob with LF "first line\nsame line\n".

> 
> The former, when renormalized, should (we are discussing the
> expectation, not necessarily what is done by today's code) be
> processed like this:
> 
>  * Pretend as if blob "first line\r\nsame line\r\n" is in the stage
>    #0 of the index at the path;
>  * Pretend as if the user said "git checkout" that path;
>  * Pretend as if the user then said "git add" that path.
> 
> The checkout process hopefully does not blindly turn LF into CRLF,
> making it "first line \r\r\nsame line\r\rn".  Instead the (virtual)
> working tree file will have "first line\r\nsame line\r\n".
Yes
> 
> Then "git add" should turn that CRLF into LF, which would give us
> "first line\nsame line\n", but because the "safer autocrlf" rule
> prevents it from happening.  The (real) index already has CR in it
> in the blob in stage #2, so the check-in process would (this is not
> describing the ideal, but what is done by today's code) disable
> CRLF->LF conversion.
> 
> Is that the problem you are trying to solve?
Not sure, if that problem isn't already solved.

> 
> If that is the case, I do not see how "don't use stage #2 of the
> real index; use the blob being renormalized instead" would help.
> The blob being renormalized may have CR in it, triggering that
> "safer autocrlf" rule and cause you the same trouble, no?
> 
> To me, it appears that if you consider that the "safer autocrlf" is
> a sensible thing, you _must_ expect that the renormalization would
> not work at all, in the scenario you presented.  Also,
> 
>> The expected result of the merge is "first line\nsame line\n".
> 
> if you expect this, to me, it appears that you need to reject the
> "safer autocrlf", at least during renormalization, as a sensible
> thing.  And if you _are_ to disable the "safer autocrlf" thing, then
> it does not matter what is currently in the index--the conversion
> can happen solely based on the data being converted and the
> configuration and attribute settings.
> 
> So I still do not see why you want to pass "no do not use stage #0
> or stage #2; use this blob instead".  Shouldn't you be just passing
> a bit "don't do the safer autocrlf thing in this convert_to_git()
> call" from renormalization codepath without doing anything else?
> 

This is my understanding:
- git checkout and git add are working as expected:
  LF in blob gives CRLF in the working tree at checkout (if attr says "auto")
  CRLF in blob gives CRLF in the working tree at checkout.
  CRLF in the working tree gives CRLF in the blob at "git add", when
  the new safer CRLF handling says so.

- Merges
 First the working tree is checked, if it is clean.
 I haven't digged deep enough to follow the whole code path,
 but that is what ce_compare_data() does, and it fails in a merge.

 Next thing is that the blobs are merged, and when a blob with CRLF
 is merged with a blob with LF, there are only conflicts :-(
 (Remember that both may have CRLF in the worktree)
 And here renormalize_buffer() comes in (only when "merge.renormalize" is true):
 - convert the blob with convert_to_working_tree_internal() into the working
    tree format (but do it in memory), and back to the "blob":
 - convert_to_git(path, src, len, dst, SAFE_CRLF_RENORMALIZE, NULL);

 Note the the "new safer autocrlf" is suppressed here, because of SAFE_CRLF_RENORMALIZE.
 The result is, that both blobs are now normalized, having LF.
 After that, they are merged.

This is my understanding: there are 2 different things involved in t6038#5:
- check for a clean worktree in ce_compare_data() # fails -> this is the problem to be solved
- When merge.renormalize is true: renormalize the buffers before the blobs are merged # -> works
Previous: Junio C HamanoNext: Junio C Hamano
Message 7 of 24 in “What's cooking in git.git (Jun 2016, #09; Mon, 27)”
  1. Junio C HamanoJun 27, 2016
  2. 0/3 unified auto CRLF handling, V3tboegi@web.de, Jun 28, 2016
  3. 1/3 convert: unify the "auto" handling of CRLFtboegi@web.de, Jun 28, 2016
  4. 2/3 read-cache: factor out get_sha1_from_index() helpertboegi@web.de, Jun 28, 2016
  5. 3/3 correct ce_compare_data() in a middle of a mergetboegi@web.de, Jun 28, 2016
  6. Junio C HamanoJun 29, 2016
  7. Torsten BögershausenJun 30, 2016
  8. Junio C HamanoJul 1, 2016
  9. Torsten BögershausenJul 2, 2016
  10. Junio C HamanoJul 6, 2016
  11. Torsten BögershausenJul 7, 2016
  12. Junio C HamanoJul 7, 2016
  13. Junio C HamanoJul 7, 2016
  14. Torsten BögershausenJul 8, 2016
  15. Junio C HamanoJul 8, 2016
  16. Torsten BögershausenJul 8, 2016
  17. Junio C HamanoJul 8, 2016
  18. Junio C HamanoJul 8, 2016
  19. Junio C HamanoJul 8, 2016
  20. Junio C HamanoJul 8, 2016
  21. Junio C HamanoJul 11, 2016
  22. Torsten BögershausenJul 12, 2016
  23. Junio C HamanoJul 12, 2016
  24. Torsten BögershausenJul 8, 2016

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.