mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
git: support old-school Pull & Merge actions to show a log tab with new commits instead of the file tree: IDEA-52643
There are several limitations for these actions to avoid complicating the code for not very frequent cases. If the restrictions are not met, the code just falls back to the previous behavior and shows a file tree. * Support only the case when a single branch is pulled from, i.e. octopus merges are not supported. * Don't support pulling to a detached HEAD, or to an empty repository. GitOrigin-RevId: e84c76f02f5cc21a37eef7f6cd47620d251dab36
This commit is contained in:
committed by
intellij-monorepo-bot
parent
0f70237a11
commit
c00917a7b8
@@ -51,6 +51,6 @@ public class GitMerge extends GitMergeAction {
|
||||
return null;
|
||||
}
|
||||
return new DialogState(dialog.getSelectedRoot(), GitBundle.message("merging.title", dialog.getSelectedRoot().getPath()),
|
||||
() -> dialog.handler());
|
||||
() -> dialog.handler(), dialog.getSelectedBranches());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,15 +4,21 @@ package git4idea.actions;
|
||||
import com.intellij.dvcs.DvcsUtil;
|
||||
import com.intellij.history.Label;
|
||||
import com.intellij.history.LocalHistory;
|
||||
import com.intellij.notification.Notification;
|
||||
import com.intellij.notification.NotificationAction;
|
||||
import com.intellij.openapi.application.AccessToken;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.VcsNotifier;
|
||||
import com.intellij.openapi.vcs.ex.ProjectLevelVcsManagerEx;
|
||||
import com.intellij.openapi.vcs.update.AbstractCommonUpdateAction;
|
||||
import com.intellij.openapi.vcs.update.ActionInfo;
|
||||
import com.intellij.openapi.vcs.update.UpdateInfoTree;
|
||||
import com.intellij.openapi.vcs.update.UpdatedFiles;
|
||||
@@ -20,9 +26,8 @@ import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.GuiUtils;
|
||||
import com.intellij.vcs.ViewUpdateInfoNotification;
|
||||
import git4idea.GitRevisionNumber;
|
||||
import git4idea.GitUtil;
|
||||
import git4idea.GitVcs;
|
||||
import git4idea.*;
|
||||
import git4idea.branch.GitBranchPair;
|
||||
import git4idea.commands.*;
|
||||
import git4idea.merge.GitConflictResolver;
|
||||
import git4idea.merge.GitMergeCommittingConflictResolver;
|
||||
@@ -30,6 +35,8 @@ import git4idea.merge.GitMerger;
|
||||
import git4idea.merge.MergeChangeCollector;
|
||||
import git4idea.repo.GitRepository;
|
||||
import git4idea.repo.GitRepositoryManager;
|
||||
import git4idea.update.GitUpdateInfoAsLog;
|
||||
import git4idea.update.GitUpdatedRanges;
|
||||
import git4idea.util.GitUIUtil;
|
||||
import git4idea.util.GitUntrackedFilesHelper;
|
||||
import git4idea.util.LocalChangesWouldBeOverwrittenHelper;
|
||||
@@ -39,19 +46,30 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.notification.NotificationType.INFORMATION;
|
||||
import static git4idea.commands.GitLocalChangesWouldBeOverwrittenDetector.Operation.MERGE;
|
||||
import static git4idea.update.GitUpdateSessionKt.getBodyForUpdateNotification;
|
||||
import static git4idea.update.GitUpdateSessionKt.getTitleForUpdateNotification;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.Collections.singletonMap;
|
||||
|
||||
abstract class GitMergeAction extends GitRepositoryAction {
|
||||
private static final Logger LOG = Logger.getInstance(GitMergeAction.class);
|
||||
|
||||
protected static class DialogState {
|
||||
final VirtualFile selectedRoot;
|
||||
final String progressTitle;
|
||||
final Computable<GitLineHandler> handlerProvider;
|
||||
DialogState(@NotNull VirtualFile root, @NotNull String title, @NotNull Computable<GitLineHandler> provider) {
|
||||
@NotNull private final List<String> selectedBranches;
|
||||
|
||||
DialogState(@NotNull VirtualFile root,
|
||||
@NotNull String title,
|
||||
@NotNull Computable<GitLineHandler> provider,
|
||||
@NotNull List<String> selectedBranches) {
|
||||
selectedRoot = root;
|
||||
progressTitle = title;
|
||||
handlerProvider = provider;
|
||||
this.selectedBranches = selectedBranches;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +97,22 @@ abstract class GitMergeAction extends GitRepositoryAction {
|
||||
new GitUntrackedFilesOverwrittenByOperationDetector(selectedRoot);
|
||||
GitSimpleEventDetector mergeConflict = new GitSimpleEventDetector(GitSimpleEventDetector.Event.MERGE_CONFLICT);
|
||||
|
||||
GitRepository repository = repositoryManager.getRepositoryForRoot(selectedRoot);
|
||||
assert repository != null : "Repository can't be null for root " + selectedRoot;
|
||||
|
||||
GitUpdatedRanges updatedRanges = null;
|
||||
if (repository.getCurrentBranch() != null && dialogState.selectedBranches.size() == 1) {
|
||||
String selectedBranch = StringUtil.trimStart(dialogState.selectedBranches.get(0), "remotes/");
|
||||
GitBranch targetBranch = repository.getBranches().findBranchByName(selectedBranch);
|
||||
if (targetBranch != null) {
|
||||
GitBranchPair refPair = new GitBranchPair(repository.getCurrentBranch(), targetBranch);
|
||||
updatedRanges = GitUpdatedRanges.calcInitialPositions(project, singletonMap(repository, refPair));
|
||||
}
|
||||
else {
|
||||
LOG.warn("Couldn't find the branch with name [" + selectedBranch + "]");
|
||||
}
|
||||
}
|
||||
|
||||
try (AccessToken ignore = DvcsUtil.workingTreeChangeStarted(project, getActionName())) {
|
||||
GitCommandResult result = git.runCommand(() -> {
|
||||
GitLineHandler handler = handlerProvider.compute();
|
||||
@@ -88,27 +122,28 @@ abstract class GitMergeAction extends GitRepositoryAction {
|
||||
return handler;
|
||||
});
|
||||
|
||||
GitRepository repository = repositoryManager.getRepositoryForRoot(selectedRoot);
|
||||
assert repository != null : "Repository can't be null for root " + selectedRoot;
|
||||
String revision = repository.getCurrentRevision();
|
||||
if (revision == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
GitRevisionNumber currentRev = new GitRevisionNumber(revision);
|
||||
handleResult(result, project, mergeConflict, localChangesDetector, untrackedFilesDetector, repository, currentRev, beforeLabel);
|
||||
handleResult(result, project, mergeConflict, localChangesDetector, untrackedFilesDetector, repository, currentRev, beforeLabel,
|
||||
updatedRanges);
|
||||
}
|
||||
}
|
||||
}.queue();
|
||||
}
|
||||
|
||||
private void handleResult(@NotNull GitCommandResult result,
|
||||
@NotNull Project project,
|
||||
@NotNull GitSimpleEventDetector mergeConflictDetector,
|
||||
@NotNull GitLocalChangesWouldBeOverwrittenDetector localChangesDetector,
|
||||
@NotNull GitUntrackedFilesOverwrittenByOperationDetector untrackedFilesDetector,
|
||||
@NotNull GitRepository repository,
|
||||
@NotNull GitRevisionNumber currentRev,
|
||||
@NotNull Label beforeLabel) {
|
||||
@NotNull Project project,
|
||||
@NotNull GitSimpleEventDetector mergeConflictDetector,
|
||||
@NotNull GitLocalChangesWouldBeOverwrittenDetector localChangesDetector,
|
||||
@NotNull GitUntrackedFilesOverwrittenByOperationDetector untrackedFilesDetector,
|
||||
@NotNull GitRepository repository,
|
||||
@NotNull GitRevisionNumber currentRev,
|
||||
@NotNull Label beforeLabel,
|
||||
@Nullable GitUpdatedRanges updatedRanges) {
|
||||
VirtualFile root = repository.getRoot();
|
||||
|
||||
if (mergeConflictDetector.hasHappened()) {
|
||||
@@ -118,10 +153,21 @@ abstract class GitMergeAction extends GitRepositoryAction {
|
||||
|
||||
if (result.success() || mergeConflictDetector.hasHappened()) {
|
||||
VfsUtil.markDirtyAndRefresh(false, true, false, root);
|
||||
List<VcsException> exceptions = new ArrayList<>();
|
||||
showUpdates(project, exceptions, root, currentRev, beforeLabel, getActionName());
|
||||
repository.update();
|
||||
GitVcs.getInstance(project).showErrors(exceptions, getActionName());
|
||||
if (updatedRanges != null && AbstractCommonUpdateAction.showsCustomNotification(singletonList(GitVcs.getInstance(project)))) {
|
||||
new GitUpdateInfoAsLog(project, updatedRanges.calcCurrentPositions(), (filesCount, commitCount, filteredCommits, viewCommits) -> {
|
||||
String title = getTitleForUpdateNotification(filesCount, commitCount);
|
||||
String content = getBodyForUpdateNotification(filesCount, commitCount, filteredCommits);
|
||||
Notification notification = VcsNotifier.STANDARD_NOTIFICATION.createNotification(title, content, INFORMATION, null);
|
||||
notification.addAction(NotificationAction.createSimple("View Commits", viewCommits));
|
||||
return notification;
|
||||
}).buildAndShowNotification();
|
||||
}
|
||||
else {
|
||||
List<VcsException> exceptions = new ArrayList<>();
|
||||
showUpdates(project, exceptions, root, currentRev, beforeLabel, getActionName());
|
||||
GitVcs.getInstance(project).showErrors(exceptions, getActionName());
|
||||
}
|
||||
}
|
||||
else if (localChangesDetector.wasMessageDetected()) {
|
||||
LocalChangesWouldBeOverwrittenHelper.showErrorNotification(project, repository.getRoot(), getActionName(),
|
||||
|
||||
@@ -57,7 +57,8 @@ public class GitPull extends GitMergeAction {
|
||||
GitRemote remote = GitUtil.findRemoteByName(repository, remoteOrUrl);
|
||||
final List<String> urls = remote == null ? Collections.singletonList(remoteOrUrl) : remote.getUrls();
|
||||
Computable<GitLineHandler> handlerProvider = () -> dialog.makeHandler(urls);
|
||||
return new DialogState(dialog.gitRoot(), GitBundle.message("pulling.title", dialog.getRemote()), handlerProvider);
|
||||
return new DialogState(dialog.gitRoot(), GitBundle.message("pulling.title", dialog.getRemote()), handlerProvider,
|
||||
dialog.getSelectedBranches());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ public class GitMergeDialog extends DialogWrapper {
|
||||
final ElementsChooser.ElementsMarkListener<String> listener = new ElementsChooser.ElementsMarkListener<String>() {
|
||||
@Override
|
||||
public void elementMarkChanged(final String element, final boolean isMarked) {
|
||||
setOKActionEnabled(myBranchChooser.getMarkedElements().size() != 0);
|
||||
setOKActionEnabled(getSelectedBranches().size() != 0);
|
||||
}
|
||||
};
|
||||
listener.elementMarkChanged(null, true);
|
||||
@@ -177,12 +177,16 @@ public class GitMergeDialog extends DialogWrapper {
|
||||
if (!GitMergeUtil.DEFAULT_STRATEGY.equals(strategy)) {
|
||||
h.addParameters("--strategy", strategy);
|
||||
}
|
||||
for (String branch : myBranchChooser.getMarkedElements()) {
|
||||
for (String branch : getSelectedBranches()) {
|
||||
h.addParameters(branch);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getSelectedBranches() {
|
||||
return myBranchChooser.getMarkedElements();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
|
||||
@@ -156,7 +156,7 @@ public class GitPullDialog extends DialogWrapper {
|
||||
setOKActionEnabled(false);
|
||||
return;
|
||||
}
|
||||
setOKActionEnabled(myBranchChooser.getMarkedElements().size() != 0);
|
||||
setOKActionEnabled(getSelectedBranches().size() != 0);
|
||||
}
|
||||
|
||||
public GitLineHandler makeHandler(@NotNull List<String> urls) {
|
||||
@@ -189,7 +189,7 @@ public class GitPullDialog extends DialogWrapper {
|
||||
h.addParameters("--progress");
|
||||
}
|
||||
|
||||
final List<String> markedBranches = myBranchChooser.getMarkedElements();
|
||||
final List<String> markedBranches = getSelectedBranches();
|
||||
String remote = getRemote();
|
||||
LOG.assertTrue(remote != null, "Selected remote can't be null here.");
|
||||
// git pull origin master (remote branch name in the format local to that remote)
|
||||
@@ -200,6 +200,11 @@ public class GitPullDialog extends DialogWrapper {
|
||||
return h;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getSelectedBranches() {
|
||||
return myBranchChooser.getMarkedElements();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String removeRemotePrefix(@NotNull String branch, @NotNull String remote) {
|
||||
String prefix = remote + "/";
|
||||
|
||||
@@ -71,8 +71,7 @@ class GitUpdateSession(private val project: Project,
|
||||
val title: String
|
||||
var content: String?
|
||||
val type: NotificationType
|
||||
val mainMessage = "$updatedFilesNumber ${pluralize("file", updatedFilesNumber)} " +
|
||||
"updated in $updatedCommitsNumber ${pluralize("commit", updatedCommitsNumber)}"
|
||||
val mainMessage = getTitleForUpdateNotification(updatedFilesNumber, updatedCommitsNumber)
|
||||
if (isCanceled) {
|
||||
title = "Project Partially Updated"
|
||||
content = mainMessage
|
||||
@@ -80,11 +79,7 @@ class GitUpdateSession(private val project: Project,
|
||||
}
|
||||
else {
|
||||
title = mainMessage
|
||||
content = when (filteredCommitsNumber) {
|
||||
null -> ""
|
||||
0 -> "No commits matching filters"
|
||||
else -> "$filteredCommitsNumber ${pluralize("commit", filteredCommitsNumber)} matching filters"
|
||||
}
|
||||
content = getBodyForUpdateNotification(updatedFilesNumber, updatedCommitsNumber, filteredCommitsNumber)
|
||||
type = NotificationType.INFORMATION
|
||||
}
|
||||
|
||||
@@ -99,3 +94,17 @@ class GitUpdateSession(private val project: Project,
|
||||
return VcsNotifier.STANDARD_NOTIFICATION.createNotification(title, content, type, null)
|
||||
}
|
||||
}
|
||||
|
||||
fun getTitleForUpdateNotification(updatedFilesNumber: Int, updatedCommitsNumber: Int): String {
|
||||
val files = pluralize("file", updatedFilesNumber)
|
||||
val commits = pluralize("commit", updatedCommitsNumber)
|
||||
return "$updatedFilesNumber $files updated in $updatedCommitsNumber $commits"
|
||||
}
|
||||
|
||||
fun getBodyForUpdateNotification(updatedFilesNumber: Int, updatedCommitsNumber: Int, filteredCommitsNumber: Int?): String {
|
||||
return when (filteredCommitsNumber) {
|
||||
null -> ""
|
||||
0 -> "No commits matching filters"
|
||||
else -> "$filteredCommitsNumber ${pluralize("commit", filteredCommitsNumber)} matching filters"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user