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 :
- 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)
- Create a new project (SampleProject)
- Share it through git (Team > Share Project, I've created
the repo out of my workspace)
- Make an initial commit for the .project
- Create a new file "test.sample" in there, put some content
in (sufficiently long, I went with "some content for the test
file")
- commit, then branch (Team > Switch To > New Branch...
I used "branch" as the name)
- 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)
- commit, then checkout master
- 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)
- commit
- 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 :
- Create a new project (SampleProject)
- Share it through git (Team > Share Project, I've created
the repo out of my workspace)
- Make an initial commit for the .project
- Create a new ecore file (New > Other... > Eclipse
Modeling Framework > Ecore Model) - I named it main.ecore
- Expand the root (platform:/resource...) and right-click the
empty package to select "Show Properties View"
- Click the empty package again and give it a name (in the
properties view, I went for "firstPackage" since I'm so
creative)
- Right-click the package and use New Child > EClass
- Name that class 'ClassA' through the properties view as in
6.
- 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"
- Go back into main.ecore, then right-click anywhere and
select "Load Resource..."
- Browse the workspace to select the other ecore file
(types.ecore)
- 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
- 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.
- Create and checkout a new branch (I named it "branch" again)
- Open main.ecore, browse to ClassA so that types.ecore gets
loaded, then while staying in this editor, delete ClassB.
Save.
- Both files should have been modified, commit both
- Switch back to master
- 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".
- Repeat step 12 so that both ClassA and ClassC have "ClassB"
as a super-type
- 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