Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [egit-dev] Logical model support for merge operations

Hi,

I can't really answer that without writing a wall of text so... please bear with me :p.

You can try this with either the "sample" model provider and merger I have defined in these unit tests (1), or with the more advanced one we have in EMF Compare (2).

(1)
This model provider is defined so that all files with the "sample" extension located in a single folder will be considered to be part of the same logical model, and must thus be compared, replaced, merged, ... together. This doesn't amount to much since they are simple text files with no real connection between them but that's sufficient for the tests I currently have. We could assume that these files have a very strict parser and that they thus cannot be impaired with the "textual" conflict markers (>>>> ==== <<<<) much like MANIFEST.MF files do, but that'll come later. For now, the SampleResourceMappingMerger I've defined to merge them only delegates to the default Team one, which has pretty good results on textual files, and which takes responsibility for deleting files when needed.

Manually testing that we pass through this merger can be done by reenacting the test case I've defined as a unit test :
  1. Add "*.sample" to the "text" content-type (Window > Preferences > General > Content Types, select "Text" then "Add..." and fill in "*.sample". This will tell Eclipse to treat these files as text while merging through the default Team merger)
  2. Create a new project (SampleProject)
  3. Share it through git (Team > Share Project, I've created the repo out of my workspace)
  4. Make an initial commit for the .project
  5. Create a new file "test.sample" in there, put some content in (sufficiently long, I went with "some content for the test file")
  6. commit, then branch (Team > Switch To > New Branch... I used "branch" as the name)
  7. append content in the beginning of the file (I went with "branch change\ninitial content" i.e. change text on a new line, without changing the existing one)
  8. commit, then checkout master
  9. append content at the end of the file ("initial content\nmaster change" i.e. once again, don't change the existing line except for a carriage return, just append at the end of the file)
  10. commit
  11. Try and merge "branch" in our current master

Now, without the patchs applied, the merge will end in conflict as it will go through the default git merger. With the patchs, the merge will properly see that as an automatically mergeable conflict : even though these are "model" mergers, a "model" can be comprised of a single file. This is a way for resource format provider to better tell Team how the merges should be handled. It wouldn't have been the same if we had appended content at the start of the file in step 9, as that would have been a conflict either way. You can try out multiple use cases, the one that causes a failure in the auto-staging hook for deletions is if we change step 7 to "delete the test file" and do nothing in step 9 and 10 : just delete the file in a branch, checkout master then try and merge : an exception will make the operation as a whole fail.

Do note that these changes do not honor the "allow models to participate in synchronization" preference yet... or a preference to disable models during merge if we'd rather introduce another one.

(2)
This model provider is defined to use EMF Compare for the EMF files (I'll always use "EMF files" here to avoid confusion : they are usually named "models" but these are not the same models we are talking about here) instead of comparing them textually. Indeed, these are XMI files, with a whole world of tooling to handle them, from loading to validation, with their own editors to avoid manually twiddling with the xmi serialization. This also means that adding "foreign" information inside of said serialization will break the whole tooling (how would you load an xmi file where the xmi is malformed, or "corrupted" by, say, the git conflict markers?). Furthermore, some things that are detected as conflicts textually might very well be automatically mergeable when handling logically (as in "the EMF way"). We have a set of unit tests aiming in particular at covering the git integration in https://git.eclipse.org/c/emfcompare/org.eclipse.emf.compare.git/tree/plugins/org.eclipse.emf.compare.ide.ui.tests.git . Namely, "GitLogicalMergeTest" (https://git.eclipse.org/c/emfcompare/org.eclipse.emf.compare.git/tree/plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/unit/GitLogicalMergeTest.java) executes a number of unit tests by launching both of the merge : first text, then logical, asserting the differences between the two and the expected results of both (since 'logical' merge is supposed to have much better results in all cases).

You can try this manually. We don't have a working psf or oomph setup, but here is the dependencies you need to install (from a "vanilla" luna). I'd attach a target platform... but that would lack the possibility to launch a new runtime...

Clone both JGit, EGit and EMF Compare (git://git.eclipse.org/gitroot/emfcompare/org.eclipse.emf.compare.git). You don't need me to tell you what you need from JGit and EGit, but here's what I retrieved in my workspace :
  • import from JGit
    • org.eclipse.jgit
    • org.eclipse.jgit.java7
  • import from EGit
    • org.eclipse.egit.core
    • org.eclipse.egit.ui
  • import from EMF Compare
    • org.eclipse.emf.compare
    • org.eclipse.emf.compare.edit
    • org.eclipse.emf.compare.ide
    • org.eclipse.emf.compare.ide.ui
    • org.eclipse.emf.compare.rcp
    • org.eclipse.emf.compare.rcp.ui

From there, apply the patchs you need on the egit repo (jgit already has what's needed) and you'll be able to test out the support in a new runtime. I won't go into details about how to create EMF files, but here's an example that presents cross-resources links that would be broken by the default git merge handling :

  1. Create a new project (SampleProject)
  2. Share it through git (Team > Share Project, I've created the repo out of my workspace)
  3. Make an initial commit for the .project
  4. Create a new ecore file (New > Other... > Eclipse Modeling Framework > Ecore Model) - I named it main.ecore
  5. Expand the root (platform:/resource...) and right-click the empty package to select "Show Properties View"
  6. Click the empty package again and give it a name (in the properties view, I went for "firstPackage" since I'm so creative)
  7. Right-click the package and use New Child > EClass
  8. Name that class 'ClassA' through the properties view as in 6.
  9. Repeat steps 4 to 8 in order to create a second ecore file looking much the same; this time I named the package "secondPackage" and the class "ClassB" while naming the file "types.ecore"
  10. Go back into main.ecore, then right-click anywhere and select "Load Resource..."
  11. Browse the workspace to select the other ecore file (types.ecore)
  12. Click ClassA to show its properties, then select the line "ESuper types". Click the "..." button at the right edge of the table and double-click "ClassB" in there
  13. This action has created a link between our two resources. If you close the editor and reopen it, you will see that the other file gets automatically loaded when you browse down to ClassA. Commit both files.
  14. Create and checkout a new branch (I named it "branch" again)
  15. Open main.ecore, browse to ClassA so that types.ecore gets loaded, then while staying in this editor, delete ClassB. Save.
  16. Both files should have been modified, commit both
  17. Switch back to master
  18. Open main.ecore, browse to ClassA so that types.ecore gets loaded, then while staying in this editor, create a new Class "ClassC" beside ClassA in "firstPackage".
  19. Repeat step 12 so that both ClassA and ClassC have "ClassB" as a super-type
  20. Only main.ecore has changed. Commit it

In the current state of this repository, we have a logical conflict : in a branch we have deleted a type, while on the other, master, we have created a new reference to this class. However, there are no "text" conflict in there since the changes impact distinct lines. In short, a textual merge will simply merge the text in both files, making it so that this "new reference to ClassB" we've created in step 19 is merged in main.ecore, even though the ClassB in question is deleted as a result of the successful textual merging of what we did in step 15.
If you merge without my patchs applied, the above will happen. Now, if you try to open "main.ecore" after this merge, you will see that both ClassA and ClassC appear with "null" as their super-type (and this error is silent, so the user will have a hard type figuring it other than through right-click > validate on the resource root).
If you merge with my patchs applied, the merge tells you that this cannot happen because of conflicts, and both files are marked as conflicting _without us adding the textual conflict markers_ i.e. the user can still open the files in his editor. Or call the merge tool if https://git.eclipse.org/r/#/c/22672/ is also applied.

The reverse (textual conflict but no logical conflict) can also happen, with the adverse effect of adding the conflict markers, preventing the EMF editor from properly parsing the xmi file. This can also be observed if you change step 18 and 19 to "rename ClassB into ClassD" : ClassA still references this class, but we also renamed it while it was deleted in the branch. This will cause a logical conflict as well as a textual conflict.

I'll stop here, many variations of these cases can be done, but as you can see even though it is pretty easy, it will be quite costly to create the environment to test this manually (hence the unit tests we're creating in EMF Compare, and which I've started to implement for git itself).

Laurent


Laurent Goubet <laurent.goubet@xxxxxxx>
Obeo

begin:vcard
fn:Laurent Goubet
n:Goubet;Laurent
org:<a href="http://www.obeo.fr";>Obeo</a>
email;internet:laurent.goubet@xxxxxxx
url:http://www.obeo.fr
version:2.1
end:vcard


Back to the top