<action id="Git.Stash" class="git4idea.actions.GitStash" text="Stash Changes"/>
<action id="Git.Unstash" class="git4idea.actions.GitUnstash" text="UnStash Changes"/>
<separator/>
+ <action id="Git.Rebase" class="git4idea.actions.GitRebase" text="Rebase ..."/>
+ <action id="Git.Rebase.Abort" class="git4idea.actions.GitRebaseAbort" text="Abort Rebasing"/>
+ <action id="Git.Rebase.Continue" class="git4idea.actions.GitRebaseContinue" text="Continue Rebasing"/>
+ <action id="Git.Rebase.Skip" class="git4idea.actions.GitRebaseSkip" text="Skip Commit in Rebasing"/>
+ <separator/>
<add-to-group group-id="VcsGroup" anchor="last"/>
<add-to-group group-id="VcsGroups" anchor="last"/>
<applicationService
serviceInterface="org.jetbrains.git4idea.ssh.GitSSHService"
serviceImplementation="org.jetbrains.git4idea.ssh.GitSSHService"/>
+ <applicationService
+ serviceInterface="git4idea.rebase.GitRebaseEditorService"
+ serviceImplementation="git4idea.rebase.GitRebaseEditorService"/>
<ComponentRoamingType component="Git.Settings" type="DISABLED"/>
</extensions>
* Copyright 2007 Decentrix Inc
* Copyright 2007 Aspiro AS
* Copyright 2008 MQSoftware
+ * Copyright 2008 JetBrains s.r.o.
* Authors: gevession, Erlend Simonsen & Mark Scott
*
* This code was originally derived from the MKS & Mercurial IDEA VCS plugins
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.util.ArrayList;
import java.util.Collection;
-import java.util.List;
import java.util.StringTokenizer;
/**
* This data class represents a Git branch
*/
-public class GitBranch {
- private final Project project;
- private final String name;
- private final boolean remote;
- private final boolean active;
+public class GitBranch extends GitReference {
/**
- * The name that specifies that git is on specific commit rather then on some branch
+ * If true, the branch is remote
*/
- @NonNls public static final String NO_BRANCH_NAME = "(no " + GitHandler.BRANCH + ")";
-
- public GitBranch(@NotNull Project project, @NotNull String name, boolean active, boolean remote) {
- this.project = project;
- this.name = name;
- this.remote = remote;
- this.active = active;
- }
-
- @NotNull
- public Project getProject() {
- return project;
- }
+ private final boolean myRemote;
+ /**
+ * If true, the branch is active
+ */
+ private final boolean myActive;
+ /**
+ * The name that specifies that git is on specific commit rather then on some branch ({@value})
+ */
+ @NonNls public static final String NO_BRANCH_NAME = "(no branch)";
+ /**
+ * Prefix for local branches ({@value})
+ */
+ @NonNls public static final String REFS_HEADS_PREFIX = "refs/heads/";
+ /**
+ * Prefix for remote branches ({@value})
+ */
+ @NonNls public static final String REFS_REMOTES_PREFIX = "refs/remotes/";
- @NotNull
- public String getName() {
- return name;
+ /**
+ * The constructor for the branch
+ *
+ * @param name the name of the branch
+ * @param active if true, the branch is active
+ * @param remote if true, the branch is remote
+ */
+ public GitBranch(@NotNull String name, boolean active, boolean remote) {
+ super(name);
+ myRemote = remote;
+ myActive = active;
}
+ /**
+ * @return true if the branch is remtoe
+ */
public boolean isRemote() {
- return remote;
+ return myRemote;
}
+ /**
+ * @return true if the branch is active
+ */
public boolean isActive() {
- return active;
+ return myActive;
}
/**
return null;
}
else {
- return new GitBranch(project, line.substring(2), true, false);
+ return new GitBranch(line.substring(2), true, false);
}
}
}
* @param branches the collection used to store branches
* @throws VcsException if there is a problem with running git
*/
- public static void list(final Project project,
- final VirtualFile root,
- final boolean remote,
- final boolean local,
- final Collection<String> branches) throws VcsException {
+ public static void listAsStrings(final Project project,
+ final VirtualFile root,
+ final boolean remote,
+ final boolean local,
+ final Collection<String> branches) throws VcsException {
if (!local && !remote) {
// no need to run hanler
return;
}
/**
- * List tags for the git root
+ * {@inheritDoc}
+ */
+ @NotNull
+ public String getFullName() {
+ return (myRemote ? REFS_REMOTES_PREFIX : REFS_HEADS_PREFIX) + myName;
+ }
+
+ /**
+ * List branches for the git root
*
- * @param project the context
- * @param root the git root
- * @param tags the tag list
- * @throws com.intellij.openapi.vcs.VcsException
- * if there is a problem with running git
+ * @param project the context project
+ * @param root the git root
+ * @param remote if true remote branches are listed
+ * @param local if true local branches are listed
+ * @param branches the collection used to store branches
+ * @throws VcsException if there is a problem with running git
*/
- public static void listTags(final Project project, final VirtualFile root, final List<String> tags) throws VcsException {
- GitSimpleHandler handler = new GitSimpleHandler(project, root, GitHandler.TAG);
- handler.setNoSSH(true);
- handler.setSilent(true);
- handler.addParameters("-l");
- for (String line : handler.run().split("\n")) {
- if (line.length() == 0) {
- continue;
+ public static void list(final Project project,
+ final VirtualFile root,
+ final boolean local,
+ final boolean remote,
+ final Collection<GitBranch> branches) throws VcsException {
+ ArrayList<String> temp = new ArrayList<String>();
+ if (local) {
+ listAsStrings(project, root, false, true, temp);
+ for (String b : temp) {
+ branches.add(new GitBranch(b, false, false));
+ }
+ temp.clear();
+ }
+ if (remote) {
+ listAsStrings(project, root, true, false, temp);
+ for (String b : temp) {
+ branches.add(new GitBranch(b, false, true));
}
- tags.add(line);
}
}
}
--- /dev/null
+/*
+ * Copyright 2000-2008 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;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * The base class for named git references
+ */
+public abstract class GitReference implements Comparable<GitReference> {
+ /**
+ * The name of the reference
+ */
+ protected final String myName;
+
+ /**
+ * The constructor
+ *
+ * @param name the used name
+ */
+ public GitReference(@NotNull String name) {
+ myName = name;
+ }
+
+ /**
+ * @return the local name of the reference
+ */
+ @NotNull
+ public String getName() {
+ return myName;
+ }
+
+ /**
+ * @return the full name of the object
+ */
+ @NotNull
+ public abstract String getFullName();
+
+ /**
+ * @return the full name for the reference ({@link #getFullName()}.
+ */
+ @Override
+ public String toString() {
+ return getFullName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ return obj instanceof GitReference &&
+ toString().equals(obj.toString()); //To change body of overridden methods use File | Settings | File Templates.
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int compareTo(final GitReference o) {
+ return o == null ? 1 : getFullName().compareTo(o.getFullName());
+ }
+
+ /**
+ * Get name clashes for the for the sequence of the collections
+ *
+ * @param collections the collection list
+ * @return the conflict set
+ */
+ public static Set<String> getNameClashes(Collection<? extends GitReference>... collections) {
+ ArrayList<HashSet<String>> individual = new ArrayList<HashSet<String>>();
+ // collect individual key sets
+ for (Collection<? extends GitReference> c : collections) {
+ HashSet<String> s = new HashSet<String>();
+ individual.add(s);
+ for (GitReference r : c) {
+ s.add(r.getName());
+ }
+ }
+ HashSet<String> rc = new HashSet<String>();
+ // all pairs from array
+ for (int i = 0; i < collections.length - 1; i++) {
+ HashSet<String> si = individual.get(i);
+ for (int j = i + 1; j < collections.length; j++) {
+ HashSet<String> sj = individual.get(i);
+ final HashSet<String> copy = new HashSet<String>(si);
+ copy.retainAll(sj);
+ rc.addAll(copy);
+ }
+ }
+ return rc;
+ }
+}
--- /dev/null
+/*
+ * Copyright 2000-2008 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;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vcs.VcsException;
+import com.intellij.openapi.vfs.VirtualFile;
+import git4idea.commands.GitHandler;
+import git4idea.commands.GitSimpleHandler;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * The tag reference object
+ */
+public class GitTag extends GitReference {
+ /**
+ * Prefix for tags ({@value})
+ */
+ @NonNls public static final String REFS_TAGS_PREFIX = "refs/tags/";
+
+ /**
+ * The constructor
+ *
+ * @param name the used name
+ */
+ public GitTag(@NotNull String name) {
+ super(name);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @NotNull
+ public String getFullName() {
+ return REFS_TAGS_PREFIX + myName;
+ }
+
+ /**
+ * List tags for the git root
+ *
+ * @param project the context
+ * @param root the git root
+ * @param tags the tag list
+ * @throws com.intellij.openapi.vcs.VcsException
+ * if there is a problem with running git
+ */
+ public static void listAsStrings(final Project project, final VirtualFile root, final Collection<String> tags) throws VcsException {
+ GitSimpleHandler handler = new GitSimpleHandler(project, root, GitHandler.TAG);
+ handler.setNoSSH(true);
+ handler.setSilent(true);
+ handler.addParameters("-l");
+ for (String line : handler.run().split("\n")) {
+ if (line.length() == 0) {
+ continue;
+ }
+ tags.add(line);
+ }
+ }
+
+ /**
+ * List tags for the git root
+ *
+ * @param project the context
+ * @param root the git root
+ * @param tags the tag list
+ * @throws com.intellij.openapi.vcs.VcsException
+ * if there is a problem with running git
+ */
+ public static void list(final Project project, final VirtualFile root, final Collection<? super GitTag> tags) throws VcsException {
+ ArrayList<String> temp = new ArrayList<String>();
+ listAsStrings(project, root, temp);
+ for (String t : temp) {
+ tags.add(new GitTag(t));
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright 2000-2008 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.actions;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.vcs.VcsException;
+import com.intellij.openapi.vfs.VirtualFile;
+import git4idea.commands.GitHandler;
+import git4idea.commands.GitHandlerUtil;
+import git4idea.commands.GitSimpleHandler;
+import git4idea.i18n.GitBundle;
+import git4idea.rebase.GitRebaseActionDialog;
+import git4idea.rebase.GitRebaseUtils;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Base class for git rebase [--skip, --abort, and --continue] actions
+ */
+public abstract class GitAbstractRebaseAction extends GitRepositoryAction {
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void perform(@NotNull Project project,
+ @NotNull List<VirtualFile> gitRoots,
+ @NotNull VirtualFile defaultRoot,
+ Set<VirtualFile> affectedRoots,
+ List<VcsException> exceptions) throws VcsException {
+ // remote all roots where there are no rebase in progress
+ for (Iterator<VirtualFile> i = gitRoots.iterator(); i.hasNext();) {
+ if (!GitRebaseUtils.isRebaseInTheProgress(i.next())) {
+ i.remove();
+ }
+ }
+ if (gitRoots.size() == 0) {
+ Messages.showErrorDialog(project, GitBundle.getString("rebase.action.no.root"), GitBundle.getString("rebase.action.error"));
+ return;
+ }
+ final VirtualFile root;
+ if (gitRoots.size() == 1) {
+ root = gitRoots.get(0);
+ }
+ else {
+ if (!gitRoots.contains(defaultRoot)) {
+ defaultRoot = gitRoots.get(0);
+ }
+ GitRebaseActionDialog d = new GitRebaseActionDialog(project, getActionTitle(), gitRoots, defaultRoot);
+ root = d.selectRoot();
+ if (root == null) {
+ return;
+ }
+ }
+ GitSimpleHandler h = new GitSimpleHandler(project, root, GitHandler.REBASE);
+ h.addParameters(getOptionName());
+ GitHandlerUtil.doSynchronously(h, getActionTitle(), h.printableCommandLine());
+ }
+
+ /**
+ * @return title for rebase operation
+ */
+ @NonNls
+ protected abstract String getOptionName();
+
+ /**
+ * @return title for root selection dialog
+ */
+ protected abstract String getActionTitle();
+}
--- /dev/null
+package git4idea.actions;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.vcs.VcsException;
+import com.intellij.openapi.vfs.VirtualFile;
+import git4idea.commands.GitHandler;
+import git4idea.commands.GitHandlerUtil;
+import git4idea.commands.GitLineHandler;
+import git4idea.i18n.GitBundle;
+import git4idea.rebase.GitRebaseDialog;
+import git4idea.rebase.GitRebaseEditorHandler;
+import git4idea.rebase.GitRebaseEditorMain;
+import git4idea.rebase.GitRebaseEditorService;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Git rebase action
+ */
+public class GitRebase extends GitRepositoryAction {
+
+ /**
+ * {@inheritDoc}
+ */
+ @NotNull
+ protected String getActionName() {
+ return GitBundle.getString("rebase.action.name");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void perform(@NotNull final Project project,
+ @NotNull final List<VirtualFile> gitRoots,
+ @NotNull final VirtualFile defaultRoot,
+ final Set<VirtualFile> affectedRoots,
+ final List<VcsException> exceptions) throws VcsException {
+ GitRebaseDialog dialog = new GitRebaseDialog(project, gitRoots, defaultRoot);
+ dialog.show();
+ if (!dialog.isOK()) {
+ return;
+ }
+ GitLineHandler h = dialog.handler();
+ GitRebaseEditorService service = GitRebaseEditorService.getInstance();
+ GitRebaseEditorHandler editor = service.getHandler(project, dialog.gitRoot());
+ affectedRoots.add(dialog.gitRoot());
+ try {
+ String editorPath = service.getScriptPath().getPath();
+ if (SystemInfo.isWindows) {
+ editorPath = editorPath.replace('\\', '/');
+ }
+ h.setenv(GitHandler.GIT_EDITOR_ENV, editorPath);
+ h.setenv(GitRebaseEditorMain.IDEA_REBASE_HANDER_NO, Integer.toString(editor.getHandlerNo()));
+ GitHandlerUtil.doSynchronously(h, GitBundle.getString("rebasing.title"), h.printableCommandLine());
+ }
+ finally {
+ editor.close();
+ }
+
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
--- /dev/null
+/*
+ * Copyright 2000-2008 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.actions;
+
+import git4idea.i18n.GitBundle;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Rebase abort action
+ */
+public class GitRebaseAbort extends GitAbstractRebaseAction {
+
+ /**
+ * {@inheritDoc}
+ */
+ @NotNull
+ protected String getActionName() {
+ return GitBundle.getString("rebase.abort.action.name");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @NonNls
+ protected String getOptionName() {
+ return "--abort";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected String getActionTitle() {
+ return GitBundle.getString("rebase.abort.action.name");
+ }
+}
--- /dev/null
+/*
+ * Copyright 2000-2008 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.actions;
+
+import git4idea.i18n.GitBundle;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Rebase abort action
+ */
+public class GitRebaseContinue extends GitAbstractRebaseAction {
+
+ /**
+ * {@inheritDoc}
+ */
+ @NotNull
+ protected String getActionName() {
+ return GitBundle.getString("rebase.continue.action.name");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @NonNls
+ protected String getOptionName() {
+ return "--continue";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected String getActionTitle() {
+ return GitBundle.getString("rebase.continue.action.name");
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright 2000-2008 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.actions;
+
+import git4idea.i18n.GitBundle;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Rebase abort action
+ */
+public class GitRebaseSkip extends GitAbstractRebaseAction {
+
+ /**
+ * {@inheritDoc}
+ */
+ @NotNull
+ protected String getActionName() {
+ return GitBundle.getString("rebase.skip.action.name");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @NonNls
+ protected String getOptionName() {
+ return "--skip";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected String getActionTitle() {
+ return GitBundle.getString("rebase.skip.action.name");
+ }
+}
\ No newline at end of file
import com.intellij.util.containers.HashMap;
import git4idea.GitBranch;
import git4idea.GitRemote;
+import git4idea.GitTag;
import git4idea.commands.GitHandler;
import git4idea.commands.GitLineHandler;
import git4idea.config.GitConfigUtil;
myBranchNames.clear();
myTagNames.clear();
try {
- GitBranch.list(myProject, getGitRoot(), false, true, myBranchNames);
- GitBranch.listTags(myProject, getGitRoot(), myTagNames);
+ GitBranch.listAsStrings(myProject, getGitRoot(), false, true, myBranchNames);
+ GitTag.listAsStrings(myProject, getGitRoot(), myTagNames);
}
catch (VcsException ex) {
LOG.warn("Exception in branchlist: \n" + StringUtil.getThrowableText(ex));
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.DocumentAdapter;
import git4idea.GitBranch;
+import git4idea.GitTag;
import git4idea.GitVcs;
import git4idea.commands.GitHandler;
import git4idea.commands.GitLineHandler;
try {
List<String> branchesAndTags = new ArrayList<String>();
// get branches
- GitBranch.list(myProject, gitRoot(), true, true, branchesAndTags);
+ GitBranch.listAsStrings(myProject, gitRoot(), true, true, branchesAndTags);
existingBranches.clear();
existingBranches.addAll(branchesAndTags);
Collections.sort(branchesAndTags);
// get tags
if (myIncludeTagsCheckBox.isSelected()) {
int mark = branchesAndTags.size();
- GitBranch.listTags(myProject, gitRoot(), branchesAndTags);
+ GitTag.listAsStrings(myProject, gitRoot(), branchesAndTags);
Collections.sort(branchesAndTags.subList(mark, branchesAndTags.size()));
}
myBranchToCkeckout.removeAllItems();
* The constant for git command {@value}
*/
@NonNls public static final String STASH = "stash";
+ /**
+ * The constant for git command {@value}
+ */
+ @NonNls public static final String REBASE = "rebase";
+ /**
+ * Name of environement variable that specifies editor for the git
+ */
+ @NonNls public static final String GIT_EDITOR_ENV = "GIT_EDITOR";
/**
* The vcs object
*/
protected final GitVcs myVcs;
+ /**
+ * The environment
+ */
+ private final Map<String, String> myEnv;
/**
* A constructor
protected GitHandler(@NotNull Project project, @NotNull File directory, @NotNull String command) {
myProject = project;
GitVcsSettings settings = GitVcsSettings.getInstance(project);
+ myEnv = new HashMap<String, String>(System.getenv());
myVcs = GitVcs.getInstance(project);
if (myVcs != null) {
myVcs.checkVersion();
if (log.isDebugEnabled()) {
log.debug("running git: " + myCommandLine.getCommandLineString() + " in " + myWorkingDirectory);
}
- final Map<String, String> env = new HashMap<String, String>(System.getenv());
if (!myNoSSHFlag) {
GitSSHService ssh = GitSSHService.getInstance();
- env.put(GitSSHService.GIT_SSH_ENV, ssh.getScriptPath().getPath());
+ myEnv.put(GitSSHService.GIT_SSH_ENV, ssh.getScriptPath().getPath());
myHandlerNo = ssh.registerHandler(new GitSSHGUIHandler(myProject));
myEnvironmentCleanedUp = false;
- env.put(GitSSHService.SSH_HANDLER_ENV, Integer.toString(myHandlerNo));
+ myEnv.put(GitSSHService.SSH_HANDLER_ENV, Integer.toString(myHandlerNo));
}
- myCommandLine.setEnvParams(env);
+ myCommandLine.setEnvParams(myEnv);
// start process
myProcess = myCommandLine.createProcess();
myHandler = new OSProcessHandler(myProcess, myCommandLine.getCommandLineString()) {
myStderrSuppressed = stderrSuppressed;
}
+ /**
+ * Set environement variable
+ *
+ * @param name the variable name
+ * @param value the varianble value
+ */
+ public void setenv(String name, String value) {
+ myEnv.put(name, value);
+ }
+
/**
* Translate parameter
*
/**
* Error indicators for the line
*/
- @NonNls private static final String[] ERROR_INIDCATORS = {"ERROR:", "error:", "FATAL:", "fatal:", "Cannot apply"};
+ @NonNls private static final String[] ERROR_INIDCATORS =
+ {"ERROR:", "error:", "FATAL:", "fatal:", "Cannot apply", "Could not", "Interactive rebase already started"};
/**
* Check if the line is an error line
--- /dev/null
+/*
+ * Copyright 2000-2008 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.commands;
+
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.util.PathUtil;
+import org.jetbrains.annotations.NonNls;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Script generator utility class. It uses to generate a temporary scripts that
+ * are removed after application ends.
+ */
+public class ScriptGenerator {
+ /**
+ * The extension of the ssh script name
+ */
+ @NonNls public static final String SCRIPT_EXT;
+
+ static {
+ if (SystemInfo.isWindows) {
+ SCRIPT_EXT = ".cmd";
+ }
+ else {
+ SCRIPT_EXT = ".sh";
+ }
+ }
+
+ /**
+ * The script prefix
+ */
+ private final String myPrefix;
+ /**
+ * The scripts may class
+ */
+ private final Class myMainClass;
+ /**
+ * The class paths for the script
+ */
+ private final ArrayList<String> myPaths = new ArrayList<String>();
+ /**
+ * The internal parameteers for the script
+ */
+ private final ArrayList<String> myInternalParameters = new ArrayList<String>();
+
+ /**
+ * A constructor
+ *
+ * @param prefix the script prefix
+ * @param mainClass the script main class
+ */
+ public ScriptGenerator(final String prefix, final Class mainClass) {
+ myPrefix = prefix;
+ myMainClass = mainClass;
+ addClasses(myMainClass);
+ }
+
+ /**
+ * Add jar or directory that contains the class to the classpath
+ *
+ * @param classes classes which sources will be added
+ * @return this script generator
+ */
+ public ScriptGenerator addClasses(final Class... classes) {
+ for (Class<?> c : classes) {
+ addPath(PathUtil.getJarPathForClass(c));
+ }
+ return this;
+ }
+
+ /**
+ * Add path to class path. The methods checks if the path has been already added to the classpath.
+ *
+ * @param path the path to add
+ */
+ private void addPath(final String path) {
+ if (!myPaths.contains(path)) {
+ // the size of path is expceted to be quite small, so no optimization is done here
+ myPaths.add(path);
+ }
+ }
+
+ /**
+ * Add source for the specified resource
+ *
+ * @param base the resource base
+ * @param resource the resource name
+ * @return this script generator
+ */
+ public ScriptGenerator addResource(final Class base, @NonNls String resource) {
+ addPath(getJarForResource(base, resource));
+ return this;
+ }
+
+ /**
+ * Add internal parameters for the script
+ *
+ * @param params internal parameters
+ * @return this script generator
+ */
+ public ScriptGenerator addInternal(String... params) {
+ myInternalParameters.addAll(Arrays.asList(params));
+ return this;
+ }
+
+ /**
+ * Generate script according to specified parameters
+ *
+ * @return the path to generated script
+ * @throws IOException if there is a problem with creating script
+ */
+ @SuppressWarnings({"HardCodedStringLiteral"})
+ public File generate() throws IOException {
+ File scriptPath = File.createTempFile(myPrefix, SCRIPT_EXT);
+ scriptPath.deleteOnExit();
+ PrintWriter out = new PrintWriter(new FileWriter(scriptPath));
+ try {
+ if (SystemInfo.isWindows) {
+ out.println("@echo off");
+ }
+ else {
+ out.println("#!/bin/sh");
+ }
+ out.print(System.getProperty("java.home") + File.separatorChar + "bin" + File.separatorChar + "java -cp \"");
+ boolean first = true;
+ for (String p : myPaths) {
+ if (!first) {
+ out.print(File.pathSeparatorChar);
+ }
+ else {
+ first = false;
+ }
+ out.print(p);
+ }
+ out.print("\" ");
+ out.print(myMainClass.getName());
+ for (String p : myInternalParameters) {
+ out.print(' ');
+ out.print(p);
+ }
+ if (SystemInfo.isWindows) {
+ out.println(" %1 %2 %3 %4 %5 %6 %7 %8 %9");
+ }
+ else {
+ out.println(" \"$@\"");
+ }
+ }
+ finally {
+ out.close();
+ }
+ FileUtil.setExectuableAttribute(scriptPath.getAbsolutePath(), true);
+ return scriptPath;
+ }
+
+ /**
+ * Get path for resources.jar
+ *
+ * @param context a context class
+ * @param res a resource
+ * @return a path to classpath entry
+ */
+ @SuppressWarnings({"SameParameterValue"})
+ public static String getJarForResource(Class context, String res) {
+ String resourceRoot = PathManager.getResourceRoot(context, res);
+ return new File(resourceRoot).getAbsoluteFile().getAbsolutePath();
+ }
+}
push.use.thin.pack.tooltip=If this option is selected, the push will spend extra CPU cycles to minimize amount of data transferred (use it for slow connections)
push.use.thin.pack=&Use thin pack
pushing.all.changes=Pushing all commited changes, refs & tags to remote repos
+rebase.abort.action.name=Abort Rebasing
+rebase.action.error=Git Rebase Error
+rebase.action.message=Mulitple git roots have unfinished rebase process, please select root to perform action on.
+rebase.action.name=Rebase
+rebase.action.no.root=There is no rebase operation in progress in the project
+rebase.branch.tooltip=Select branch to rebase (if branch is different from the current branch, it will be checked out first)
+rebase.branch=&Branch:
+rebase.continue.action.name=Continue Rebasing
+rebase.editor.action.column=Action
+rebase.editor.comment.column=Comment
+rebase.editor.commit.column=Commit
+rebase.editor.invalid.squash=There should be at least two consequent squashed commits
+rebase.editor.message=Reorder and edit &rebased commits
+rebase.editor.move.down.tooltip=Move commit down (commit will be applied later)
+rebase.editor.move.down=Move &Down
+rebase.editor.move.up.tooltip=Move commit up in the list (commit will be applied earlier)
+rebase.editor.move.up=Move &Up
+rebase.editor.title=Rebasing commits
+rebase.editor.view.tooltip=View commit contents
+rebase.editor.view=&View
+rebase.from.tooltip=Sepecify actual base for the branch. Leave blank to onto.
+rebase.from=&From:
+rebase.in.progress=Interactive rebase has been already started for this git root.
+rebase.interactive.tooltip=If selected, the interactive rebase will be preformed.
+rebase.interactive=&Interactive
+rebase.invalid.from=\"From\" reference expression is invalid.
+rebase.invalid.onto=\"Onto\" reference expression is invalid.
+rebase.merge.strategy.tooltip=Select merge strategy to use
+rebase.merge.strategy=Merge &Strategy:
+rebase.no.merge.tooltip=If selected, no merge strategies will be applied during the rebase.
+rebase.no.merge=&Do not use merge strategies
+rebase.onto.tooltip=The reference that will become a new base for selected branch.
+rebase.onto.validate=&Validate
+rebase.onto=&Onto:
+rebase.preserve.merges.tooltip=Preserve merges during rebease instead of squashing them.
+rebase.preserve.merges=&Preserve Merges
+rebase.show.remote.branches.tooltip=If selected, remote branches are shown in drop down as well.
+rebase.show.remote.branches=Show Re&mote Branches
+rebase.show.tags.tooltip=Show tags in \"from\" and \"onto\" dropdowns.
+rebase.skip.action.name=Skip Commit in Rebasing
+rebase.title=Rebase branch
+rebase.valdate.onto.tooltip=Valdate "onto" reference.
+rebase.validate.from.tooltip=Validate \"from\" reference
+rebase.validate.from=Va&lidate
+rebasing.title=Rebasing...
refspec.add.all.branches.tooltip=Add refspec that maps all remote branches by glob spec.
refspec.add.all.branches=Add A&ll Branches
refspec.add.all.tags.tooltip=Adds mapping entry for all tags
refspec.title=Reference mapping
refspec.validation.remote.invalid=The invalid local name for remote
refspec.validation.remote.is.blank=The local name for remote is blank
+regase.show.tags=Show &tags
repository.action.missing.roots.misconfigured=Neither of configured git roots are is under git. The configured directory or some of its ancestors must have ".git" directory in it.
repository.action.missing.roots.title=No git roots
repository.action.missing.roots.unconfigured.message=No git roots are configured for the project.
* @return an array of strategy names
*/
@NonNls
- private static String[] getMergeStrategies(int branchCount) {
+ public static String[] getMergeStrategies(int branchCount) {
if (branchCount < 0) {
throw new IllegalArgumentException("Brach count must be non-negative: " + branchCount);
}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="git4idea.rebase.GitRebaseActionDialog">
+ <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <margin top="0" left="0" bottom="0" right="0"/>
+ <constraints>
+ <xy x="20" y="20" width="440" height="72"/>
+ </constraints>
+ <properties/>
+ <border type="none"/>
+ <children>
+ <component id="19057" class="javax.swing.JLabel">
+ <constraints>
+ <grid row="0" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="rebase.action.message"/>
+ </properties>
+ </component>
+ <component id="cc3bb" class="javax.swing.JLabel">
+ <constraints>
+ <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <labelFor value="13488"/>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="common.git.root"/>
+ </properties>
+ </component>
+ <vspacer id="2ef5c">
+ <constraints>
+ <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+ </constraints>
+ </vspacer>
+ <component id="13488" class="javax.swing.JComboBox" binding="myGitRootComboBox" default-binding="true">
+ <constraints>
+ <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <toolTipText resource-bundle="git4idea/i18n/GitBundle" key="common.git.root.tooltip"/>
+ </properties>
+ </component>
+ </children>
+ </grid>
+</form>
--- /dev/null
+/*
+ * Copyright 2000-2008 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.rebase;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.vfs.VirtualFile;
+import git4idea.ui.GitUIUtil;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.List;
+
+/**
+ * The rebase action dialog
+ */
+public class GitRebaseActionDialog extends DialogWrapper {
+ /**
+ * The root selector
+ */
+ private JComboBox myGitRootComboBox;
+ /**
+ * The root panel
+ */
+ private JPanel myPanel;
+
+ /**
+ * A constructor
+ *
+ * @param project a project to select
+ * @param roots a git repository roots for the project
+ * @param defaultRoot a guessed default root
+ */
+ public GitRebaseActionDialog(Project project, String title, List<VirtualFile> roots, VirtualFile defaultRoot) {
+ super(project, true);
+ GitUIUtil.setupRootChooser(project, roots, defaultRoot, myGitRootComboBox, null);
+ setTitle(title);
+ init();
+ }
+
+
+ /**
+ * Show dialog and select root
+ *
+ * @return selected root or null if the dialog has been cancelled
+ */
+ @Nullable
+ public VirtualFile selectRoot() {
+ show();
+ return isOK() ? (VirtualFile)myGitRootComboBox.getSelectedItem() : null;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ protected JComponent createCenterPanel() {
+ return myPanel;
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="git4idea.rebase.GitRebaseDialog">
+ <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="8" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <margin top="0" left="0" bottom="0" right="0"/>
+ <constraints>
+ <xy x="20" y="20" width="583" height="255"/>
+ </constraints>
+ <properties/>
+ <border type="none"/>
+ <children>
+ <component id="76105" class="javax.swing.JLabel">
+ <constraints>
+ <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <labelFor value="bebca"/>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="common.git.root"/>
+ </properties>
+ </component>
+ <vspacer id="67a13">
+ <constraints>
+ <grid row="7" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+ </constraints>
+ </vspacer>
+ <component id="bebca" class="javax.swing.JComboBox" binding="myGitRootComboBox" default-binding="true">
+ <constraints>
+ <grid row="0" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <toolTipText resource-bundle="git4idea/i18n/GitBundle" key="common.git.root.tooltip"/>
+ </properties>
+ </component>
+ <component id="141cd" class="javax.swing.JLabel">
+ <constraints>
+ <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <labelFor value="e8e3d"/>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="rebase.branch"/>
+ </properties>
+ </component>
+ <component id="e8e3d" class="javax.swing.JComboBox" binding="myBranchComboBox" default-binding="true">
+ <constraints>
+ <grid row="1" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <toolTipText resource-bundle="git4idea/i18n/GitBundle" key="rebase.branch.tooltip"/>
+ </properties>
+ </component>
+ <component id="2b513" class="javax.swing.JLabel">
+ <constraints>
+ <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <labelFor value="b3800"/>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="rebase.onto"/>
+ </properties>
+ </component>
+ <component id="b3800" class="javax.swing.JComboBox" binding="myOntoComboBox" default-binding="true">
+ <constraints>
+ <grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <editable value="true"/>
+ <toolTipText resource-bundle="git4idea/i18n/GitBundle" key="rebase.onto.tooltip"/>
+ </properties>
+ </component>
+ <component id="ddd04" class="javax.swing.JButton" binding="myOntoValidateButton">
+ <constraints>
+ <grid row="3" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="rebase.onto.validate"/>
+ <toolTipText resource-bundle="git4idea/i18n/GitBundle" key="rebase.valdate.onto.tooltip"/>
+ </properties>
+ </component>
+ <component id="cb44a" class="javax.swing.JLabel">
+ <constraints>
+ <grid row="6" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <labelFor value="b0f9a"/>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="rebase.merge.strategy"/>
+ </properties>
+ </component>
+ <component id="4aaae" class="javax.swing.JLabel">
+ <constraints>
+ <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <labelFor value="438d6"/>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="rebase.from"/>
+ </properties>
+ </component>
+ <component id="438d6" class="javax.swing.JComboBox" binding="myFromComboBox">
+ <constraints>
+ <grid row="4" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <editable value="true"/>
+ <toolTipText resource-bundle="git4idea/i18n/GitBundle" key="rebase.from.tooltip"/>
+ </properties>
+ </component>
+ <component id="775c4" class="javax.swing.JButton" binding="myFromValidateButton">
+ <constraints>
+ <grid row="4" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="rebase.validate.from"/>
+ <toolTipText resource-bundle="git4idea/i18n/GitBundle" key="rebase.validate.from.tooltip"/>
+ </properties>
+ </component>
+ <grid id="f939d" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <margin top="0" left="0" bottom="0" right="0"/>
+ <constraints>
+ <grid row="6" column="1" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties/>
+ <border type="none"/>
+ <children>
+ <component id="b0f9a" class="javax.swing.JComboBox" binding="myMergeStrategyComboBox" default-binding="true">
+ <constraints>
+ <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <toolTipText resource-bundle="git4idea/i18n/GitBundle" key="rebase.merge.strategy.tooltip"/>
+ </properties>
+ </component>
+ <hspacer id="1ba1f">
+ <constraints>
+ <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ </hspacer>
+ <component id="3a627" class="javax.swing.JCheckBox" binding="myDoNotUseMergeCheckBox" default-binding="true">
+ <constraints>
+ <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="1" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <selected value="false"/>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="rebase.no.merge"/>
+ <toolTipText resource-bundle="git4idea/i18n/GitBundle" key="rebase.no.merge.tooltip"/>
+ </properties>
+ </component>
+ </children>
+ </grid>
+ <grid id="63e88" layout-manager="GridLayoutManager" row-count="1" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <margin top="0" left="0" bottom="0" right="0"/>
+ <constraints>
+ <grid row="2" column="1" row-span="1" col-span="2" vsize-policy="3" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties/>
+ <border type="none"/>
+ <children>
+ <hspacer id="7eb2f">
+ <constraints>
+ <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ </hspacer>
+ <component id="e5f3b" class="javax.swing.JCheckBox" binding="myPreserveMergesCheckBox" default-binding="true">
+ <constraints>
+ <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <selected value="true"/>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="rebase.preserve.merges"/>
+ <toolTipText resource-bundle="git4idea/i18n/GitBundle" key="rebase.preserve.merges.tooltip"/>
+ </properties>
+ </component>
+ <component id="281fe" class="javax.swing.JCheckBox" binding="myInteractiveCheckBox" default-binding="true">
+ <constraints>
+ <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <enabled value="true"/>
+ <selected value="true"/>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="rebase.interactive"/>
+ <toolTipText resource-bundle="git4idea/i18n/GitBundle" key="rebase.interactive.tooltip"/>
+ </properties>
+ </component>
+ </children>
+ </grid>
+ <grid id="46bb8" layout-manager="GridLayoutManager" row-count="1" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <margin top="0" left="0" bottom="0" right="0"/>
+ <constraints>
+ <grid row="5" column="1" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties/>
+ <border type="none"/>
+ <children>
+ <component id="de965" class="javax.swing.JCheckBox" binding="myShowTagsCheckBox" default-binding="true">
+ <constraints>
+ <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="regase.show.tags"/>
+ <toolTipText resource-bundle="git4idea/i18n/GitBundle" key="rebase.show.tags.tooltip"/>
+ </properties>
+ </component>
+ <component id="a0269" class="javax.swing.JCheckBox" binding="myShowRemoteBranchesCheckBox" default-binding="true">
+ <constraints>
+ <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="rebase.show.remote.branches"/>
+ <toolTipText resource-bundle="git4idea/i18n/GitBundle" key="rebase.show.remote.branches.tooltip"/>
+ </properties>
+ </component>
+ <hspacer id="b158">
+ <constraints>
+ <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ </hspacer>
+ </children>
+ </grid>
+ </children>
+ </grid>
+</form>
--- /dev/null
+/*
+ * Copyright 2000-2008 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.rebase;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.vcs.VcsException;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.ui.DocumentAdapter;
+import git4idea.GitBranch;
+import git4idea.GitTag;
+import git4idea.commands.GitHandler;
+import git4idea.commands.GitLineHandler;
+import git4idea.config.GitConfigUtil;
+import git4idea.i18n.GitBundle;
+import git4idea.merge.GitMergeUtil;
+import git4idea.ui.GitReferenceValidator;
+import git4idea.ui.GitUIUtil;
+
+import javax.swing.*;
+import javax.swing.event.DocumentEvent;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The dialog that allows initiating git rebase activity
+ */
+public class GitRebaseDialog extends DialogWrapper {
+ /**
+ * Git root selector
+ */
+ private JComboBox myGitRootComboBox;
+ /**
+ * The selector for branch to rebase
+ */
+ private JComboBox myBranchComboBox;
+ /**
+ * The from branch combo box. This is used as base branch if different from onto branch
+ */
+ private JComboBox myFromComboBox;
+ /**
+ * The validation button for from branch
+ */
+ private JButton myFromValidateButton;
+ /**
+ * The onto branch combobox.
+ */
+ private JComboBox myOntoComboBox;
+ /**
+ * The validate button for onto branch
+ */
+ private JButton myOntoValidateButton;
+ /**
+ * Show tags in drop down
+ */
+ private JCheckBox myShowTagsCheckBox;
+ /**
+ * Merge strategy drop down
+ */
+ private JComboBox myMergeStrategyComboBox;
+ /**
+ * If selected, rebase is interactive
+ */
+ private JCheckBox myInteractiveCheckBox;
+ /**
+ * No merges are performed if selected.
+ */
+ private JCheckBox myDoNotUseMergeCheckBox;
+ /**
+ * The root panel of the dialog
+ */
+ private JPanel myPanel;
+ /**
+ * If selected, remote branches are shown as well
+ */
+ private JCheckBox myShowRemoteBranchesCheckBox;
+ /**
+ * Preserve mereges checkbox
+ */
+ private JCheckBox myPreserveMergesCheckBox;
+ /**
+ * The current project
+ */
+ private Project myProject;
+ /**
+ * The list of local branches
+ */
+ private List<GitBranch> myLocalBranches = new ArrayList<GitBranch>();
+ /**
+ * The list of remote branches
+ */
+ private List<GitBranch> myRemoteBranches = new ArrayList<GitBranch>();
+ /**
+ * The current branch
+ */
+ private GitBranch myCurrentBranch;
+ /**
+ * The tags
+ */
+ private List<GitTag> myTags = new ArrayList<GitTag>();
+ /**
+ * The validator for onto field
+ */
+ private final GitReferenceValidator myOntoValidator;
+ /**
+ * The validator for from field
+ */
+ private final GitReferenceValidator myFromValidator;
+
+ /**
+ * A constructor
+ *
+ * @param project a project to select
+ * @param roots a git repository roots for the project
+ * @param defaultRoot a guessed default root
+ */
+ public GitRebaseDialog(Project project, List<VirtualFile> roots, VirtualFile defaultRoot) {
+ super(project, true);
+ setTitle(GitBundle.getString("rebase.title"));
+ init();
+ myProject = project;
+ final Runnable validateRunnable = new Runnable() {
+ public void run() {
+ validateFields();
+ }
+ };
+ myOntoValidator = new GitReferenceValidator(myProject, myGitRootComboBox, GitUIUtil.getTextField(myOntoComboBox), myOntoValidateButton,
+ validateRunnable);
+ myFromValidator = new GitReferenceValidator(myProject, myGitRootComboBox, GitUIUtil.getTextField(myFromComboBox), myFromValidateButton,
+ validateRunnable);
+ GitUIUtil.setupRootChooser(myProject, roots, defaultRoot, myGitRootComboBox, null);
+ myGitRootComboBox.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ validateFields();
+ }
+ });
+ setupBranches();
+ setupStrategy();
+ validateFields();
+ }
+
+ public GitLineHandler handler() {
+ GitLineHandler h = new GitLineHandler(myProject, gitRoot(), GitHandler.REBASE);
+ h.setNoSSH(true);
+ if (myInteractiveCheckBox.isSelected() && myInteractiveCheckBox.isEnabled()) {
+ h.addParameters("-i");
+ }
+ h.addParameters("-v");
+ if (!myDoNotUseMergeCheckBox.isSelected()) {
+ if (myMergeStrategyComboBox.getSelectedItem().equals(GitMergeUtil.DEFAULT_STRATEGY)) {
+ h.addParameters("-m");
+ }
+ else {
+ h.addParameters("-s", myMergeStrategyComboBox.getSelectedItem().toString());
+ }
+ }
+ if (myPreserveMergesCheckBox.isSelected()) {
+ h.addParameters("-p");
+ }
+ String from = GitUIUtil.getTextField(myFromComboBox).getText();
+ String onto = GitUIUtil.getTextField(myOntoComboBox).getText();
+ if (from.length() == 0) {
+ h.addParameters(onto);
+ }
+ else {
+ h.addParameters("--onto", onto, from);
+ }
+ final String selectedBranch = (String)myBranchComboBox.getSelectedItem();
+ if (myCurrentBranch != null && !myCurrentBranch.getName().equals(selectedBranch)) {
+ h.addParameters(selectedBranch);
+ }
+ return h;
+ }
+
+ /**
+ * Setup strategy
+ */
+ private void setupStrategy() {
+ for (String s : GitMergeUtil.getMergeStrategies(1)) {
+ myMergeStrategyComboBox.addItem(s);
+ }
+ myMergeStrategyComboBox.setSelectedItem(GitMergeUtil.DEFAULT_STRATEGY);
+ myDoNotUseMergeCheckBox.addActionListener(new ActionListener() {
+ public void actionPerformed(final ActionEvent e) {
+ myMergeStrategyComboBox.setEnabled(!myDoNotUseMergeCheckBox.isSelected());
+ }
+ });
+ }
+
+
+ /**
+ * Validate fields
+ */
+ private void validateFields() {
+ if (GitUIUtil.getTextField(myOntoComboBox).getText().length() == 0) {
+ setErrorText(null);
+ setOKActionEnabled(false);
+ return;
+ }
+ else if (myOntoValidator.isInvalid()) {
+ setErrorText(GitBundle.getString("rebase.invalid.onto"));
+ setOKActionEnabled(false);
+ return;
+ }
+ if (GitUIUtil.getTextField(myFromComboBox).getText().length() != 0 && myFromValidator.isInvalid()) {
+ setErrorText(GitBundle.getString("rebase.invalid.from"));
+ setOKActionEnabled(false);
+ return;
+ }
+ if (GitRebaseUtils.isRebaseInTheProgress(gitRoot())) {
+ setErrorText(GitBundle.getString("rebase.in.progress"));
+ setOKActionEnabled(false);
+ return;
+ }
+ setErrorText(null);
+ setOKActionEnabled(true);
+ }
+
+ /**
+ * Setup branch drop down.
+ */
+ private void setupBranches() {
+ GitUIUtil.getTextField(myOntoComboBox).getDocument().addDocumentListener(new DocumentAdapter() {
+ protected void textChanged(final DocumentEvent e) {
+ validateFields();
+ }
+ });
+ final ActionListener rootListener = new ActionListener() {
+ public void actionPerformed(final ActionEvent e) {
+ loadRefs();
+ updateBranches();
+ }
+ };
+ final ActionListener showListener = new ActionListener() {
+ public void actionPerformed(final ActionEvent e) {
+ updateOntoFrom();
+ }
+ };
+ myShowRemoteBranchesCheckBox.addActionListener(showListener);
+ myShowTagsCheckBox.addActionListener(showListener);
+ rootListener.actionPerformed(null);
+ myGitRootComboBox.addActionListener(rootListener);
+ myBranchComboBox.addActionListener(new ActionListener() {
+ public void actionPerformed(final ActionEvent e) {
+ updateTrackedBranch();
+ }
+ });
+ }
+
+ /**
+ * Update branches when git root changed
+ */
+ private void updateBranches() {
+ myBranchComboBox.removeAllItems();
+ for (GitBranch b : myLocalBranches) {
+ myBranchComboBox.addItem(b.getName());
+ }
+ if (myCurrentBranch != null) {
+ myBranchComboBox.setSelectedItem(myCurrentBranch.getName());
+ }
+ else {
+ myBranchComboBox.setSelectedItem(0);
+ }
+ updateOntoFrom();
+ updateTrackedBranch();
+ }
+
+ /**
+ * Update onto and from dropdowns.
+ */
+ private void updateOntoFrom() {
+ String onto = GitUIUtil.getTextField(myOntoComboBox).getText();
+ String from = GitUIUtil.getTextField(myFromComboBox).getText();
+ myFromComboBox.removeAllItems();
+ myOntoComboBox.removeAllItems();
+ for (GitBranch b : myLocalBranches) {
+ myFromComboBox.addItem(b);
+ myOntoComboBox.addItem(b);
+ }
+ if (myShowRemoteBranchesCheckBox.isSelected()) {
+ for (GitBranch b : myRemoteBranches) {
+ myFromComboBox.addItem(b);
+ myOntoComboBox.addItem(b);
+ }
+ }
+ if (myShowTagsCheckBox.isSelected()) {
+ for (GitTag t : myTags) {
+ myFromComboBox.addItem(t);
+ myOntoComboBox.addItem(t);
+ }
+ }
+ GitUIUtil.getTextField(myOntoComboBox).setText(onto);
+ GitUIUtil.getTextField(myFromComboBox).setText(from);
+ }
+
+ /**
+ * Load tags and branches
+ */
+ private void loadRefs() {
+ try {
+ myLocalBranches.clear();
+ myRemoteBranches.clear();
+ myTags.clear();
+ final VirtualFile root = gitRoot();
+ GitBranch.list(myProject, root, true, false, myLocalBranches);
+ GitBranch.list(myProject, root, false, true, myRemoteBranches);
+ GitTag.list(myProject, root, myTags);
+ myCurrentBranch = GitBranch.current(myProject, root);
+ }
+ catch (VcsException e) {
+ GitUIUtil.showOperationError(myProject, e, "git branch -a");
+ }
+ }
+
+ /**
+ * Update tracked branch basing on the currently selected branch
+ */
+ private void updateTrackedBranch() {
+ try {
+ final VirtualFile root = gitRoot();
+ String currentBranch = (String)myBranchComboBox.getSelectedItem();
+ final GitBranch trackedBranch;
+ if (currentBranch != null) {
+ String remote = GitConfigUtil.getValue(myProject, root, "branch." + currentBranch + ".remote");
+ String merge = GitConfigUtil.getValue(myProject, root, "branch." + currentBranch + ".merge");
+ String name =
+ (merge != null && merge.startsWith(GitBranch.REFS_HEADS_PREFIX)) ? merge.substring(GitBranch.REFS_HEADS_PREFIX.length()) : null;
+ if (remote == null || merge == null || name == null) {
+ trackedBranch = null;
+ }
+ else {
+ if (remote.equals(".")) {
+ trackedBranch = new GitBranch(name, false, false);
+ }
+ else {
+ trackedBranch = new GitBranch(remote + "/" + name, false, true);
+ }
+ }
+ }
+ else {
+ trackedBranch = null;
+ }
+ if (trackedBranch != null) {
+ myOntoComboBox.setSelectedItem(trackedBranch);
+ }
+ else {
+ GitUIUtil.getTextField(myOntoComboBox).setText("");
+ }
+ GitUIUtil.getTextField(myFromComboBox).setText("");
+ }
+ catch (VcsException e) {
+ GitUIUtil.showOperationError(myProject, e, "git config");
+ }
+ }
+
+ /**
+ * @return the currently selected git root
+ */
+ public VirtualFile gitRoot() {
+ return (VirtualFile)myGitRootComboBox.getSelectedItem();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected String getDimensionServiceKey() {
+ return getClass().getName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected JComponent createCenterPanel() {
+ return myPanel;
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="git4idea.rebase.GitRebaseEditor">
+ <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <margin top="0" left="0" bottom="0" right="0"/>
+ <constraints>
+ <xy x="20" y="20" width="500" height="228"/>
+ </constraints>
+ <properties/>
+ <border type="none"/>
+ <children>
+ <grid id="19dce" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <margin top="0" left="0" bottom="0" right="0"/>
+ <constraints>
+ <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties/>
+ <border type="none"/>
+ <children>
+ <component id="49f7c" class="javax.swing.JButton" binding="myMoveUpButton" default-binding="true">
+ <constraints>
+ <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <enabled value="false"/>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="rebase.editor.move.up"/>
+ <toolTipText resource-bundle="git4idea/i18n/GitBundle" key="rebase.editor.move.up.tooltip"/>
+ </properties>
+ </component>
+ <vspacer id="23afb">
+ <constraints>
+ <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+ </constraints>
+ </vspacer>
+ <component id="f607e" class="javax.swing.JButton" binding="myMoveDownButton" default-binding="true">
+ <constraints>
+ <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <enabled value="false"/>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="rebase.editor.move.down"/>
+ <toolTipText resource-bundle="git4idea/i18n/GitBundle" key="rebase.editor.move.down.tooltip"/>
+ </properties>
+ </component>
+ <component id="578eb" class="javax.swing.JButton" binding="myViewButton" default-binding="true">
+ <constraints>
+ <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <enabled value="false"/>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="rebase.editor.view"/>
+ <toolTipText resource-bundle="git4idea/i18n/GitBundle" key="rebase.editor.view.tooltip"/>
+ </properties>
+ </component>
+ </children>
+ </grid>
+ <scrollpane id="2f6c5">
+ <constraints>
+ <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties/>
+ <border type="none"/>
+ <children>
+ <component id="22e0d" class="javax.swing.JTable" binding="myCommitsTable">
+ <constraints/>
+ <properties/>
+ </component>
+ </children>
+ </scrollpane>
+ <component id="11e7a" class="javax.swing.JLabel">
+ <constraints>
+ <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <labelFor value="2f6c5"/>
+ <text resource-bundle="git4idea/i18n/GitBundle" key="rebase.editor.message"/>
+ </properties>
+ </component>
+ </children>
+ </grid>
+</form>
--- /dev/null
+/*
+ * Copyright 2000-2008 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.rebase;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.ListWithSelection;
+import com.intellij.util.ui.ComboBoxTableCellEditor;
+import com.intellij.util.ui.ComboBoxTableCellRenderer;
+import git4idea.actions.GitShowAllSubmittedFilesAction;
+import git4idea.commands.StringScanner;
+import git4idea.i18n.GitBundle;
+import org.jetbrains.annotations.NonNls;
+
+import javax.swing.*;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableColumn;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Editor for rebase entries. It allows reordering of
+ * the entries and changing commit status.
+ */
+public class GitRebaseEditor extends DialogWrapper {
+ /**
+ * The table that lists all commits
+ */
+ private JTable myCommitsTable;
+ /**
+ * The move up button
+ */
+ private JButton myMoveUpButton;
+ /**
+ * The move down button
+ */
+ private JButton myMoveDownButton;
+ /**
+ * The view commit button
+ */
+ private JButton myViewButton;
+ /**
+ * The root panel
+ */
+ private JPanel myPanel;
+ /**
+ * Table model
+ */
+ private final MyTableModel myTableModel;
+ /**
+ * The file name
+ */
+ private final String myFile;
+ /**
+ * The cygwin drive prefix
+ */
+ @NonNls private static final String CYGDRIVE_PREFIX = "/cygdrive/";
+
+ /**
+ * The constructor
+ *
+ * @param project the project
+ * @param file the file to edit
+ */
+ protected GitRebaseEditor(final Project project, final VirtualFile gitRoot, String file) throws IOException {
+ super(project, true);
+ setTitle(GitBundle.getString("rebase.editor.title"));
+ if (SystemInfo.isWindows && file.startsWith(CYGDRIVE_PREFIX)) {
+ final int pfx = CYGDRIVE_PREFIX.length();
+ file = file.substring(pfx, pfx + 1) + ":" + file.substring(pfx + 1);
+ }
+ myFile = file;
+ myTableModel = new MyTableModel();
+ myTableModel.load(file);
+ myCommitsTable.setModel(myTableModel);
+ myCommitsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ TableColumn actionColumn = myCommitsTable.getColumnModel().getColumn(MyTableModel.ACTION);
+ actionColumn.setCellEditor(ComboBoxTableCellEditor.INSTANCE);
+ actionColumn.setCellRenderer(ComboBoxTableCellRenderer.INSTANCE);
+ myCommitsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+ public void valueChanged(final ListSelectionEvent e) {
+ boolean selected = myCommitsTable.getSelectedRowCount() != 0;
+ myMoveUpButton.setEnabled(selected);
+ if (selected) {
+ myViewButton.setEnabled(true);
+ int row = myCommitsTable.getSelectedRow();
+ myMoveUpButton.setEnabled(row != 0);
+ myMoveDownButton.setEnabled(row != myTableModel.myEntries.size() - 1);
+ }
+ else {
+ myMoveUpButton.setEnabled(false);
+ myMoveDownButton.setEnabled(false);
+ myViewButton.setEnabled(false);
+ }
+ }
+ });
+ myViewButton.addActionListener(new ActionListener() {
+ public void actionPerformed(final ActionEvent e) {
+ int row = myCommitsTable.getSelectedRow();
+ if (row < 0) {
+ return;
+ }
+ GitRebaseEntry entry = myTableModel.myEntries.get(row);
+ GitShowAllSubmittedFilesAction.showSubmittedFiles(project, entry.getCommit(), gitRoot);
+ }
+ });
+ myMoveUpButton.addActionListener(new ActionListener() {
+ public void actionPerformed(final ActionEvent e) {
+ final int row = myCommitsTable.getSelectedRow();
+ if (myTableModel.moveUp(row)) {
+ myCommitsTable.getSelectionModel().setSelectionInterval(row - 1, row - 1);
+ }
+ }
+ });
+ myMoveDownButton.addActionListener(new ActionListener() {
+ public void actionPerformed(final ActionEvent e) {
+ final int row = myCommitsTable.getSelectedRow();
+ if (myTableModel.moveDown(row)) {
+ myCommitsTable.getSelectionModel().setSelectionInterval(row + 1, row + 1);
+ }
+ }
+ });
+ myTableModel.addTableModelListener(new TableModelListener() {
+ public void tableChanged(final TableModelEvent e) {
+ validateFields();
+ }
+ });
+ init();
+ }
+
+ /**
+ * Validate fields
+ */
+ private void validateFields() {
+ final ArrayList<GitRebaseEntry> entries = myTableModel.myEntries;
+ final GitRebaseEntry.Action squash = GitRebaseEntry.Action.squash;
+ for (int i = 0; i < entries.size(); i++) {
+ if (entries.get(i).getAction() == squash) {
+ if (!(i > 0 && entries.get(i - 1).getAction() == squash || i < entries.size() - 1 && entries.get(i + 1).getAction() == squash)) {
+ setErrorText(GitBundle.getString("rebase.editor.invalid.squash"));
+ setOKActionEnabled(false);
+ return;
+ }
+ }
+ }
+ setErrorText(null);
+ setOKActionEnabled(true);
+ }
+
+ /**
+ * Save entries back to the file
+ *
+ * @throws IOException if there is IO problem with saving
+ */
+ public void save() throws IOException {
+ myTableModel.save(myFile);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected JComponent createCenterPanel() {
+ return myPanel;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected String getDimensionServiceKey() {
+ return getClass().getName();
+ }
+
+ /**
+ * Cancel rebase
+ */
+ public void cancel() throws IOException {
+ myTableModel.cancel(myFile);
+ }
+
+
+ /**
+ * The table model for the commits
+ */
+ private static class MyTableModel extends AbstractTableModel {
+ /**
+ * The action column
+ */
+ private static final int ACTION = 0;
+ /**
+ * The commit hash column
+ */
+ private static final int COMMIT = 1;
+ /**
+ * The subject column
+ */
+ private static final int SUBJECT = 2;
+
+ /**
+ * The entries
+ */
+ final ArrayList<GitRebaseEntry> myEntries = new ArrayList<GitRebaseEntry>();
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Class<?> getColumnClass(final int columnIndex) {
+ return columnIndex == ACTION ? ListWithSelection.class : String.class;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getColumnName(final int column) {
+ switch (column) {
+ case ACTION:
+ return GitBundle.getString("rebase.editor.action.column");
+ case COMMIT:
+ return GitBundle.getString("rebase.editor.commit.column");
+ case SUBJECT:
+ return GitBundle.getString("rebase.editor.comment.column");
+ default:
+ throw new IllegalArgumentException("Unsupported column index: " + column);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getRowCount() {
+ return myEntries.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getColumnCount() {
+ return SUBJECT + 1;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getValueAt(final int rowIndex, final int columnIndex) {
+ GitRebaseEntry e = myEntries.get(rowIndex);
+ switch (columnIndex) {
+ case ACTION:
+ return new ListWithSelection<GitRebaseEntry.Action>(Arrays.asList(GitRebaseEntry.Action.values()), e.getAction());
+ case COMMIT:
+ return e.getCommit();
+ case SUBJECT:
+ return e.getSubject();
+ default:
+ throw new IllegalArgumentException("Unsupported column index: " + columnIndex);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings({"unchecked"})
+ public void setValueAt(final Object aValue, final int rowIndex, final int columnIndex) {
+ assert columnIndex == ACTION;
+ GitRebaseEntry e = myEntries.get(rowIndex);
+ e.setAction((GitRebaseEntry.Action)aValue);
+ fireTableCellUpdated(rowIndex, columnIndex);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isCellEditable(final int rowIndex, final int columnIndex) {
+ return columnIndex == ACTION;
+ }
+
+ /**
+ * Load data from the file
+ *
+ * @param file the file to load
+ */
+ public void load(final String file) throws IOException {
+ final StringScanner s = new StringScanner(new String(FileUtil.loadFileText(new File(file))));
+ while (s.hasMoreData()) {
+ if (s.isEol() || s.startsWith('#')) {
+ s.nextLine();
+ continue;
+ }
+ String action = s.spaceToken();
+ assert "pick".equals(action) : "Initial action should be pick: " + action;
+ String hash = s.spaceToken();
+ String comment = s.line();
+ myEntries.add(new GitRebaseEntry(hash, comment));
+ }
+ }
+
+ /**
+ * Save text to the file
+ *
+ * @param file the file to save to
+ * @throws IOException if there is IO problem
+ */
+ public void save(final String file) throws IOException {
+ PrintWriter out = new PrintWriter(new FileWriter(file));
+ try {
+ for (GitRebaseEntry e : myEntries) {
+ if (e.getAction() != GitRebaseEntry.Action.skip) {
+ out.println(e.getAction().toString() + " " + e.getCommit() + " " + e.getSubject());
+ }
+ }
+ }
+ finally {
+ out.close();
+ }
+ }
+
+ /**
+ * Save text to the file
+ *
+ * @param file the file to save to
+ * @throws IOException if there is IO problem
+ */
+ public static void cancel(final String file) throws IOException {
+ PrintWriter out = new PrintWriter(new FileWriter(file));
+ try {
+ //noinspection HardCodedStringLiteral
+ out.println("# rebase is cancelled");
+ }
+ finally {
+ out.close();
+ }
+ }
+
+
+ /**
+ * Move selected row up. If row cannot be moved up, do nothing and return false.
+ *
+ * @param row a row to move
+ * @return true if row was moved
+ */
+ public boolean moveUp(final int row) {
+ if (row < 1 || row >= myEntries.size()) {
+ return false;
+ }
+ GitRebaseEntry e = myEntries.get(row);
+ myEntries.set(row, myEntries.get(row - 1));
+ myEntries.set(row - 1, e);
+ fireTableRowsUpdated(row - 1, row);
+ return true;
+ }
+
+ /**
+ * Move selected row down. If row cannot be moved down, do nothing and return false.
+ *
+ * @param row a row to move
+ * @return true if row was moved
+ */
+ public boolean moveDown(final int row) {
+ if (row < 0 || row >= myEntries.size() - 1) {
+ return false;
+ }
+ GitRebaseEntry e = myEntries.get(row);
+ myEntries.set(row, myEntries.get(row + 1));
+ myEntries.set(row + 1, e);
+ fireTableRowsUpdated(row, row + 1);
+ return true;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright 2000-2008 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.rebase;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.ui.UIUtil;
+
+import java.io.Closeable;
+
+/**
+ * The handler for rebase editor request. The handler shows {@link git4idea.rebase.GitRebaseEditor}
+ * dialog with the specified file. If user accepts the changes, it saves file and returns 0,
+ * otherwise it just returns error code.
+ */
+public class GitRebaseEditorHandler implements Closeable {
+ /**
+ * The logger
+ */
+ private final static Logger LOG = Logger.getInstance(GitRebaseEditorHandler.class.getName());
+ /**
+ * The service object that has created this handler
+ */
+ private final GitRebaseEditorService myService;
+ /**
+ * The context project
+ */
+ private final Project myProject;
+ /**
+ * The git repository root
+ */
+ private final VirtualFile myRoot;
+ /**
+ * The handler number
+ */
+ private final int myHandlerNo;
+ /**
+ * If true, the handler has been closed
+ */
+ private boolean myIsClosed;
+
+ /**
+ * The constructor from fields that is expected to be
+ * accessed only from {@link git4idea.rebase.GitRebaseEditorService}.
+ *
+ * @param service the service object that has created this handler
+ * @param project the context project
+ * @param root the git repository root
+ * @param handlerNo the handler no for this editor
+ */
+ GitRebaseEditorHandler(final GitRebaseEditorService service, final Project project, final VirtualFile root, final int handlerNo) {
+ myService = service;
+ myProject = project;
+ myRoot = root;
+ myHandlerNo = handlerNo;
+ }
+
+ /**
+ * Edit commits request
+ *
+ * @param path the path to eding
+ * @return the exit code to be returned from editor
+ */
+ public int editCommits(final String path) {
+ ensureOpen();
+ final Ref<Boolean> isSuccess = new Ref<Boolean>();
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ public void run() {
+ try {
+ GitRebaseEditor editor = new GitRebaseEditor(myProject, myRoot, path);
+ editor.show();
+ if (editor.isOK()) {
+ editor.save();
+ isSuccess.set(true);
+ return;
+ }
+ else {
+ editor.cancel();
+ isSuccess.set(true);
+ }
+ }
+ catch (Exception e) {
+ LOG.error("Failed to edit the git rebase file: " + path, e);
+ }
+ isSuccess.set(false);
+ }
+ });
+ return (isSuccess.isNull() || !isSuccess.get().booleanValue()) ? GitRebaseEditorMain.ERROR_EXIT_CODE : 0;
+ }
+
+ /**
+ * Check that handler has not yet been closed
+ */
+ private void ensureOpen() {
+ if (myIsClosed) {
+ throw new IllegalStateException("The handler was already closed");
+ }
+ }
+
+ /**
+ * Stop using the handler
+ */
+ public void close() {
+ ensureOpen();
+ myIsClosed = true;
+ myService.unregisterHandler(myHandlerNo);
+ }
+
+ /**
+ * @return the handler number
+ */
+ public int getHandlerNo() {
+ return myHandlerNo;
+ }
+}
--- /dev/null
+/*
+ * Copyright 2000-2008 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.rebase;
+
+import org.apache.xmlrpc.XmlRpcClientLite;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Arrays;
+import java.util.Vector;
+
+/**
+ * The rebase editor application, this editor is invoked by the git.
+ * The application passes its parameter using XML RCP service
+ * registered on the host passed as the first parameter. The application
+ * exits with exit code returned from the service.
+ */
+public class GitRebaseEditorMain {
+ /**
+ * The environment variable for handler no
+ */
+ @NonNls @NotNull public static final String IDEA_REBASE_HANDER_NO = "IDEA_REBASE_HANDER_NO";
+ /**
+ * The exit code used to indicate that editing was canceled or has failed in some other way.
+ */
+ public final static int ERROR_EXIT_CODE = 2;
+ /**
+ * Rebase editor handler name
+ */
+ @NonNls static final String HANDLER_NAME = "Git4ideaRebaseEditorHandler";
+
+ /**
+ * A private constructor for static class
+ */
+ private GitRebaseEditorMain() {
+ }
+
+ /**
+ * The application entry point
+ *
+ * @param args application arguments
+ */
+ @SuppressWarnings(
+ {"UseOfSystemOutOrSystemErr", "HardCodedStringLiteral", "CallToPrintStackTrace", "UseOfObsoleteCollectionType"})
+ public static void main(String[] args) {
+ if (args.length != 2) {
+ System.err.println("Invalid amount of arguments: " + Arrays.asList(args));
+ System.exit(ERROR_EXIT_CODE);
+ }
+ int port;
+ try {
+ port = Integer.parseInt(args[0]);
+ }
+ catch (NumberFormatException ex) {
+ System.err.println("Invalid port number: " + args[0]);
+ System.exit(ERROR_EXIT_CODE);
+ return;
+ }
+ final String handlerValue = System.getenv(IDEA_REBASE_HANDER_NO);
+ if (handlerValue == null) {
+ System.err.println("Handler no is not specified");
+ System.exit(ERROR_EXIT_CODE);
+ }
+ int handler;
+ try {
+ handler = Integer.parseInt(handlerValue);
+ }
+ catch (NumberFormatException ex) {
+ System.err.println("Invalid handler number: " + handlerValue);
+ System.exit(ERROR_EXIT_CODE);
+ return;
+ }
+ String file = args[1];
+ try {
+ XmlRpcClientLite client = new XmlRpcClientLite("localhost", port);
+ Vector<Object> params = new Vector<Object>();
+ params.add(handler);
+ params.add(file);
+ Integer exitCode = (Integer)client.execute(HANDLER_NAME + ".editCommits", params);
+ if (exitCode == null) {
+ exitCode = ERROR_EXIT_CODE;
+ }
+ System.exit(exitCode.intValue());
+ }
+ catch (Exception e) {
+ System.err.println("Unable to contact IDEA: " + e);
+ e.printStackTrace();
+ System.exit(ERROR_EXIT_CODE);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright 2000-2008 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.rebase;
+
+import com.intellij.ide.XmlRpcServer;
+import com.intellij.openapi.components.ApplicationComponent;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vcs.VcsException;
+import com.intellij.openapi.vfs.VirtualFile;
+import git4idea.commands.ScriptGenerator;
+import gnu.trove.THashMap;
+import org.apache.commons.codec.DecoderException;
+import org.apache.xmlrpc.XmlRpcClientLite;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Random;
+
+/**
+ * The service that generates editor script for
+ */
+public class GitRebaseEditorService implements ApplicationComponent {
+ /**
+ * the logger
+ */
+ private static final Logger LOG = Logger.getInstance(GitRebaseEditorService.class.getName());
+
+ /**
+ * The path to editor script
+ */
+ private File myScriptPath;
+ /**
+ * The lock object
+ */
+ private final Object myScriptLock = new Object();
+ /**
+ * The handlers to use
+ */
+ private final Map<Integer, GitRebaseEditorHandler> myHandlers = new THashMap<Integer, GitRebaseEditorHandler>();
+ /**
+ * The lock for the handlers
+ */
+ private final Object myHandlersLock = new Object();
+ /**
+ * XML rcp server
+ */
+ private final XmlRpcServer myXmlRpcServer;
+ /**
+ * Random number generator
+ */
+ private final static Random oursRandom = new Random();
+ /**
+ * If true, the component has been intialized
+ */
+ private boolean myInitialized = false;
+ /**
+ * The prefix for rebase editors
+ */
+ @NonNls private static final String GIT_REBASE_EDITOR_PREFIX = "git-rebase-editor-";
+
+ /**
+ * The constructor
+ *
+ * @param xmlRpcServer the XML RCP server instance
+ */
+ public GitRebaseEditorService(@NotNull final XmlRpcServer xmlRpcServer) {
+ myXmlRpcServer = xmlRpcServer;
+ }
+
+ /**
+ * @return an instance of the server
+ */
+ @NotNull
+ public static GitRebaseEditorService getInstance() {
+ final GitRebaseEditorService service = ServiceManager.getService(GitRebaseEditorService.class);
+ if (service == null) {
+ throw new IllegalStateException("The service " + GitRebaseEditorService.class.getName() + " cannot be located");
+ }
+ return service;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @NotNull
+ public String getComponentName() {
+ return getClass().getSimpleName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void initComponent() {
+ if (!myInitialized) {
+ myXmlRpcServer.addHandler(GitRebaseEditorMain.HANDLER_NAME, new InternalHandler());
+ myInitialized = true;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void disposeComponent() {
+ myXmlRpcServer.removeHandler(GitRebaseEditorMain.HANDLER_NAME);
+ synchronized (myScriptLock) {
+ if (myScriptPath != null) {
+ if (!myScriptPath.delete()) {
+ LOG.warn("The temporary file " + myScriptPath + " generated by git4idea plugin failed to be removed during disposing.");
+ }
+ myScriptPath = null;
+ }
+ }
+ }
+
+ /**
+ * Get file to the script service
+ *
+ * @return path to the script
+ * @throws java.io.IOException if script cannot be generated
+ */
+ @NotNull
+ public synchronized File getScriptPath() throws VcsException {
+ try {
+ synchronized (myScriptLock) {
+ if (myScriptPath == null) {
+ ScriptGenerator generator = new ScriptGenerator(GIT_REBASE_EDITOR_PREFIX, GitRebaseEditorMain.class);
+ generator.addInternal(Integer.toString(myXmlRpcServer.getPortNumber()));
+ generator.addClasses(XmlRpcClientLite.class, DecoderException.class);
+ myScriptPath = generator.generate();
+ }
+ return myScriptPath;
+ }
+ }
+ catch (IOException ex) {
+ throw new VcsException("Unable to generate script file: " + ex, ex);
+ }
+ }
+
+ /**
+ * @return the handler instance
+ */
+ public GitRebaseEditorHandler getHandler(Project project, VirtualFile root) {
+ initComponent();
+ GitRebaseEditorHandler rc = null;
+ synchronized (myHandlersLock) {
+ for (int i = Integer.MAX_VALUE; i > 0; i--) {
+ int code = Math.abs(oursRandom.nextInt());
+ // note that code might still be negative at this point if it is Integer.MIN_VALUE.
+ if (code > 0 && !myHandlers.containsKey(code)) {
+ rc = new GitRebaseEditorHandler(this, project, root, code);
+ break;
+ }
+ }
+ if (rc == null) {
+ throw new IllegalStateException("There is a problem with random number allocation");
+ }
+ myHandlers.put(rc.getHandlerNo(), rc);
+ }
+ return rc;
+ }
+
+
+ /**
+ * Unregister handler
+ *
+ * @param handlerNo the handler number.
+ */
+ void unregisterHandler(final int handlerNo) {
+ synchronized (myHandlersLock) {
+ if (myHandlers.remove(handlerNo) == null) {
+ throw new IllegalStateException("The handler " + handlerNo + " has been already remoted");
+ }
+ }
+ }
+
+ /**
+ * Unregister handler
+ *
+ * @param handlerNo the handler number.
+ */
+ @NotNull
+ GitRebaseEditorHandler getHandler(final int handlerNo) {
+ synchronized (myHandlersLock) {
+ GitRebaseEditorHandler h = myHandlers.get(handlerNo);
+ if (h == null) {
+ throw new IllegalStateException("The handler " + handlerNo + " has been already remoted");
+ }
+ return h;
+ }
+ }
+
+
+ /**
+ * The internal xml rcp handler
+ */
+ public class InternalHandler {
+ /**
+ * Edit commits for the rebase operation
+ *
+ * @param handlerNo the handler no
+ * @param path the path to edit
+ * @return exit code
+ */
+ public int editCommits(int handlerNo, String path) {
+ return getHandler(handlerNo).editCommits(path);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright 2000-2008 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.rebase;
+
+/**
+ * The entry for rebase editor
+ */
+class GitRebaseEntry {
+ /**
+ * The commit hash
+ */
+ private final String myCommit;
+ /**
+ * The commit comment subject line
+ */
+ private final String mySubject;
+ /**
+ * The action associated with the entry
+ */
+ private Action myAction = Action.pick;
+
+ /**
+ * The constructor
+ *
+ * @param commit the commit hash
+ * @param subject the commit subject
+ */
+ public GitRebaseEntry(final String commit, final String subject) {
+ myCommit = commit;
+ mySubject = subject;
+ }
+
+ /**
+ * @return the commit hash
+ */
+ public String getCommit() {
+ return myCommit;
+ }
+
+ /**
+ * @return the commit subject
+ */
+ public String getSubject() {
+ return mySubject;
+ }
+
+ /**
+ * @return the action associated with the commit
+ */
+ public Action getAction() {
+ return myAction;
+ }
+
+ /**
+ * @param action a new action to set
+ */
+ public void setAction(final Action action) {
+ myAction = action;
+ }
+
+
+ /**
+ * The action associated with the commit
+ */
+ static public enum Action {
+ /**
+ * the pick action
+ */
+ pick,
+ /**
+ * the edit action, the user will be offered to alter commit
+ */
+ edit,
+ /**
+ * the skip action
+ */
+ skip,
+ /**
+ * the squash action (for two or more commits)
+ */
+ squash, }
+}
--- /dev/null
+/*
+ * Copyright 2000-2008 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.rebase;
+
+import com.intellij.openapi.vfs.VirtualFile;
+
+/**
+ * The utilities related to rebase functionality
+ */
+public class GitRebaseUtils {
+ /**
+ * A private constructor for utility class
+ */
+ private GitRebaseUtils() {
+ }
+
+ /**
+ * Checks if the rebase is in the progress for the specified git root
+ *
+ * @param root the git root
+ * @return true if the rebase directory presents in the root
+ */
+ public static boolean isRebaseInTheProgress(VirtualFile root) {
+ return root.findFileByRelativePath(".git/rebase-merge") != null;
+ }
+}
import com.intellij.util.Icons;
import com.intellij.util.ui.Tree;
import com.intellij.util.ui.tree.TreeUtil;
+import git4idea.GitBranch;
+import git4idea.GitTag;
import git4idea.commands.GitHandler;
import git4idea.commands.GitHandlerUtil;
import git4idea.commands.GitSimpleHandler;
while (s.hasMoreData()) {
s.tabToken(); // skip last commit hash
String ref = s.line();
- if (ref.startsWith(GitRefspecPanel.REFS_HEADS_PREFIX)) {
+ if (ref.startsWith(GitBranch.REFS_HEADS_PREFIX)) {
myBranches.add(ref);
}
- else if (ref.startsWith(GitRefspecPanel.REFS_TAGS_PREFIX)) {
+ else if (ref.startsWith(GitTag.REFS_TAGS_PREFIX)) {
myTags.add(ref);
}
else {
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.DocumentAdapter;
import com.intellij.util.containers.HashMap;
+import git4idea.GitBranch;
import git4idea.GitRemote;
+import git4idea.GitTag;
import git4idea.commands.StringScanner;
import git4idea.i18n.GitBundle;
import git4idea.validators.GitBranchNameValidator;
* Mapping table model
*/
private final MyMappingTableModel myReferencesModel = new MyMappingTableModel();
- /**
- * Prefix for local branches
- */
- @NonNls public static final String REFS_HEADS_PREFIX = "refs/heads/";
- /**
- * Prefix for tags
- */
- @NonNls public static final String REFS_TAGS_PREFIX = "refs/tags/";
- /**
- * Prefix for remotes
- */
- @NonNls public static final String REFS_REMOTES_PREFIX = "refs/remotes/";
/**
* A constructor
myReferencesModel.addMapping(false, tag, tag);
}
for (String head : d.getSelected(false)) {
- myReferencesModel.addMapping(true, head, remoteName(head.substring(REFS_HEADS_PREFIX.length())));
+ myReferencesModel.addMapping(true, head, remoteName(head.substring(GitBranch.REFS_HEADS_PREFIX.length())));
}
}
});
* @return the full path to the head
*/
private static String tagRemoteName(final String remoteName, final String tagName) {
- return REFS_TAGS_PREFIX + remoteName + "/" + tagName;
+ return GitTag.REFS_TAGS_PREFIX + remoteName + "/" + tagName;
}
/**
* @return the tag name
*/
private static String tagName(final String tagName) {
- return REFS_TAGS_PREFIX + tagName;
+ return GitTag.REFS_TAGS_PREFIX + tagName;
}
/**
* @return the full path to the head
*/
private static String remoteName(final String remote, final String headName) {
- return remote.length() != 0 ? REFS_REMOTES_PREFIX + remote + "/" + headName : headName(headName);
+ return remote.length() != 0 ? GitBranch.REFS_REMOTES_PREFIX + remote + "/" + headName : headName(headName);
}
/**
* @return the full path to the head
*/
private static String headName(final String head) {
- return REFS_HEADS_PREFIX + head;
+ return GitBranch.REFS_HEADS_PREFIX + head;
}
/**
}
+ /**
+ * Get text field from combobox
+ *
+ * @param cb a combobox to examine
+ * @return the text field reference
+ */
+ public static JTextField getTextField(JComboBox cb) {
+ return (JTextField)cb.getEditor().getEditorComponent();
+ }
+
/**
* Create list cell renderd for remotes. It shows both name and url and highlights the default
* remote for the branch with bold.
}
myBranches.clear();
try {
- GitBranch.list(myProject, getGitRoot(), false, true, myBranches);
+ GitBranch.listAsStrings(myProject, getGitRoot(), false, true, myBranches);
}
catch (VcsException e) {
// ignore error
package org.jetbrains.git4idea.ssh;
import com.intellij.ide.XmlRpcServer;
-import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.util.PathUtil;
import com.trilead.ssh2.KnownHosts;
+import git4idea.commands.ScriptGenerator;
import git4idea.i18n.GitBundle;
import gnu.trove.THashMap;
import org.apache.commons.codec.DecoderException;
import org.jetbrains.annotations.NotNull;
import java.io.File;
-import java.io.FileWriter;
import java.io.IOException;
-import java.io.PrintWriter;
import java.util.Random;
import java.util.Vector;
*/
@NonNls private static final String GIT_SSH_PREFIX = "git-ssh-";
/**
- * The extension of the ssh script name
+ * If true, the component has been intialized
*/
- @NonNls private static final String GIT_SSH_EXT;
-
- static {
- if (SystemInfo.isWindows) {
- GIT_SSH_EXT = ".cmd";
- }
- else {
- GIT_SSH_EXT = ".sh";
- }
- }
-
+ private boolean myInitialized = false;
/**
* Path to the generated script
*/
* Get file to the script service
*
* @return path to the script
- * @throws IOException
+ * @throws IOException if script cannot be generated
*/
- @SuppressWarnings({"HardCodedStringLiteral"})
@NotNull
public synchronized File getScriptPath() throws IOException {
- myXmlRpcServer.addHandler(HANDLER_NAME, new InternalRequestHandler());
if (myScriptPath == null) {
- myScriptPath = File.createTempFile(GIT_SSH_PREFIX, GIT_SSH_EXT);
- myScriptPath.deleteOnExit();
- PrintWriter out = new PrintWriter(new FileWriter(myScriptPath));
- try {
- if (SystemInfo.isWindows) {
- out.println("@echo off");
- }
- else {
- out.println("#!/bin/sh");
- }
- String mainPath = PathUtil.getJarPathForClass(SSHMain.class);
- String sshPath = PathUtil.getJarPathForClass(KnownHosts.class);
- String xmlRcpPath = PathUtil.getJarPathForClass(XmlRpcClientLite.class);
- String codecPath = PathUtil.getJarPathForClass(DecoderException.class);
- String resPath = getJarForResource(GitBundle.class, "/git4idea/i18n/GitBundle.properties");
- String utilPath = PathUtil.getJarPathForClass(FileUtil.class);
- // six parameters are enough for the git case (actually 4 are enough)
- out.print("java -cp \"" +
- mainPath +
- File.pathSeparator +
- sshPath +
- File.pathSeparator +
- codecPath +
- File.pathSeparator +
- xmlRcpPath +
- File.pathSeparator +
- resPath +
- File.pathSeparator +
- utilPath +
- "\" " +
- SSHMain.class.getName() +
- " " +
- myXmlRpcServer.getPortNumber());
- if (SystemInfo.isWindows) {
- out.println(" %1 %2 %3 %4 %5 %6");
- }
- else {
- out.println(" \"$@\"");
- }
- }
- finally {
- out.close();
- }
- FileUtil.setExectuableAttribute(myScriptPath.getAbsolutePath(), true);
+ ScriptGenerator generator = new ScriptGenerator(GIT_SSH_PREFIX, SSHMain.class);
+ generator.addInternal(Integer.toString(myXmlRpcServer.getPortNumber()));
+ generator.addClasses(XmlRpcClientLite.class, DecoderException.class);
+ generator.addClasses(KnownHosts.class, FileUtil.class);
+ generator.addResource(GitBundle.class, "/git4idea/i18n/GitBundle.properties");
+ myScriptPath = generator.generate();
}
return myScriptPath;
}
- /**
- * Get path for resources.jar
- *
- * @param context a context class
- * @param res a resource
- * @return a path to classpath entry
- */
- @SuppressWarnings({"SameParameterValue"})
- private static String getJarForResource(Class context, String res) {
- String resourceRoot = PathManager.getResourceRoot(context, res);
- return new File(resourceRoot).getAbsoluteFile().getAbsolutePath();
- }
-
/**
* {@inheritDoc}
*/
* {@inheritDoc}
*/
public void initComponent() {
- myXmlRpcServer.addHandler(HANDLER_NAME, new InternalRequestHandler());
- // do nothing
+ if (!myInitialized) {
+ myXmlRpcServer.addHandler(HANDLER_NAME, new InternalRequestHandler());
+ myInitialized = true;
+ }
}
/**
* @return an identifier to pass to the environment variable
*/
public synchronized int registerHandler(@NotNull Handler handler) {
+ initComponent();
while (true) {
int rnd = RANDOM.nextInt();
if (rnd == Integer.MIN_VALUE) {