IDEA-76794 Add "force checkout" option to the smart checkout dialog.
authorKirill Likhodedov <Kirill.Likhodedov@jetbrains.com>
Mon, 30 Jan 2012 14:24:54 +0000 (18:24 +0400)
committerKirill Likhodedov <Kirill.Likhodedov@jetbrains.com>
Mon, 30 Jan 2012 14:24:54 +0000 (18:24 +0400)
plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java
plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java
plugins/git4idea/src/git4idea/branch/GitWouldBeOverwrittenByCheckoutDialog.java
plugins/git4idea/src/git4idea/commands/Git.java

index 28396fdde88c72d3ea4ef20072af30ba4e720c96..f7bfa21ecd7cd0961068006b1333dcd55911ca03 100644 (file)
@@ -104,7 +104,7 @@ public class GitCheckoutNewBranchOperation extends GitBranchOperation {
     GitCompoundResult deleteResult = new GitCompoundResult(myProject);
     Collection<GitRepository> 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));
index 9be5f1e1f0e9696e7ad5fc6080c8f42a5aa26bc7..06f93d1c923351772f41142d60ba85db8ea9848f 100644 (file)
@@ -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<GitRepository, List<Change>> conflictingChangesInRepositories = collectLocalChangesOnAllOtherRepositories(repository);
     Set<GitRepository> otherProblematicRepositories = conflictingChangesInRepositories.keySet();
-    Collection<GitRepository> allConflictingRepositories = new ArrayList<GitRepository>(otherProblematicRepositories);
+    List<GitRepository> allConflictingRepositories = new ArrayList<GitRepository>(otherProblematicRepositories);
     allConflictingRepositories.add(repository);
     for (List<Change> 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<GitRepository> repositories, @NotNull final String reference, @Nullable final String newBranch, @NotNull ProgressIndicator indicator) {
+  private boolean smartCheckout(@NotNull final List<GitRepository> 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<GitRepository> repositories,
-                                                    @NotNull String reference,
-                                                    @Nullable String newBranch) {
+  private boolean checkoutOrNotify(@NotNull List<GitRepository> 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;
index f281e4a1f71876ffc5e6655cfbe5b552b278509b..ad60e17fcc44d31d85b4c98d6b6b85174c9cb530 100644 (file)
@@ -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<Change> 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<Change> changes) {
-    final AtomicBoolean ok = new AtomicBoolean();
+  static int showAndGetAnswer(@NotNull final Project project, @NotNull final List<Change> 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<Change> 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);
+    }
+  }
+
 }
index 8f47061ad11c8d85ee3f98c83293ae828bc029af..ebe5b02a9f0ee39699176f642430abc7f0d0c967 100644 (file)
@@ -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) {