From 85bf22894c42005f936c63cdc26a92126977ec75 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 21 Jun 2012 17:31:45 +0400 Subject: [PATCH] [git] IDEA-87609 When updating via Rebase, use merge instead of rebase, if it is fast-forward. Before starting the normal update procedure (with possible stash-unstash), try to perform a fast-forward merge instead of rebase, because it is equal to fast-forward rebase, but is faster, because doesn't require stash-unstash (unless the uncommitted files would be overwritten by merge) Any failure in 'git merge --ff-only' means, than this repository will then be updated in a usual manner. No pre-checking if a fast-forward merge is possible is done, because it is fast enough to execute the command and get the error. --- .../git4idea/branch/GitMergeOperation.java | 4 +-- .../git4idea/src/git4idea/commands/Git.java | 3 ++- .../src/git4idea/commands/GitImpl.java | 5 +++- .../src/git4idea/update/GitRebaseUpdater.java | 26 +++++++++++++++++-- .../src/git4idea/update/GitUpdateProcess.java | 20 +++++++++++++- .../tests/git4idea/test/MockGit.groovy | 3 ++- 6 files changed, 53 insertions(+), 8 deletions(-) diff --git a/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java b/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java index 8235466851b9..2081313b5bd7 100644 --- a/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java @@ -93,7 +93,7 @@ class GitMergeOperation extends GitBranchOperation { GitSimpleEventDetector mergeConflict = new GitSimpleEventDetector(GitSimpleEventDetector.Event.MERGE_CONFLICT); GitSimpleEventDetector alreadyUpToDateDetector = new GitSimpleEventDetector(GitSimpleEventDetector.Event.ALREADY_UP_TO_DATE); - GitCommandResult result = myGit.merge(repository, myBranchToMerge, + GitCommandResult result = myGit.merge(repository, myBranchToMerge, Collections.emptyList(), localChangesOverwrittenByMerge, unmergedFiles, untrackedOverwrittenByMerge, mergeConflict, alreadyUpToDateDetector); if (result.success()) { @@ -238,7 +238,7 @@ class GitMergeOperation extends GitBranchOperation { private boolean doMerge(@NotNull Collection repositories) { for (GitRepository repository : repositories) { GitSimpleEventDetector mergeConflict = new GitSimpleEventDetector(GitSimpleEventDetector.Event.MERGE_CONFLICT); - GitCommandResult result = myGit.merge(repository, myBranchToMerge, mergeConflict); + GitCommandResult result = myGit.merge(repository, myBranchToMerge, Collections.emptyList(), mergeConflict); if (!result.success()) { if (mergeConflict.hasHappened()) { myConflictedRepositories.put(repository, Boolean.TRUE); diff --git a/plugins/git4idea/src/git4idea/commands/Git.java b/plugins/git4idea/src/git4idea/commands/Git.java index beb4ffaf0b54..040a34e4541b 100644 --- a/plugins/git4idea/src/git4idea/commands/Git.java +++ b/plugins/git4idea/src/git4idea/commands/Git.java @@ -49,7 +49,8 @@ public interface Git { GitCommandResult clone(@NotNull Project project, @NotNull File parentDirectory, @NotNull String url, @NotNull String clonedDirectoryName); @NotNull - GitCommandResult merge(@NotNull GitRepository repository, @NotNull String branchToMerge, @NotNull GitLineHandlerListener... listeners); + GitCommandResult merge(@NotNull GitRepository repository, @NotNull String branchToMerge, @Nullable List additionalParams, + @NotNull GitLineHandlerListener... listeners); @NotNull GitCommandResult checkout(@NotNull GitRepository repository, @NotNull String reference, @Nullable String newBranch, boolean force, diff --git a/plugins/git4idea/src/git4idea/commands/GitImpl.java b/plugins/git4idea/src/git4idea/commands/GitImpl.java index 29d6be84a3cb..2a34b0abf9a0 100644 --- a/plugins/git4idea/src/git4idea/commands/GitImpl.java +++ b/plugins/git4idea/src/git4idea/commands/GitImpl.java @@ -139,10 +139,13 @@ public class GitImpl implements Git { @Override @NotNull public GitCommandResult merge(@NotNull GitRepository repository, @NotNull String branchToMerge, - @NotNull GitLineHandlerListener... listeners) { + @Nullable List additionalParams, @NotNull GitLineHandlerListener... listeners) { final GitLineHandler mergeHandler = new GitLineHandler(repository.getProject(), repository.getRoot(), GitCommand.MERGE); mergeHandler.setSilent(false); mergeHandler.addParameters(branchToMerge); + if (additionalParams != null) { + mergeHandler.addParameters(additionalParams); + } for (GitLineHandlerListener listener : listeners) { mergeHandler.addLineListener(listener); } diff --git a/plugins/git4idea/src/git4idea/update/GitRebaseUpdater.java b/plugins/git4idea/src/git4idea/update/GitRebaseUpdater.java index be59067a6cfb..7dcf1ab17c60 100644 --- a/plugins/git4idea/src/git4idea/update/GitRebaseUpdater.java +++ b/plugins/git4idea/src/git4idea/update/GitRebaseUpdater.java @@ -24,12 +24,15 @@ import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.update.UpdatedFiles; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ui.UIUtil; +import git4idea.GitBranch; +import git4idea.GitUtil; import git4idea.PlatformFacade; import git4idea.branch.GitBranchPair; import git4idea.commands.*; import git4idea.merge.GitConflictResolver; import git4idea.rebase.GitRebaseProblemDetector; import git4idea.rebase.GitRebaser; +import git4idea.repo.GitRepository; import git4idea.util.GitUIUtil; import git4idea.util.UntrackedFilesNotifier; import org.jetbrains.annotations.NotNull; @@ -60,8 +63,7 @@ public class GitRebaseUpdater extends GitUpdater { protected GitUpdateResult doUpdate() { LOG.info("doUpdate "); - GitBranchPair gitBranchPair = myTrackedBranches.get(myRoot); - String remoteBranch = gitBranchPair.getDest().getName(); + String remoteBranch = getRemoteBranchToMerge(); final GitLineHandler rebaseHandler = new GitLineHandler(myProject, myRoot, GitCommand.REBASE); rebaseHandler.addParameters(remoteBranch); @@ -99,6 +101,15 @@ public class GitRebaseUpdater extends GitUpdater { return updateResult.get(); } + @NotNull + private String getRemoteBranchToMerge() { + GitBranchPair gitBranchPair = myTrackedBranches.get(myRoot); + GitBranch dest = gitBranchPair.getDest(); + LOG.assertTrue(dest != null, String.format("Destination branch is null for source branch %s in %s", + gitBranchPair.getBranch().getName(), myRoot)); + return dest.getName(); + } + private GitUpdateResult handleRebaseFailure(GitLineHandler pullHandler, GitRebaseProblemDetector rebaseConflictDetector, final GitMessageWithFilesDetector untrackedWouldBeOverwrittenDetector) { @@ -159,6 +170,17 @@ public class GitRebaseUpdater extends GitUpdater { return "Rebase updater"; } + public boolean fastForwardMerge() { + LOG.info("Trying fast-forward merge for " + myRoot); + GitRepository repository = GitUtil.getRepositoryManager(myProject).getRepositoryForRoot(myRoot); + if (repository == null) { + LOG.error("Repository is null for " + myRoot); + return false; + } + GitCommandResult result = myGit.merge(repository, getRemoteBranchToMerge(), Collections.singletonList("--ff-only")); + return result.success(); + } + private static class MyConflictResolver extends GitConflictResolver { private final GitRebaser myRebaser; private final VirtualFile myRoot; diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java index f9d260aeb43b..8ff7f9dc0049 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java @@ -134,7 +134,7 @@ public class GitUpdateProcess { @NotNull private GitUpdateResult updateImpl(@NotNull UpdateMethod updateMethod, ContinuationContext context) { - final Map updaters; + Map updaters; try { updaters = defineUpdaters(updateMethod); } @@ -144,6 +144,8 @@ public class GitUpdateProcess { return GitUpdateResult.ERROR; } + updaters = tryFastForwardMergeForRebaseUpdaters(updaters); + if (updaters.isEmpty()) { return GitUpdateResult.NOTHING_TO_UPDATE; } @@ -204,6 +206,22 @@ public class GitUpdateProcess { return compoundResult; } + @NotNull + private static Map tryFastForwardMergeForRebaseUpdaters(@NotNull Map updaters) { + Map modifiedUpdaters = new HashMap(); + for (Map.Entry updaterEntry : updaters.entrySet()) { + GitUpdater updater = updaterEntry.getValue(); + if (updater instanceof GitRebaseUpdater) { + GitRebaseUpdater rebaseUpdater = (GitRebaseUpdater) updater; + if (rebaseUpdater.fastForwardMerge()) { + continue; + } + } + modifiedUpdaters.put(updaterEntry.getKey(), updaterEntry.getValue()); + } + return modifiedUpdaters; + } + @NotNull private Map defineUpdaters(@NotNull UpdateMethod updateMethod) throws VcsException { final Map updaters = new HashMap(); diff --git a/plugins/git4idea/tests/git4idea/test/MockGit.groovy b/plugins/git4idea/tests/git4idea/test/MockGit.groovy index 63d93c6e0628..9b7b12e40167 100644 --- a/plugins/git4idea/tests/git4idea/test/MockGit.groovy +++ b/plugins/git4idea/tests/git4idea/test/MockGit.groovy @@ -88,7 +88,8 @@ class MockGit implements Git { @NotNull @Override - GitCommandResult merge(@NotNull GitRepository repository, @NotNull String branchToMerge, @NotNull GitLineHandlerListener... listeners) { + GitCommandResult merge(@NotNull GitRepository repository, @NotNull String branchToMerge, @Nullable List additionalParams, + @NotNull GitLineHandlerListener... listeners) { throw new UnsupportedOperationException() }