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

Re: [PATCH 3/3] merge-ort: fix issue with dual rename and add/add conflict

From
JTJonathan Tan <jonathantanmy@google.com>
Date
Jul 6, 2022, 17:25 UTC
Message-ID
<20220706172505.270363-1-jonathantanmy@google.com>
In-Reply-To
<CABPp-BG8r4zUOKZ+DzZOdsEwr+580cK=SvZ4n_euPOV1Nocu+A@mail.gmail.com>

Sorry for getting back to this so late. I don't have any issues with the patches, but just to close the loop:

Elijah Newren <newren@gmail.com> writes:
Show 16 quoted lines
> On Mon, Jun 27, 2022 at 11:47 AM Jonathan Tan <jonathantanmy@google.com> wrote:
> >
> > "Elijah Newren via GitGitGadget" <gitgitgadget@gmail.com> writes:
> > > The testcases added in t6423 a couple commits ago are slightly different
> > > but similar in principle.  They involve a similar case of paired
> > > renaming but instead of A/ -> B/ and B/ -> C/, the second side renames
> > > a leading directory of B/ to C/.
> >
> > Hmm...one side moved sub1 -> sub3 and the other moved sub2 from the root
> > to under sub1, right? So it's more like A/ -> B/ and C/ -> A/C/.
> 
> Hmm, maybe I should have been more explicit in my mapping:
>    A = sub2
>    B = sub1/sub2
>    leading directory of B = sub1
>    C = sub3

Substituting into A/ -> B/ and "a leading directory of B/ to C/", we get:

  sub2 -> sub1/sub2 and sub1 -> sub3
which is indeed what is happening. I see, thanks.
Show 10 quoted lines
> > > And both sides add a new file
> > > somewhere under the directory that the other side will rename.
> >
> > Rename or move, I think.
> 
> I'm confused; I don't understand what this comment means.  Renames
> tend to be created using "git mv", before or after making content
> changes, so to me a file being renamed or a file being moved to a
> different location are synonymous.  What distinction are you making
> between renames and moves?

I was thinking that a rename means that the directory still has the same parent directory, whereas a move means that the directory keeps its basename but has a different parent directory. Maybe it's just the way I think about things, but the important thing here is that a directory was moved so that its parent directory is a directory that is different and that already exists, and I think that this meaning is lost when we say "rename". But it might just be me.

Show 9 quoted lines
> Hmm, perhaps I should change this to:
> 
> /* Cases where we don't have or don't want a directory rename for this
> path, so we return NULL */
> 
> The purpose of this function is to check whether a given path would be
> modified by directory renaming to get a new path.  So, "no new path"
> means we don't have an applicable directory rename or don't want to
> use it.
I see - the new text makes sense.
Show 30 quoted lines
> > >       if (strmap_empty(dir_renames))
> > >               return new_path;
> > > +     if (strmap_get(&collisions[other_side], path))
> > > +             return new_path;
> >
> > So as far as I understand, collisions here, for a given side, is a map.
> > The map's keys are all the filenames of added and renamed files (I'm
> > assuming that's what 'A' and 'R' are) from that side after any directory
> > moves on the other side are applied. So, for example, if we add "foo/a"
> > on side A and rename "foo/" to "bar/" on side B, then side A's collision
> > map would have a key "bar/a". So I'm not sure if "collision" is the
> > right name here, but the existing code already uses it so I'll leave it
> > be.
> 
> Let's take your example a bit further, to discuss the original kind of
> usecase that "collisions" was written for.  In addition to adding
> "foo/a" on side A, we also add "foo2/a" and "foo3/a".  And then in
> addition to renaming "foo/" to "bar/" on side B, we also rename
> "foo2/" to "bar/" and "foo3/" to "bar/", thus merging all of foo/,
> foo2/, and foo3/ into a single directory named bar/.  If the files in
> foo/, foo2/, and foo3/ on side B were all unique, you can see how
> there'd be no problem merging these directories together.  The problem
> only comes at merge time when you attempt to apply the directory
> renames from side B to the new files on side A.  That's when you get
> collisions, in this case three files that would be named bar/a.
> 
> Checking for such collisions was the purpose of the "collisions"
> metadata, so I think the name is fitting.  The only problem is that
> we're reusing that data now for a slightly different purpose, though I
> think it's still "collision-y".
That makes sense, thanks.
Show 9 quoted lines
> > It makes sense that this situation (of side A having "bar/a" because
> > side B renamed "foo/" to "bar/", and at the same time, side B adds its
> > own "bar/a") is weird, as stated in the commit message, so I don't mind
> > disabling checking for directory rename in this case.  However, in
> > theory, I don't see how disabling this check would fix anything, since
> > the bug seems to be about two different files on different sides being
> > renamed to the same filename through some convoluted means. (Unless this
> > is the only convoluted means to do it, and disabling it means that the
> > bug wouldn't occur.)
[snip]
Show 20 quoted lines
> Hmm...let me see if I can explain this a different way.
> 
> The short version of the issue here is that if a directory rename
> wants to rename NEWFILE -> ALTERNATE_NEWFILE, but there is another
> directory rename on the other side of history that wants to rename
> ANOTHER_FILE -> NEWFILE, then we run into problems and have to turn
> off the NEWFILE -> ALTERNATE_NEWFILE.  This check here is all about
> this case.
> 
> To see why this is the problematic setup...
> 
> Now a conflict_info
> stores information about the OIDs and modes for all three sides of the
> merge (i.e. both sides of the merge and the base).  Whenever a rename
> is processed, we have to update this map, because the rename makes the
> conflict_info now apply to a different path.  In the simple cases, the
> conflict_info from the source path needs to be merged with the
> conflict_info for the target path, and the source path's conflict_info
> needs to be marked as null (literally setting the .is_null field to
> 1).  rename/rename and such can make this a bit more complicated.

Ah, I think I was missing this part. The intention is that processing one side in this way (and thus modifying its conflict_info) would not affect the processing of any other sides, but there is a bug that makes it not so. (And the intention is not, say, when processing all sides, to write the output in a new data structure so that the result is the same no matter the order.)

So I think the answer to my question is: no, we do not want to be able to rename two different files on different sides to the same filename through any convoluted means, and if that happens, it's a bug.

[snip illustration of what happens in either merge order]
Show 7 quoted lines
> To avoid this order dependence, and the weird multiple-renaming of a
> single path, we just want to turn off directory renames when the
> source of a directory rename on one side is the target of a directory
> rename on the other.  That's what this patch does.
> 
> 
> Does that help?  Or did I make it more confusing?
I think that helped, thanks.
Previous: Elijah NewrenNext: Elijah Newren
Message 16 of 45 in “Fix dual rename into each other plus conflicting adds”
  1. 0/3 Fix dual rename into each other plus conflicting addsElijah Newren via GitGitGadget, Jun 22, 2022
  2. 1/3 t6423: add tests of dual directory rename plus add/add conflictElijah Newren via GitGitGadget, Jun 22, 2022
  3. Jonathan TanJun 27, 2022
  4. Elijah NewrenJun 30, 2022
  5. Jonathan TanJun 30, 2022
  6. Elijah NewrenJul 1, 2022
  7. Calvin WanJun 27, 2022
  8. Elijah NewrenJun 30, 2022
  9. 2/3 merge-ort: shuffle the computation and cleanup of potential collisionsElijah Newren via GitGitGadget, Jun 22, 2022
  10. Jonathan TanJun 27, 2022
  11. Calvin WanJun 27, 2022
  12. Elijah NewrenJun 30, 2022
  13. 3/3 merge-ort: fix issue with dual rename and add/add conflictElijah Newren via GitGitGadget, Jun 22, 2022
  14. Jonathan TanJun 27, 2022
  15. Elijah NewrenJun 30, 2022
  16. Jonathan TanJul 6, 2022
  17. Elijah NewrenJun 22, 2022
  18. 0/3 Fix dual rename into each other plus conflicting addsElijah Newren via GitGitGadget, Jun 30, 2022
  19. 1/3 t6423: add tests of dual directory rename plus add/add conflictElijah Newren via GitGitGadget, Jun 30, 2022
  20. Ævar Arnfjörð BjarmasonJun 30, 2022
  21. Elijah NewrenJul 1, 2022
  22. Ævar Arnfjörð BjarmasonJul 1, 2022
  23. 2/3 merge-ort: shuffle the computation and cleanup of potential collisionsElijah Newren via GitGitGadget, Jun 30, 2022
  24. Ævar Arnfjörð BjarmasonJun 30, 2022
  25. Elijah NewrenJul 1, 2022
  26. 3/3 merge-ort: fix issue with dual rename and add/add conflictElijah Newren via GitGitGadget, Jun 30, 2022
  27. Ævar Arnfjörð BjarmasonJun 30, 2022
  28. Elijah NewrenJul 1, 2022
  29. 0/5 Fix dual rename into each other plus conflicting addsElijah Newren via GitGitGadget, Jul 1, 2022
  30. 1/5 t6423: add tests of dual directory rename plus add/add conflictElijah Newren via GitGitGadget, Jul 1, 2022
  31. 2/5 merge-ort: small cleanups of check_for_directory_renameElijah Newren via GitGitGadget, Jul 1, 2022
  32. 3/5 merge-ort: make a separate function for freeing struct collisionsElijah Newren via GitGitGadget, Jul 1, 2022
  33. 4/5 merge-ort: shuffle the computation and cleanup of potential collisionsElijah Newren via GitGitGadget, Jul 1, 2022
  34. Ævar Arnfjörð BjarmasonJul 1, 2022
  35. C99 "for (int ..." form on "master" (was: [PATCH v3 4/5] merge-ort: shuffle the computation and cleanup of potential collisions)Ævar Arnfjörð Bjarmason, Jul 25, 2022
  36. Elijah NewrenJul 26, 2022
  37. Junio C HamanoJul 26, 2022
  38. 5/5 merge-ort: fix issue with dual rename and add/add conflictElijah Newren via GitGitGadget, Jul 1, 2022
  39. 0/5 Fix dual rename into each other plus conflicting addsElijah Newren via GitGitGadget, Jul 5, 2022
  40. 1/5 t6423: add tests of dual directory rename plus add/add conflictElijah Newren via GitGitGadget, Jul 5, 2022
  41. 2/5 merge-ort: small cleanups of check_for_directory_renameElijah Newren via GitGitGadget, Jul 5, 2022
  42. 3/5 merge-ort: make a separate function for freeing struct collisionsElijah Newren via GitGitGadget, Jul 5, 2022
  43. 4/5 merge-ort: shuffle the computation and cleanup of potential collisionsElijah Newren via GitGitGadget, Jul 5, 2022
  44. 5/5 merge-ort: fix issue with dual rename and add/add conflictElijah Newren via GitGitGadget, Jul 5, 2022
  45. Junio C HamanoJul 6, 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.