mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
fix [VCS, merge]: Don't auto resolve modified_deleted conflicts IJPL-252505
GitOrigin-RevId: bbdc4b3c172b4bbec0791b737ecb2f04839ed254
This commit is contained in:
committed by
intellij-monorepo-bot
parent
28e0bf1a91
commit
0f1cb3ea5e
@@ -351,6 +351,7 @@ f:com.intellij.diff.merge.MergeTool$ToolbarComponents
|
||||
a:com.intellij.diff.merge.TextMergeRequest
|
||||
- com.intellij.diff.merge.ThreesideMergeRequest
|
||||
- <init>():V
|
||||
- getConflictType():com.intellij.diff.merge.ConflictType
|
||||
- a:getContents():java.util.List
|
||||
- a:getOutputContent():com.intellij.diff.contents.DocumentContent
|
||||
a:com.intellij.diff.merge.ThreesideMergeRequest
|
||||
|
||||
@@ -12,4 +12,8 @@ public abstract class TextMergeRequest extends ThreesideMergeRequest {
|
||||
|
||||
@Override
|
||||
public abstract @NotNull DocumentContent getOutputContent();
|
||||
|
||||
public @NotNull ConflictType getConflictType() {
|
||||
return ConflictType.DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,7 +333,8 @@ public class DiffRequestFactoryImpl extends DiffRequestFactory {
|
||||
|
||||
List<DocumentContent> contents = DiffUtil.getDocumentContentsForViewer(project, byteContents, output, conflictType);
|
||||
|
||||
return new TextMergeRequestImpl(project, outputContent, originalContent, contents, title, contentTitles);
|
||||
ConflictType effectiveConflictType = conflictType != null ? conflictType : ConflictType.DEFAULT;
|
||||
return new TextMergeRequestImpl(project, outputContent, originalContent, contents, effectiveConflictType, title, contentTitles);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -355,8 +355,9 @@ class MergeConflictModel(
|
||||
}
|
||||
|
||||
fun canResolveChangeAutomatically(changeIndex: Int, side: ThreeSide): Boolean {
|
||||
val change = getByIndex(changeIndex)
|
||||
if (mergeRequest.conflictType.isModifyDeleteFileConflict()) return false
|
||||
|
||||
val change = getByIndex(changeIndex)
|
||||
return if (change.isConflict) {
|
||||
side == ThreeSide.BASE &&
|
||||
change.conflictType.canBeResolved() &&
|
||||
@@ -371,6 +372,11 @@ class MergeConflictModel(
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConflictType.isModifyDeleteFileConflict() = when (this) {
|
||||
ConflictType.MODIFIED_DELETED, ConflictType.DELETED_MODIFIED -> true
|
||||
ConflictType.DEFAULT, ConflictType.ADDED_ADDED -> false
|
||||
}
|
||||
|
||||
private fun TextMergeRequest.resetOutputContent() {
|
||||
val text = ThreeSide.BASE.select(contents).document.text
|
||||
outputContent.document.setText(text)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package com.intellij.diff.requests;
|
||||
|
||||
import com.intellij.diff.contents.DocumentContent;
|
||||
import com.intellij.diff.merge.ConflictType;
|
||||
import com.intellij.diff.merge.MergeCallback;
|
||||
import com.intellij.diff.merge.MergeResult;
|
||||
import com.intellij.diff.merge.MergeUtil;
|
||||
@@ -25,6 +26,7 @@ public class TextMergeRequestImpl extends TextMergeRequest {
|
||||
private final @NotNull List<DocumentContent> myContents;
|
||||
|
||||
private final @NotNull CharSequence myOriginalContent;
|
||||
private final @NotNull ConflictType myConflictType;
|
||||
|
||||
private final @Nullable @NlsContexts.DialogTitle String myTitle;
|
||||
private final @NotNull List<String> myTitles;
|
||||
@@ -35,12 +37,23 @@ public class TextMergeRequestImpl extends TextMergeRequest {
|
||||
@NotNull List<DocumentContent> contents,
|
||||
@Nullable @NlsContexts.DialogTitle String title,
|
||||
@NotNull List<@Nls String> contentTitles) {
|
||||
this(project, output, originalContent, contents, ConflictType.DEFAULT, title, contentTitles);
|
||||
}
|
||||
|
||||
public TextMergeRequestImpl(@Nullable Project project,
|
||||
@NotNull DocumentContent output,
|
||||
@NotNull CharSequence originalContent,
|
||||
@NotNull List<DocumentContent> contents,
|
||||
@NotNull ConflictType conflictType,
|
||||
@Nullable @NlsContexts.DialogTitle String title,
|
||||
@NotNull List<@Nls String> contentTitles) {
|
||||
assert contents.size() == 3;
|
||||
assert contentTitles.size() == 3;
|
||||
myProject = project;
|
||||
|
||||
myOutput = output;
|
||||
myOriginalContent = originalContent;
|
||||
myConflictType = conflictType;
|
||||
|
||||
myContents = contents;
|
||||
myTitles = contentTitles;
|
||||
@@ -57,6 +70,11 @@ public class TextMergeRequestImpl extends TextMergeRequest {
|
||||
return myContents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ConflictType getConflictType() {
|
||||
return myConflictType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getTitle() {
|
||||
return myTitle;
|
||||
|
||||
@@ -813,6 +813,38 @@ class MergeTest : MergeTestBase() {
|
||||
}
|
||||
}
|
||||
|
||||
fun testDoNotAutoResolveDeletedByUsFileConflict() {
|
||||
// "deleted by us": ours (left) removed the file, theirs (right) kept the base content (e.g. a rename).
|
||||
doTest("", "A_B_C", "A_B_C", 1, ConflictType.DELETED_MODIFIED) {
|
||||
assertFalse(0.canResolveConflict())
|
||||
|
||||
runApplyNonConflictsAction(ThreeSide.BASE)
|
||||
0.assertResolved(NONE)
|
||||
assertContent("A_B_C")
|
||||
}
|
||||
}
|
||||
|
||||
fun testDoNotAutoResolveDeletedByThemFileConflict() {
|
||||
// "deleted by them": theirs (right) removed the file, ours (left) kept the base content.
|
||||
doTest("A_B_C", "A_B_C", "", 1, ConflictType.MODIFIED_DELETED) {
|
||||
assertFalse(0.canResolveConflict())
|
||||
|
||||
runApplyNonConflictsAction(ThreeSide.BASE)
|
||||
0.assertResolved(NONE)
|
||||
assertContent("A_B_C")
|
||||
}
|
||||
}
|
||||
|
||||
fun testAutoResolveDeletionWithoutFileConflictType() {
|
||||
// Control: without the modify/delete ConflictType, the same one-sided change still auto-resolves.
|
||||
doTest("", "A_B_C", "A_B_C", 1) {
|
||||
assertTrue(0.canResolveConflict())
|
||||
|
||||
runApplyNonConflictsAction(ThreeSide.BASE)
|
||||
0.assertResolved(BOTH)
|
||||
}
|
||||
}
|
||||
|
||||
fun testApplySeveralActions() {
|
||||
doTest("X_1_Y_2_Z_3_4_U_W_",
|
||||
"X_a_Y_b_Z_c_U_d_W_",
|
||||
|
||||
@@ -48,7 +48,21 @@ abstract class MergeTestBase : HeavyDiffTestCase() {
|
||||
doTest(left, base, right, changesCount, IgnorePolicy.DEFAULT, f)
|
||||
}
|
||||
|
||||
fun doTest(
|
||||
left: String, base: String, right: String, changesCount: Int,
|
||||
conflictType: ConflictType, f: TestBuilder.() -> Unit,
|
||||
) {
|
||||
doTest(left, base, right, changesCount, IgnorePolicy.DEFAULT, conflictType, f)
|
||||
}
|
||||
|
||||
fun doTest(left: String, base: String, right: String, changesCount: Int, policy: IgnorePolicy, f: TestBuilder.() -> Unit) {
|
||||
doTest(left, base, right, changesCount, policy, ConflictType.DEFAULT, f)
|
||||
}
|
||||
|
||||
fun doTest(
|
||||
left: String, base: String, right: String, changesCount: Int, policy: IgnorePolicy,
|
||||
conflictType: ConflictType, f: TestBuilder.() -> Unit,
|
||||
) {
|
||||
val contentFactory = DiffContentFactoryImpl()
|
||||
val leftContent: DocumentContent = contentFactory.create(parseSource(left))
|
||||
val baseContent: DocumentContent = contentFactory.create(parseSource(base))
|
||||
@@ -57,7 +71,7 @@ abstract class MergeTestBase : HeavyDiffTestCase() {
|
||||
outputContent.document.setReadOnly(false)
|
||||
|
||||
val context = MockMergeContext(project)
|
||||
val request = MockMergeRequest(leftContent, baseContent, rightContent, outputContent)
|
||||
val request = MockMergeRequest(leftContent, baseContent, rightContent, outputContent, conflictType)
|
||||
|
||||
val settings = TextDiffSettings()
|
||||
settings.ignorePolicy = policy
|
||||
@@ -376,10 +390,13 @@ abstract class MergeTestBase : HeavyDiffTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
private class MockMergeRequest(val left: DocumentContent,
|
||||
val base: DocumentContent,
|
||||
val right: DocumentContent,
|
||||
val output: DocumentContent) : TextMergeRequest() {
|
||||
private class MockMergeRequest(
|
||||
val left: DocumentContent,
|
||||
val base: DocumentContent,
|
||||
val right: DocumentContent,
|
||||
val output: DocumentContent,
|
||||
private val requestConflictType: ConflictType = ConflictType.DEFAULT,
|
||||
) : TextMergeRequest() {
|
||||
override fun getTitle(): String? = null
|
||||
|
||||
override fun applyResult(result: MergeResult) {
|
||||
@@ -390,6 +407,8 @@ abstract class MergeTestBase : HeavyDiffTestCase() {
|
||||
override fun getOutputContent(): DocumentContent = output
|
||||
|
||||
override fun getContentTitles(): List<String?> = listOf(null, null, null)
|
||||
|
||||
override fun getConflictType(): ConflictType = requestConflictType
|
||||
}
|
||||
|
||||
enum class SidesState {
|
||||
|
||||
Reference in New Issue
Block a user