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

Re: [PATCH] fix recursive-merge of empty files with different permissions

From
Johannes Schindelin <johannes.schindelin@gmx.de>
Date
Mar 13, 2008, 15:19 UTC
Message-ID
<alpine.LSU.1.00.0803131607030.1656@racer.site>
In-Reply-To
<20080313125229.GA24758@localhost>
Hi,
[Junio, there is a bugfix at the end of this mail.]
On Thu, 13 Mar 2008, Clemens Buchacher wrote:
Show 40 quoted lines
> Hi,
> 
> On Sat, Mar 08, 2008 at 06:17:26PM +0100, Clemens Buchacher wrote:
> > If git-merge-recursive attempts to merge two empty new files with 
> > different executable flags, eventually xdl_merge() is called and 
> > produces empty diffs for both files and therefore does not choose 
> > either file as successor. Make xdl_merge() choose one of the files 
> > instead.
> 
> On Sat, Mar 08, 2008 at 06:51:48PM +0100, Johannes Schindelin wrote:
> > On Sat, 8 Mar 2008, Clemens Buchacher wrote:
> > > I do not understand why, but this does not happen if the file 
> > > permissions are the same.
> > 
> > I think this is the biggest problem.
> > 
> > >  t/t6031-merge-recursive.sh |   23 +++++++++++++++++++++++
> > >  xdiff/xmerge.c             |   30 ++++++++++++++----------------
> > 
> > ... because xdiff/xmerge.c is definitely the wrong place to "fix" this 
> > issue.  xdl_merge() does not even _know_ about permissions.
> 
> After analyzing the problem in greater detail, I have to disagree. It is 
> true, of course, that xdl_merge() does not and should not know about 
> permissions at all. However, the bug is still in xdl_merge(). Different 
> permissions are only the trigger of the problem, because only then will 
> xdl_merge() be called at all.
> 
> What happens is this. Before looking at the file contents directly 
> merge_trees() attempts to resolve the merge trivially. If both sha1 and 
> mode of the head and remote entries match, the merge will be resolved as 
> per case #5ALT (see Documentation/trivial-merge.txt), i.e. head is 
> chosen as the merge result.
> 
> If either sha1 _or_ mode differ between the head and remote entries, 
> however, merge_trees() will use xdl_merge() to merge the file content 
> and the remote entry's mode will be chosen as result mode.
> 
> One could argue that it would be better to mark the mismatching 
> permissions as a conflict.

Right you are. Your whole "it still is xdl_merge()s fault" point was just contradicted by your own analysis. Calling xdl_merge() when the sha1 does _not_ differ is _a mistake_. _That_ is the bug. Not xdl_merge() returning 0 (because there were 0 conflicts).

Show 8 quoted lines
> However, this is how the merge currently silently succeeds _unless_ both 
> files are empty. If they are, xdl_merge() will effectively exit with an 
> error status and git-merge-recursive will fail with an internal error 
> (as shown in the testcase).
> 
> In any case, I think it is reasonable to expect xdl_merge() to work with 
> empty files. Whether or not the current "mode merging" behavior is 
> desired is a different matter.

I just tested. xdl_merge() is _just fine_ with empty files. However, git-merge-file was not. Fixed by this:

-- snipsnap -- [PATCH] merge-file: handle empty files gracefully

Earlier, it would error out while trying to read and/or writing them. Now, calling merge-file with empty files is neither interesting nor useful, but it is a bug that needed fixing.

Noticed by Clemens Buchacher.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin-merge-file.c |    3 ++-
 xdiff-interface.c    |    4 ++--
 2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/builtin-merge-file.c b/builtin-merge-file.c
index adce6d4..cde4b2c 100644
--- a/builtin-merge-file.c
+++ b/builtin-merge-file.c
@@ -57,7 +57,8 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
 
 		if (!f)
 			ret = error("Could not open %s for writing", filename);
-		else if (fwrite(result.ptr, result.size, 1, f) != 1)
+		else if (result.size &&
+				fwrite(result.ptr, result.size, 1, f) != 1)
 			ret = error("Could not write to %s", filename);
 		else if (fclose(f))
 			ret = error("Could not close %s", filename);
diff --git a/xdiff-interface.c b/xdiff-interface.c
index bba2364..61dc5c5 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -152,8 +152,8 @@ int read_mmfile(mmfile_t *ptr, const char *filename)
 	if ((f = fopen(filename, "rb")) == NULL)
 		return error("Could not open %s", filename);
 	sz = xsize_t(st.st_size);
-	ptr->ptr = xmalloc(sz);
-	if (fread(ptr->ptr, sz, 1, f) != 1)
+	ptr->ptr = xmalloc(sz ? sz : 1);
+	if (sz && fread(ptr->ptr, sz, 1, f) != 1)
 		return error("Could not read %s", filename);
 	fclose(f);
 	ptr->size = sz;
-- 
1.5.4.4.706.ga822
Previous: Clemens BuchacherNext: Junio C Hamano
Message 4 of 23 in “fix recursive-merge of empty files with different permissions”
  1. fix recursive-merge of empty files with different permissionsClemens Buchacher, Mar 8, 2008
  2. Johannes SchindelinMar 8, 2008
  3. Clemens BuchacherMar 13, 2008
  4. Johannes SchindelinMar 13, 2008
  5. Junio C HamanoMar 13, 2008
  6. Johannes SchindelinMar 13, 2008
  7. merge-recursive: cause a conflict if file mode does not matchClemens Buchacher, Mar 13, 2008
  8. Johannes SchindelinMar 13, 2008
  9. merge-recursive: handle file mode changesClemens Buchacher, Mar 13, 2008
  10. Johannes SchindelinMar 13, 2008
  11. merge-recursive: handle file mode and links similarly to file contentClemens Buchacher, Mar 14, 2008
  12. Clemens BuchacherMar 14, 2008
  13. Junio C HamanoMar 14, 2008
  14. Junio C HamanoMar 14, 2008
  15. Clemens BuchacherMar 14, 2008
  16. Jakub NarebskiMar 14, 2008
  17. Clemens BuchacherMar 14, 2008
  18. Junio C HamanoMar 14, 2008
  19. Clemens BuchacherMar 14, 2008
  20. Junio C HamanoMar 14, 2008
  21. Clemens BuchacherMar 14, 2008
  22. Junio C HamanoMar 14, 2008
  23. Clemens BuchacherMar 14, 2008

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.