From 5332f00a8d4dca1dd9a59d3dff5d722d0f174de6 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 10 Feb 2017 18:29:36 +0000 Subject: [PATCH] Allow to create Git branch without checking it out Add a checkbox to the branch creation dialog. Fixes IDEA-149886 --- .../src/com/intellij/openapi/ui/Messages.java | 2 +- .../actions/GitCreateNewBranchAction.java | 13 ++- .../src/git4idea/branch/GitBranchUtil.java | 14 ++-- .../src/git4idea/branch/GitBranchWorker.java | 6 ++ .../src/git4idea/branch/GitBrancher.java | 12 ++- .../src/git4idea/branch/GitBrancherImpl.java | 10 +++ .../branch/GitCreateBranchOperation.kt | 78 +++++++++++++++++ .../src/git4idea/branch/GitNewBranchDialog.kt | 48 +++++++++++ .../ui/branch/GitBranchPopupActions.java | 17 +++- .../git4idea/branch/GitBranchWorkerTest.kt | 84 ++++++++----------- 10 files changed, 220 insertions(+), 64 deletions(-) create mode 100644 plugins/git4idea/src/git4idea/branch/GitCreateBranchOperation.kt create mode 100644 plugins/git4idea/src/git4idea/branch/GitNewBranchDialog.kt diff --git a/platform/platform-api/src/com/intellij/openapi/ui/Messages.java b/platform/platform-api/src/com/intellij/openapi/ui/Messages.java index cd643eb17a29..9cf532cfbc84 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/Messages.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/Messages.java @@ -1688,7 +1688,7 @@ public class Messages { } } - protected static class InputDialog extends MessageDialog { + public static class InputDialog extends MessageDialog { protected JTextComponent myField; private final InputValidator myValidator; diff --git a/plugins/git4idea/src/git4idea/actions/GitCreateNewBranchAction.java b/plugins/git4idea/src/git4idea/actions/GitCreateNewBranchAction.java index 02c4ae83c878..8dae1031d3cd 100644 --- a/plugins/git4idea/src/git4idea/actions/GitCreateNewBranchAction.java +++ b/plugins/git4idea/src/git4idea/actions/GitCreateNewBranchAction.java @@ -18,22 +18,29 @@ package git4idea.actions; import com.intellij.openapi.project.Project; import com.intellij.vcs.log.Hash; import git4idea.branch.GitBrancher; +import git4idea.branch.GitNewBranchOptions; import git4idea.repo.GitRepository; import org.jetbrains.annotations.NotNull; import static git4idea.branch.GitBranchUtil.getNewBranchNameFromUser; import static java.util.Collections.singleton; import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; public class GitCreateNewBranchAction extends GitLogSingleCommitAction { @Override protected void actionPerformed(@NotNull GitRepository repository, @NotNull Hash commit) { Project project = repository.getProject(); - String name = getNewBranchNameFromUser(project, singleton(repository), "Checkout New Branch From " + commit.toShortString()); - if (name != null) { + GitNewBranchOptions options = getNewBranchNameFromUser(project, singleton(repository), "Checkout New Branch From " + commit.toShortString()); + if (options != null) { GitBrancher brancher = GitBrancher.getInstance(project); - brancher.checkoutNewBranchStartingFrom(name, commit.asString(), singletonList(repository), null); + if (options.shouldCheckout()) { + brancher.checkoutNewBranchStartingFrom(options.getName(), commit.asString(), singletonList(repository), null); + } + else { + brancher.createBranch(options.getName(), singletonMap(repository, commit.asString())); + } } } } diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java b/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java index d90678ec1fb6..4792c378bc51 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java @@ -21,7 +21,6 @@ import com.google.common.collect.Collections2; import com.intellij.dvcs.DvcsUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.CharsetToolkit; @@ -260,13 +259,16 @@ public class GitBranchUtil { } /** - * Shows a message dialog to enter the name of new branch. - * @return name of new branch or {@code null} if user has cancelled the dialog. + *

Shows a message dialog to enter the name of new branch.

+ *

Optionally allows to not checkout this branch, and just create it.

+ * + * @return the name of the new branch and whether it should be checked out, or {@code null} if user has cancelled the dialog. */ @Nullable - public static String getNewBranchNameFromUser(@NotNull Project project, @NotNull Collection repositories, @NotNull String dialogTitle) { - return Messages.showInputDialog(project, "New branch name:", dialogTitle, null, "", - GitNewBranchNameValidator.newInstance(repositories)); + public static GitNewBranchOptions getNewBranchNameFromUser(@NotNull Project project, + @NotNull Collection repositories, + @NotNull String dialogTitle) { + return new GitNewBranchDialog(project, dialogTitle, GitNewBranchNameValidator.newInstance(repositories)).showAndGetOptions(); } /** diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchWorker.java b/plugins/git4idea/src/git4idea/branch/GitBranchWorker.java index b7d14ea9f283..2d6676b941be 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchWorker.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchWorker.java @@ -38,6 +38,7 @@ import org.jetbrains.annotations.NotNull; import java.util.Collection; import java.util.List; +import java.util.Map; /** * Executes the logic of git branch operations. @@ -75,6 +76,11 @@ public final class GitBranchWorker { } } + public void createBranch(@NotNull String name, @NotNull Map startPoints) { + updateInfo(startPoints.keySet()); + new GitCreateBranchOperation(myProject, myGit, myUiHandler, name, startPoints).execute(); + } + public void createNewTag(@NotNull final String name, @NotNull final String reference, @NotNull final List repositories) { for (GitRepository repository : repositories) { myGit.createNewTag(repository, name, null, reference); diff --git a/plugins/git4idea/src/git4idea/branch/GitBrancher.java b/plugins/git4idea/src/git4idea/branch/GitBrancher.java index 6a2ca1b58e3b..645012bc4e71 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBrancher.java +++ b/plugins/git4idea/src/git4idea/branch/GitBrancher.java @@ -22,6 +22,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.Map; /** *

Executes various operations on Git branches: checkout, create new branch, merge, delete, compare.

@@ -29,7 +30,7 @@ import java.util.List; *

It also takes care of analyzing results and notifying the user.

*

All operations can be called for multiple repositories at once.

* - * @author Kirill Likhodedov + * @see GitBranchWorker */ public interface GitBrancher { static GitBrancher getInstance(@NotNull Project project) { @@ -48,6 +49,15 @@ public interface GitBrancher { */ void checkoutNewBranch(@NotNull String name, @NotNull List repositories); + /** + * Creates new branch without checking it out. + * + * @param name name of the new branch. + * @param startPoints position (commit hash) where the branch should be created, for each repository. + * Such position can be indicated by any valid Git reference (commit hash, branch name, etc.) + */ + void createBranch(@NotNull String name, @NotNull Map startPoints); + /** *

Creates new tag on the selected reference.

* diff --git a/plugins/git4idea/src/git4idea/branch/GitBrancherImpl.java b/plugins/git4idea/src/git4idea/branch/GitBrancherImpl.java index e05cac19eacf..4cb70e43d800 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBrancherImpl.java +++ b/plugins/git4idea/src/git4idea/branch/GitBrancherImpl.java @@ -27,6 +27,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.Map; /** * @author Kirill Likhodedov @@ -55,6 +56,15 @@ class GitBrancherImpl implements GitBrancher { return new GitBranchWorker(myProject, myGit, new GitBranchUiHandlerImpl(myProject, myGit, indicator)); } + @Override + public void createBranch(@NotNull String name, @NotNull Map startPoints) { + new CommonBackgroundTask(myProject, "Creating branch " + name, null) { + @Override public void execute(@NotNull ProgressIndicator indicator) { + newWorker(indicator).createBranch(name, startPoints); + } + }.runInBackground(); + } + @Override public void createNewTag(@NotNull final String name, @NotNull final String reference, @NotNull final List repositories, @Nullable Runnable callInAwtLater) { diff --git a/plugins/git4idea/src/git4idea/branch/GitCreateBranchOperation.kt b/plugins/git4idea/src/git4idea/branch/GitCreateBranchOperation.kt new file mode 100644 index 000000000000..08ce58d07e2a --- /dev/null +++ b/plugins/git4idea/src/git4idea/branch/GitCreateBranchOperation.kt @@ -0,0 +1,78 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea.branch + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vcs.VcsNotifier +import git4idea.commands.Git +import git4idea.commands.GitCompoundResult +import git4idea.repo.GitRepository + +internal class GitCreateBranchOperation( + project: Project, + git: Git, + uiHandler: GitBranchUiHandler, + private val branchName: String, + private val startPoints: Map) : GitBranchOperation(project, git, uiHandler, startPoints.keys) { + + public override fun execute() { + var fatalErrorHappened = false + while (hasMoreRepositories() && !fatalErrorHappened) { + val repository = next() + val result = myGit.branchCreate(repository, branchName, startPoints[repository]!!) + + if (result.success()) { + repository.update() + markSuccessful(repository) + } + else { + fatalError("Couldn't create new branch $branchName", result.errorOutputAsJoinedString) + fatalErrorHappened = true + } + } + + if (!fatalErrorHappened) { + notifySuccess() + updateRecentBranch() + } + } + + override fun rollback() { + val repositories = successfulRepositories + val deleteResult = GitCompoundResult(myProject) + for (repository in repositories) { + deleteResult.append(repository, myGit.branchDelete(repository, branchName, false)) + repository.update() + } + + val vcsNotifier = VcsNotifier.getInstance(myProject) + if (deleteResult.totalSuccess()) { + vcsNotifier.notifySuccess("Rollback successful", "Deleted $branchName") + } + else { + vcsNotifier.notifyError("Error during rollback", deleteResult.errorOutputWithReposIndication) + } + } + + override fun getSuccessMessage() = "Branch $branchName was created" + + override fun getRollbackProposal() = """ + However the branch was created in the following ${repositories()}:
+ ${successfulRepositoriesJoined()}
+ You may rollback (delete $branchName) not to let branches diverge.""".trimIndent() + + override fun getOperationName() = "create branch" +} diff --git a/plugins/git4idea/src/git4idea/branch/GitNewBranchDialog.kt b/plugins/git4idea/src/git4idea/branch/GitNewBranchDialog.kt new file mode 100644 index 000000000000..045d7801b642 --- /dev/null +++ b/plugins/git4idea/src/git4idea/branch/GitNewBranchDialog.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea.branch + +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.Messages +import com.intellij.ui.components.JBCheckBox +import com.intellij.util.ui.JBUI +import com.intellij.util.ui.UIUtil.DEFAULT_HGAP +import com.intellij.util.ui.UIUtil.DEFAULT_VGAP +import git4idea.validators.GitNewBranchNameValidator +import java.awt.BorderLayout +import java.awt.event.KeyEvent +import javax.swing.JComponent + +internal data class GitNewBranchOptions(val name: String, @get:JvmName("shouldCheckout") val checkout: Boolean) + +internal class GitNewBranchDialog(project: Project, dialogTitle: String, validator: GitNewBranchNameValidator) : + Messages.InputDialog(project, "New branch name:", dialogTitle, null, "", validator) { + + private lateinit var checkoutCheckbox : JBCheckBox + + fun showAndGetOptions(): GitNewBranchOptions? { + return if (showAndGet()) GitNewBranchOptions(inputString!!.trim(), checkoutCheckbox.isSelected) else null + } + + override fun createCenterPanel(): JComponent? { + checkoutCheckbox = JBCheckBox("Checkout branch", true) + checkoutCheckbox.mnemonic = KeyEvent.VK_C + + val panel = JBUI.Panels.simplePanel(DEFAULT_HGAP, DEFAULT_VGAP) + panel.add(checkoutCheckbox, BorderLayout.WEST) + return panel + } +} diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java index bce8008ea8fe..30d91d851c22 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java @@ -29,8 +29,10 @@ import com.intellij.openapi.ui.Messages; import com.intellij.util.containers.ContainerUtil; import git4idea.branch.GitBranchUtil; import git4idea.branch.GitBrancher; +import git4idea.branch.GitNewBranchOptions; import git4idea.repo.GitRepository; import git4idea.validators.GitNewBranchNameValidator; +import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -40,6 +42,7 @@ import java.util.List; import static com.intellij.dvcs.ui.BranchActionGroupPopup.wrapWithMoreActionIfNeeded; import static com.intellij.dvcs.ui.BranchActionUtil.*; import static git4idea.GitStatisticsCollectorKt.reportUsage; +import static git4idea.GitUtil.HEAD; import static git4idea.branch.GitBranchType.LOCAL; import static git4idea.branch.GitBranchType.REMOTE; import static java.util.stream.Collectors.toList; @@ -100,11 +103,17 @@ class GitBranchPopupActions { @Override public void actionPerformed(AnActionEvent e) { - final String name = GitBranchUtil.getNewBranchNameFromUser(myProject, myRepositories, "Create New Branch"); - if (name != null) { + GitNewBranchOptions options = GitBranchUtil.getNewBranchNameFromUser(myProject, myRepositories, "Create New Branch"); + if (options != null) { GitBrancher brancher = GitBrancher.getInstance(myProject); - brancher.checkoutNewBranch(name, myRepositories); - reportUsage("git.branch.create.new"); + if (options.shouldCheckout()) { + reportUsage("git.branch.create.new"); + brancher.checkoutNewBranch(options.getName(), myRepositories); + } + else { + reportUsage("git.branch.create.new.nocheckout"); + brancher.createBranch(options.getName(), StreamEx.of(myRepositories).toMap(position -> HEAD)); + } } } } diff --git a/plugins/git4idea/tests/git4idea/branch/GitBranchWorkerTest.kt b/plugins/git4idea/tests/git4idea/branch/GitBranchWorkerTest.kt index 45afe94eba7e..3dfaffa161c3 100644 --- a/plugins/git4idea/tests/git4idea/branch/GitBranchWorkerTest.kt +++ b/plugins/git4idea/tests/git4idea/branch/GitBranchWorkerTest.kt @@ -23,7 +23,6 @@ import com.intellij.openapi.ui.DialogWrapper import com.intellij.openapi.util.Ref import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.text.StringUtil -import com.intellij.openapi.vcs.Executor import com.intellij.openapi.vcs.Executor.* import com.intellij.openapi.vcs.changes.Change import com.intellij.openapi.vfs.VirtualFile @@ -56,13 +55,13 @@ class GitBranchWorkerTest : GitPlatformTest() { super.setUp() cd(myProjectRoot) - val community = Executor.mkdir("community") - val contrib = Executor.mkdir("contrib") + val community = mkdir("community") + val contrib = mkdir("contrib") myUltimate = createRepository(myProjectPath) myCommunity = createRepository(community.path) myContrib = createRepository(contrib.path) - myRepositories = Arrays.asList(myUltimate, myCommunity, myContrib) + myRepositories = listOf(myUltimate, myCommunity, myContrib) cd(myProjectRoot) touch(".gitignore", "community\ncontrib") @@ -75,8 +74,22 @@ class GitBranchWorkerTest : GitPlatformTest() { checkoutNewBranch("feature", TestUiHandler()) assertCurrentBranch("feature") - assertEquals("Notification about successful branch creation is incorrect", - "Branch " + bcode("feature") + " was created", myVcsNotifier.lastNotification.content) + assertSuccessfulNotification("Branch ${bcode("feature")} was created") + } + + fun `test create new branch without checkout not at HEAD`() { + val hashMap = myRepositories.map { it to it.currentRevision!! }.toMap() + myRepositories.forEach { cd(it); tac("f.txt") } + + GitBranchWorker(myProject, myGit, TestUiHandler()).createBranch("feature", myRepositories.map{ it to "HEAD^" }.toMap()) + + assertCurrentBranch("master") + myRepositories.forEach { + val branch = it.branches.findLocalBranch("feature") + assertNotNull("Branch not created in $it", branch) + assertEquals("Branch feature created at wrong point", hashMap[it], it.branches.getHash(branch!!)!!.asString()) + } + assertSuccessfulNotification("Branch ${bcode("feature")} was created") } fun test_create_new_branch_with_unmerged_files_in_first_repo_should_show_notification() { @@ -177,9 +190,7 @@ class GitBranchWorkerTest : GitPlatformTest() { unmergedFiles(myCommunity) checkoutBranch("feature", object : TestUiHandler() { - override fun showUnmergedFilesMessageWithRollback(operationName: String, rollbackProposal: String): Boolean { - return true - } + override fun showUnmergedFilesMessageWithRollback(operationName: String, rollbackProposal: String) = true }) assertCurrentBranch("master") @@ -190,9 +201,7 @@ class GitBranchWorkerTest : GitPlatformTest() { unmergedFiles(myCommunity) checkoutBranch("feature", object : TestUiHandler() { - override fun showUnmergedFilesMessageWithRollback(operationName: String, rollbackProposal: String): Boolean { - return false - } + override fun showUnmergedFilesMessageWithRollback(operationName: String, rollbackProposal: String) = false }) assertCurrentBranch(myUltimate, "feature") @@ -206,8 +215,7 @@ class GitBranchWorkerTest : GitPlatformTest() { checkoutRevision("feature", TestUiHandler()) assertDetachedState("feature") - assertEquals("Notification about successful branch checkout is incorrect", "Checked out " + bcode("feature"), - myVcsNotifier.lastNotification.content) + assertSuccessfulNotification("Checked out ${bcode("feature")}") } fun test_checkout_revision_checkout_ref_with_complete_success() { @@ -216,8 +224,7 @@ class GitBranchWorkerTest : GitPlatformTest() { checkoutRevision("feature~1", TestUiHandler()) assertDetachedState("master") - assertEquals("Notification about successful branch checkout is incorrect", "Checked out " + bcode("feature~1"), - myVcsNotifier.lastNotification.content) + assertSuccessfulNotification("Checked out ${bcode("feature~1")}") } fun test_checkout_revision_checkout_ref_with_complete_failure() { @@ -227,13 +234,11 @@ class GitBranchWorkerTest : GitPlatformTest() { assertCurrentBranch("master") assertCurrentRevision("master") - assertEquals("Notification about successful branch checkout is incorrect", - "Revision not found in project, community and contrib", - myVcsNotifier.lastNotification.content) + assertSuccessfulNotification("Revision not found in project, community and contrib") } fun test_checkout_revision_checkout_ref_with_partial_success() { - branchWithCommit(ContainerUtil.list(myCommunity, myContrib), "feature") + branchWithCommit(listOf(myCommunity, myContrib), "feature") checkoutRevision("feature", TestUiHandler()) @@ -241,10 +246,8 @@ class GitBranchWorkerTest : GitPlatformTest() { assertDetachedState(myCommunity, "feature") assertDetachedState(myContrib, "feature") - assertEquals("Notification about successful branch checkout is incorrect", - "Checked out " + bcode("feature") + " in community and contrib" + "
" + - "Revision not found in project" + "
Rollback", - myVcsNotifier.lastNotification.content) + assertSuccessfulNotification("Checked out ${bcode("feature")} in community and contrib
" + + "Revision not found in project
Rollback") } fun test_checkout_with_untracked_files_overwritten_by_checkout_in_first_repo_should_show_notification() { @@ -369,13 +372,8 @@ class GitBranchWorkerTest : GitPlatformTest() { private fun agree_to_smart_operation(operation: String, expectedSuccessMessage: String): List { val localChanges = prepareLocalChangesOverwrittenBy(myUltimate) - - val handler = TestUiHandler() - checkoutOrMerge(operation, "feature", handler) - - assertNotNull("No success notification was shown", myVcsNotifier.lastNotification) - assertEquals("Success message is incorrect", expectedSuccessMessage, myVcsNotifier.lastNotification.content) - + checkoutOrMerge(operation, "feature", TestUiHandler()) + assertSuccessfulNotification(expectedSuccessMessage) return localChanges } @@ -407,9 +405,7 @@ class GitBranchWorkerTest : GitPlatformTest() { changes: List, paths: Collection, operation: String, - forceButton: String?): Int { - return GitSmartOperationDialog.CANCEL_EXIT_CODE - } + forceButton: String?) = GitSmartOperationDialog.CANCEL_EXIT_CODE }) assertNull("Notification was unexpectedly shown:" + myVcsNotifier.lastNotification, myVcsNotifier.lastNotification) @@ -436,9 +432,7 @@ class GitBranchWorkerTest : GitPlatformTest() { changes: List, paths: Collection, operation: String, - forceButton: String?): Int { - return GitSmartOperationDialog.CANCEL_EXIT_CODE - } + forceButton: String?) = GitSmartOperationDialog.CANCEL_EXIT_CODE override fun notifyErrorWithRollbackProposal(title: String, message: String, @@ -460,15 +454,11 @@ class GitBranchWorkerTest : GitPlatformTest() { changes: List, paths: Collection, operation: String, - forceButton: String?): Int { - return GitSmartOperationDialog.FORCE_EXIT_CODE - } + forceButton: String?) = GitSmartOperationDialog.FORCE_EXIT_CODE }) brancher.checkoutNewBranchStartingFrom("new_branch", "feature", myRepositories) - assertEquals("Notification about successful branch creation is incorrect", - "Checked out new branch new_branch from feature", - myVcsNotifier.lastNotification.content) + assertSuccessfulNotification("Checked out new branch new_branch from feature") assertCurrentBranch("new_branch") } @@ -547,9 +537,7 @@ class GitBranchWorkerTest : GitPlatformTest() { override fun showBranchIsNotFullyMergedDialog(project: Project, history: Map>, baseBranches: Map, - removedBranch: String): Boolean { - return true - } + removedBranch: String) = true }) assertBranchDeleted("todelete") } @@ -639,9 +627,7 @@ class GitBranchWorkerTest : GitPlatformTest() { mergeBranch("master2", TestUiHandler()) - assertNotNull("Success message wasn't shown", myVcsNotifier.lastNotification) - assertEquals("Success message is incorrect", - "Merged " + bcode("master2") + " to " + bcode("master") + "
Delete master2", + assertSuccessfulNotification("Merged " + bcode("master2") + " to " + bcode("master") + "
Delete master2", myVcsNotifier.lastNotification.content) assertFile(myUltimate, "branch_file.txt", "branch content") assertFile(myCommunity, "branch_file.txt", "branch content")