diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchWorker.java b/plugins/git4idea/src/git4idea/branch/GitBranchWorker.java index faf8e1a8c686..01177699a002 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchWorker.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchWorker.java @@ -133,6 +133,11 @@ public final class GitBranchWorker { myUiHandler.getProgressIndicator()); } + public void renameBranch(@NotNull String currentName, @NotNull String newName, @NotNull List repositories) { + updateInfo(repositories); + new GitRenameBranchOperation(myProject, myFacade, myGit, myUiHandler, currentName, newName, repositories).execute(); + } + public void compare(@NotNull final String branchName, @NotNull final List repositories, @NotNull final GitRepository selectedRepository) { final GitCommitCompareInfo myCompareInfo = loadCommitsToCompare(repositories, branchName); diff --git a/plugins/git4idea/src/git4idea/branch/GitBrancher.java b/plugins/git4idea/src/git4idea/branch/GitBrancher.java index e73a9f9aa0f4..4431bbef9238 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBrancher.java +++ b/plugins/git4idea/src/git4idea/branch/GitBrancher.java @@ -139,6 +139,11 @@ public interface GitBrancher { */ void rebaseOnCurrent(@NotNull List repositories, @NotNull String branchName); + /** + * Renames the given branch. + */ + void renameBranch(@NotNull String currentName, @NotNull String newName, @NotNull List repositories); + /** * What should be done after successful merging a branch: delete the merged branch, propose to delete or do nothing. */ diff --git a/plugins/git4idea/src/git4idea/branch/GitBrancherImpl.java b/plugins/git4idea/src/git4idea/branch/GitBrancherImpl.java index 42f14d06422b..3ac8293a42bf 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBrancherImpl.java +++ b/plugins/git4idea/src/git4idea/branch/GitBrancherImpl.java @@ -151,6 +151,16 @@ class GitBrancherImpl implements GitBrancher { }.runInBackground(); } + @Override + public void renameBranch(@NotNull final String currentName, @NotNull final String newName, @NotNull final List repositories) { + new CommonBackgroundTask(myProject, "Renaming " + currentName + " to " + newName + "...", null) { + @Override + void execute(@NotNull ProgressIndicator indicator) { + newWorker(indicator).renameBranch(currentName, newName, repositories); + } + }.runInBackground(); + } + /** * Executes common operations before/after executing the actual branch operation. */ diff --git a/plugins/git4idea/src/git4idea/branch/GitRenameBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitRenameBranchOperation.java new file mode 100644 index 000000000000..0faf227f760f --- /dev/null +++ b/plugins/git4idea/src/git4idea/branch/GitRenameBranchOperation.java @@ -0,0 +1,104 @@ +/* + * Copyright 2000-2016 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.GitPlatformFacade; +import git4idea.commands.Git; +import git4idea.commands.GitCommandResult; +import git4idea.commands.GitCompoundResult; +import git4idea.repo.GitRepository; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.List; + +public class GitRenameBranchOperation extends GitBranchOperation { + @NotNull private final VcsNotifier myNotifier; + @NotNull private final String myCurrentName; + @NotNull private final String myNewName; + + public GitRenameBranchOperation(@NotNull Project project, + @NotNull GitPlatformFacade facade, + @NotNull Git git, + @NotNull GitBranchUiHandler uiHandler, + @NotNull String currentName, + @NotNull String newName, + @NotNull List repositories) { + super(project, facade, git, uiHandler, repositories); + myCurrentName = currentName; + myNewName = newName; + myNotifier = VcsNotifier.getInstance(myProject); + } + + @Override + protected void execute() { + while (hasMoreRepositories()) { + GitRepository repository = next(); + GitCommandResult result = myGit.renameBranch(repository, myCurrentName, myNewName); + if (result.success()) { + refresh(repository); + markSuccessful(repository); + } + else { + fatalError("Couldn't rename " + myCurrentName + " to " + myNewName, result.getErrorOutputAsJoinedString()); + return; + } + } + notifySuccess(); + } + + @Override + protected void rollback() { + GitCompoundResult result = new GitCompoundResult(myProject); + Collection repositories = getSuccessfulRepositories(); + for (GitRepository repository : repositories) { + result.append(repository, myGit.renameBranch(repository, myNewName, myCurrentName)); + refresh(repository); + } + if (result.totalSuccess()) { + myNotifier.notifySuccess("Rollback Successful", "Renamed back to " + myCurrentName); + } + else { + myNotifier.notifyError("Rollback Failed", result.getErrorOutputWithReposIndication()); + } + } + + @NotNull + @Override + public String getSuccessMessage() { + return String.format("Branch %s was renamed to %s", myCurrentName, myNewName); + } + + @NotNull + @Override + protected String getRollbackProposal() { + return "However rename has succeeded for the following " + repositories() + ":
" + + successfulRepositoriesJoined() + + "
You may rollback (rename branch back to " + myCurrentName + ") not to let branches diverge."; + } + + @NotNull + @Override + protected String getOperationName() { + return "rename"; + } + + private static void refresh(@NotNull GitRepository repository) { + repository.update(); + } +} diff --git a/plugins/git4idea/src/git4idea/commands/Git.java b/plugins/git4idea/src/git4idea/commands/Git.java index 79ae680a02b0..d6ae90eece6d 100644 --- a/plugins/git4idea/src/git4idea/commands/Git.java +++ b/plugins/git4idea/src/git4idea/commands/Git.java @@ -103,6 +103,12 @@ public interface Git { @NotNull GitCommandResult branchCreate(@NotNull GitRepository repository, @NotNull String branchName); + @NotNull + GitCommandResult renameBranch(@NotNull GitRepository repository, + @NotNull String currentName, + @NotNull String newName, + @NotNull GitLineHandlerListener... listeners); + @NotNull GitCommandResult reset(@NotNull GitRepository repository, @NotNull GitResetMode mode, @NotNull String target, @NotNull GitLineHandlerListener... listeners); diff --git a/plugins/git4idea/src/git4idea/commands/GitImpl.java b/plugins/git4idea/src/git4idea/commands/GitImpl.java index 9b43b73128d6..a3c6ff3aeb7c 100644 --- a/plugins/git4idea/src/git4idea/commands/GitImpl.java +++ b/plugins/git4idea/src/git4idea/commands/GitImpl.java @@ -363,6 +363,18 @@ public class GitImpl implements Git { return run(h); } + @NotNull + @Override + public GitCommandResult renameBranch(@NotNull GitRepository repository, + @NotNull String currentName, + @NotNull String newName, + @NotNull GitLineHandlerListener... listeners) { + GitLineHandler h = new GitLineHandler(repository.getProject(), repository.getRoot(), GitCommand.BRANCH); + h.setStdoutSuppressed(false); + h.addParameters("-m", currentName, newName); + return run(h); + } + @Override @NotNull public GitCommandResult reset(@NotNull GitRepository repository, @NotNull GitResetMode mode, @NotNull String target, diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java index d861cb51b6b2..adbb3e9e88c0 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java @@ -188,6 +188,7 @@ class GitBranchPopupActions { new RebaseAction(myProject, myRepositories, myBranchName), new CheckoutWithRebaseAction(myProject, myRepositories, myBranchName), new MergeAction(myProject, myRepositories, myBranchName, true), + new RenameBranchAction(myProject, myRepositories, myBranchName), new DeleteAction(myProject, myRepositories, myBranchName) }; } @@ -237,6 +238,31 @@ class GitBranchPopupActions { } } + private static class RenameBranchAction extends DumbAwareAction { + @NotNull private final Project myProject; + @NotNull private final List myRepositories; + @NotNull private final String myCurrentBranchName; + + public RenameBranchAction(@NotNull Project project, @NotNull List repositories, @NotNull String currentBranchName) { + super("Rename"); + myProject = project; + myRepositories = repositories; + myCurrentBranchName = currentBranchName; + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + String newName = Messages.showInputDialog(myProject, "Enter new name for the branch " + myCurrentBranchName, + "Rename Branch " + myCurrentBranchName, + Messages.getQuestionIcon(), "", GitNewBranchNameValidator.newInstance(myRepositories)); + if (newName != null) { + GitBrancher brancher = ServiceManager.getService(myProject, GitBrancher.class); + brancher.renameBranch(myCurrentBranchName, newName, myRepositories); + reportUsage("git.branch.rename"); + } + } + } + private static class DeleteAction extends DumbAwareAction { private final Project myProject; private final List myRepositories;