From 78372a5c82423e40875027b72d3be5ae99d592e0 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 30 Jan 2012 18:24:54 +0400 Subject: [PATCH] IDEA-76794 Add "force checkout" option to the smart checkout dialog. --- .../branch/GitCheckoutNewBranchOperation.java | 2 +- .../git4idea/branch/GitCheckoutOperation.java | 23 ++++++++------ ...GitWouldBeOverwrittenByCheckoutDialog.java | 31 ++++++++++++++----- .../git4idea/src/git4idea/commands/Git.java | 7 ++++- 4 files changed, 44 insertions(+), 19 deletions(-) diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java index 28396fdde88c..f7bfa21ecd7c 100644 --- a/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java @@ -104,7 +104,7 @@ public class GitCheckoutNewBranchOperation extends GitBranchOperation { GitCompoundResult deleteResult = new GitCompoundResult(myProject); Collection repositories = getSuccessfulRepositories(); for (GitRepository repository : repositories) { - GitCommandResult result = Git.checkout(repository, myPreviousBranch, null); + GitCommandResult result = Git.checkout(repository, myPreviousBranch, null, true); checkoutResult.append(repository, result); if (result.success()) { deleteResult.append(repository, Git.branchDelete(repository, myNewBranchName, false)); diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java index 9be5f1e1f0e9..06f93d1c9233 100644 --- a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java @@ -96,7 +96,7 @@ public class GitCheckoutOperation extends GitBranchOperation { GitSimpleEventDetector unmergedFiles = new GitSimpleEventDetector(GitSimpleEventDetector.Event.UNMERGED); GitMessageWithFilesDetector untrackedOverwrittenByCheckout = new GitMessageWithFilesDetector(UNTRACKED_FILES_OVERWRITTEN_BY, root); - GitCommandResult result = Git.checkout(repository, myStartPointReference, myNewBranch, + GitCommandResult result = Git.checkout(repository, myStartPointReference, myNewBranch, false, localChangesOverwrittenByCheckout, unmergedFiles, untrackedOverwrittenByCheckout); if (result.success()) { refresh(repository); @@ -134,13 +134,14 @@ public class GitCheckoutOperation extends GitBranchOperation { // get all other conflicting changes Map> conflictingChangesInRepositories = collectLocalChangesOnAllOtherRepositories(repository); Set otherProblematicRepositories = conflictingChangesInRepositories.keySet(); - Collection allConflictingRepositories = new ArrayList(otherProblematicRepositories); + List allConflictingRepositories = new ArrayList(otherProblematicRepositories); allConflictingRepositories.add(repository); for (List changes : conflictingChangesInRepositories.values()) { affectedChanges.addAll(changes); } - if (GitWouldBeOverwrittenByCheckoutDialog.showAndGetAnswer(myProject, affectedChanges)) { + int smartCheckoutDecision = GitWouldBeOverwrittenByCheckoutDialog.showAndGetAnswer(myProject, affectedChanges); + if (smartCheckoutDecision == GitWouldBeOverwrittenByCheckoutDialog.SMART_CHECKOUT) { boolean smartCheckedOutSuccessfully = smartCheckout(allConflictingRepositories, myStartPointReference, myNewBranch, getIndicator()); if (smartCheckedOutSuccessfully) { GitRepository[] otherRepositories = ArrayUtil.toObjectArray(otherProblematicRepositories, GitRepository.class); @@ -156,6 +157,9 @@ public class GitCheckoutOperation extends GitBranchOperation { return false; } } + else if (smartCheckoutDecision == GitWouldBeOverwrittenByCheckoutDialog.FORCE_CHECKOUT_EXIT_CODE) { + return checkoutOrNotify(allConflictingRepositories, myStartPointReference, myNewBranch, true); + } else { fatalLocalChangesError(); return false; @@ -248,7 +252,7 @@ public class GitCheckoutOperation extends GitBranchOperation { GitCompoundResult checkoutResult = new GitCompoundResult(myProject); GitCompoundResult deleteResult = new GitCompoundResult(myProject); for (GitRepository repository : getSuccessfulRepositories()) { - GitCommandResult result = Git.checkout(repository, myPreviousBranch, null); + GitCommandResult result = Git.checkout(repository, myPreviousBranch, null, true); checkoutResult.append(repository, result); if (result.success() && myNewBranch != null) { /* @@ -310,7 +314,7 @@ public class GitCheckoutOperation extends GitBranchOperation { } // stash - checkout - unstash - private boolean smartCheckout(@NotNull final Collection repositories, @NotNull final String reference, @Nullable final String newBranch, @NotNull ProgressIndicator indicator) { + private boolean smartCheckout(@NotNull final List repositories, @NotNull final String reference, @Nullable final String newBranch, @NotNull ProgressIndicator indicator) { final GitChangesSaver saver = configureSaver(reference, indicator); final AtomicBoolean result = new AtomicBoolean(); @@ -319,7 +323,7 @@ public class GitCheckoutOperation extends GitBranchOperation { boolean savedSuccessfully = save(repositories, saver); if (savedSuccessfully) { try { - result.set(checkoutOrNotify(repositories, reference, newBranch)); + result.set(checkoutOrNotify(repositories, reference, newBranch, false)); } finally { saver.restoreLocalChanges(context); } @@ -384,12 +388,11 @@ public class GitCheckoutOperation extends GitBranchOperation { /** * Checks out or shows an error message. */ - private boolean checkoutOrNotify(@NotNull Collection repositories, - @NotNull String reference, - @Nullable String newBranch) { + private boolean checkoutOrNotify(@NotNull List repositories, + @NotNull String reference, @Nullable String newBranch, boolean force) { GitCompoundResult compoundResult = new GitCompoundResult(myProject); for (GitRepository repository : repositories) { - compoundResult.append(repository, Git.checkout(repository, reference, newBranch)); + compoundResult.append(repository, Git.checkout(repository, reference, newBranch, force)); } if (compoundResult.totalSuccess()) { return true; diff --git a/plugins/git4idea/src/git4idea/branch/GitWouldBeOverwrittenByCheckoutDialog.java b/plugins/git4idea/src/git4idea/branch/GitWouldBeOverwrittenByCheckoutDialog.java index f281e4a1f718..ad60e17fcc44 100644 --- a/plugins/git4idea/src/git4idea/branch/GitWouldBeOverwrittenByCheckoutDialog.java +++ b/plugins/git4idea/src/git4idea/branch/GitWouldBeOverwrittenByCheckoutDialog.java @@ -26,8 +26,9 @@ import git4idea.DialogManager; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import java.awt.event.ActionEvent; import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; /** * The dialog that is shown when the error "The following files would be overwritten by checkout" happens. @@ -38,23 +39,26 @@ import java.util.concurrent.atomic.AtomicBoolean; // TODO "don't ask again" option class GitWouldBeOverwrittenByCheckoutDialog extends DialogWrapper { + public static final int SMART_CHECKOUT = OK_EXIT_CODE; + public static final int FORCE_CHECKOUT_EXIT_CODE = NEXT_USER_EXIT_CODE; + private final Project myProject; private final List myChanges; /** * @return true if smart checkout has to be performed, false if user doesn't want to checkout. */ - static boolean showAndGetAnswer(@NotNull final Project project, @NotNull final List changes) { - final AtomicBoolean ok = new AtomicBoolean(); + static int showAndGetAnswer(@NotNull final Project project, @NotNull final List changes) { + final AtomicInteger exitCode = new AtomicInteger(); UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { GitWouldBeOverwrittenByCheckoutDialog dialog = new GitWouldBeOverwrittenByCheckoutDialog(project, changes); DialogManager.getInstance(project).showDialog(dialog); - ok.set(dialog.isOK()); + exitCode.set(dialog.getExitCode()); } }); - return ok.get(); + return exitCode.get(); } private GitWouldBeOverwrittenByCheckoutDialog(@NotNull Project project, @NotNull List changes) { @@ -68,8 +72,8 @@ class GitWouldBeOverwrittenByCheckoutDialog extends DialogWrapper { } @Override - protected Action getOKAction() { - return super.getOKAction(); + protected Action[] createLeftSideActions() { + return new Action[] {new ForceCheckoutAction() }; } @Override @@ -93,4 +97,17 @@ class GitWouldBeOverwrittenByCheckoutDialog extends DialogWrapper { return GitWouldBeOverwrittenByCheckoutDialog.class.getName(); } + + private class ForceCheckoutAction extends AbstractAction { + + ForceCheckoutAction() { + super("Force checkout"); + } + + @Override + public void actionPerformed(ActionEvent e) { + close(FORCE_CHECKOUT_EXIT_CODE); + } + } + } diff --git a/plugins/git4idea/src/git4idea/commands/Git.java b/plugins/git4idea/src/git4idea/commands/Git.java index 8f47061ad11c..ebe5b02a9f0e 100644 --- a/plugins/git4idea/src/git4idea/commands/Git.java +++ b/plugins/git4idea/src/git4idea/commands/Git.java @@ -138,12 +138,17 @@ public class Git { public static GitCommandResult checkout(@NotNull GitRepository repository, @NotNull String reference, @Nullable String newBranch, + boolean force, @NotNull GitLineHandlerListener... listeners) { final GitLineHandler h = new GitLineHandler(repository.getProject(), repository.getRoot(), GitCommand.CHECKOUT); h.setSilent(false); + if (force) { + h.addParameters("--force"); + } if (newBranch == null) { // simply checkout h.addParameters(reference); - } else { // checkout reference as new branch + } + else { // checkout reference as new branch h.addParameters("-b", newBranch, reference); } for (GitLineHandlerListener listener : listeners) {