-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Clean Merging (including code motion inside files) #13
Comments
Update: breaking out code motion across files into its own ticket: #26 . |
It may be the case that divergent code motion can be accomodated, at least in some situations by allowing both moves to take place; this can also pick up edits from the other side of the move in both cases. It is then up to user to decide whether to delete either or both moves, or simply accept both. This doesn't work with ambiguous matches because multiple edits may associate to several of the matches, but that can be left as unsupported. In fact, having ambiguous matches with code motion can lead to a situation where a moved section is associated with multiple edits on the other side - so there are edit collisions on the same side. Stay away from this for now... |
More pondering leads to this rule of thumb: if an all-sides match leads to a coincident edit in the merge with the left and right contributions to the match being moved to different locations, then we have two independent edits, each applying to the move on the opposite side. Going further, if the two moves land in the same place and are picked up by the merge as either a coincident insertion or edit, then we have an edit collision that can be represented as an insertion / insertion conflict or an edit / edit conflict. If the two moves land in the same place that happens to be a preservation or coincident insertion because of an ambiguous match, we don't care what happens as that's not supported yet, as long as the application doesn't crash. |
Regarding edit collisions due to ambiguous matches, a quick-and-dirty approach is to store the rival edits as a set, so duplicated edits don't actually conflict. If a set turns out to have more than edit, they are simply concatenated in no particular order and a diagnostic can be issued. A deletion would form its own entry in the set too. For now however, just store one edit or deletion for each side and issue a diagnostic if a collision occurs on the same side. |
So in the implementation of the merge algebra for By using the left and right elements from the match, we can distinguish between edits and / or deletions associated with both sides. |
Got tests for the simpler situations exercising The more complex scenarios can wait (eg. a single edit on one side versus two distinct moves on the other side, or an edit on one side adjacent to a move destination versus a move on the other side). The next thing to do is to wire in use of |
Got a failure in |
BASE FILE:
|
LEFT FILE:
|
RIGHT FILE:
|
DESIRED MERGE BASED ON INTUITION:
|
Outcome seen as of Git commit SHA: 9c5dd26 ...
|
So we got a conflict at the end. |
The minimum sure-fire match size was 5, and as there was just the one file, no smaller matches would have been considered. So the obvious match of The final section on each side was generated as a filler, hence the lack of consistency between them. |
What happens with a minimum match size of 4? (Git commit SHA: 5a9a82b) Now we see an all-sides match for
That is fully merged, seems promising ... but the test still fails! |
Ah - the test expectations were too rigid - was using default equality to compare tokens, which takes whitespace into account. The tests were cutover to use the whitespace-insensitive Test now passes. |
This is good, but I'm uneasy about how much has been proven.
|
Another wrinkle is that the nice intuitive picture of a single section moving on one side of the merge and being edited on the other generally won't be the case unless the minimum match size is quite large. What will happen instead is that there will be three sections on each side - a leading and trailing one that are both matched on all sides, moving in tandem, and a middle one that has a pairwise match between the base and the side with the move - and an unmatched section that is the precisely the edit change. I expect this to work with the current implementation as of a694056, but this needs testing... |
As of Git commit SHA: d3e02cb, Code motion has arrived! |
Pushing all further work on supporting edge cases for propagating edits and deletions through moves into a separate ticket #28 . |
Favouring moves of small sections over moves of large sections by modifying |
As of Git commit SHA: 9a2fddb the longest common subsequence algorithm favours subsequences with longer section when choosing between longest common subsequences of the same length. This is reflected in the downstream merge, where it is the smaller sections that get picked up as code motion when they interchange with larger sections. The test failure noted above in This led to the suffix moving on the other side from the edit as is, and an ordinary delete versus edit conflict at the source of the move. Had the suffix been large enough to match, then this would have resulted in a move of the suffix in tandem with the prefix; the edit being propagated through the move. Edit anchoring is a possible way of dealing with this - unmatched sections are considered to be anchored to adjacent matched sections, so as long as the matched sections move in tandem, they could pick up the unmatched section as a move, thus allowing edit propagation. A new ticket #29 has been made for edit anchoring; for now, we have something worth getting out there... |
This went out in release 1.1.0, Git commit SHA: 26a9c9a. |
Evidence (screencast of a demonstration of Kinetic Merge): Kinetic.Merge.in.action.-.part.1.-.editing.the.code.movKinetic.Merge.in.action.-.part.2.-.refactoring.the.code.movKinetic.Merge.in.action.-.part.3.-.merging.the.branches.mov |
Closing now that evidence is uploaded. |
This follows on from #1 , adding in the requirement dropped from that ticket:
Given a Git repository of files in multiple directories that has been worked on in two branches, provide a command line utility that merges one branch into another, taking into account code motion inside files.
Any divergent code motion is treated as an error and causes the merge to be aborted - the repository should be left as it was prior to the merge being attempted.
Code motion is only considered inside a file on a file-by-file basis - so when a method is extracted and placed elsewhere in the same file, it should be picked up as code motion in this ticket. Similarly for code rearrangement due to method sorting in something like IntelliJ.
Moving a class into its own file would not be picked up in this ticket, that job is for #26.
The text was updated successfully, but these errors were encountered: