git4idea: Implemeted forced merge/rebase and stash options for update operation

This commit is contained in:
Constantine Plotnikov
2009-09-30 21:29:25 +04:00
parent 1d502ca8dc
commit aae7863535
11 changed files with 1023 additions and 417 deletions
+45 -4
View File
@@ -49,7 +49,27 @@ import java.util.*;
* Git utility/helper methods
*/
public class GitUtil {
/**
* The logger instance
*/
private final static Logger LOG = Logger.getInstance("#git4idea.GitUtil");
/**
* Comparator for virtual files by name
*/
public static final Comparator<VirtualFile> VIRTUAL_FILE_COMPARATOR = new Comparator<VirtualFile>() {
public int compare(final VirtualFile o1, final VirtualFile o2) {
if (o1 == null && o2 == null) {
return 0;
}
if (o1 == null) {
return -1;
}
if (o2 == null) {
return 1;
}
return o1.getPresentableUrl().compareTo(o2.getPresentableUrl());
}
};
/**
* A private constructor to suppress instance creation
@@ -269,8 +289,8 @@ public class GitUtil {
* @return timestamp as {@link Date} object
*/
public static Date parseTimestamp(String value) {
return new Date(Long.parseLong(value.trim()) * 1000);
}
return new Date(Long.parseLong(value.trim()) * 1000);
}
/**
* Get git roots from content roots
@@ -629,8 +649,10 @@ public class GitUtil {
return getPossibleBase(file, n - 1, path);
}
public static List<CommittedChangeList> getLocalCommittedChanges(final Project project, final VirtualFile root,
final Consumer<GitSimpleHandler> parametersSpecifier) throws VcsException {
public static List<CommittedChangeList> getLocalCommittedChanges(final Project project,
final VirtualFile root,
final Consumer<GitSimpleHandler> parametersSpecifier)
throws VcsException {
final List<CommittedChangeList> rc = new ArrayList<CommittedChangeList>();
GitSimpleHandler h = new GitSimpleHandler(project, root, GitHandler.LOG);
@@ -650,4 +672,23 @@ public class GitUtil {
}
return rc;
}
/**
* Cast or wrap exception into a vcs exception, errors and runtime exceptions are just thrown throw.
*
* @param t an exception to throw
* @return a wrapped exception
*/
public static VcsException rethrowVcsException(Throwable t) {
if (t instanceof Error) {
throw (Error)t;
}
if (t instanceof RuntimeException) {
throw (RuntimeException)t;
}
if (t instanceof VcsException) {
return (VcsException)t;
}
return new VcsException(t.getMessage(), t);
}
}
+1 -1
View File
@@ -193,7 +193,7 @@ public class GitVcs extends AbstractVcs {
myRollbackEnvironment = gitRollbackEnvironment;
myRevSelector = new GitRevisionSelector();
myConfigurable = new GitVcsConfigurable(mySettings, myProject);
myUpdateEnvironment = new GitUpdateEnvironment(myProject);
myUpdateEnvironment = new GitUpdateEnvironment(myProject, this, mySettings);
myMergeProvider = new GitMergeProvider(myProject);
myCommittedChangeListProvider = new GitCommittedChangeListProvider(myProject);
myOutgoingChangesProvider = new GitOutgoingChangesProvider(myProject);
@@ -70,11 +70,7 @@ public abstract class GitRepositoryAction extends AnAction {
GitBundle.getString("repository.action.missing.roots.title"));
return;
}
Collections.sort(roots, new Comparator<VirtualFile>() {
public int compare(final VirtualFile o1, final VirtualFile o2) {
return o1.getPresentableUrl().compareTo(o2.getPresentableUrl());
}
});
Collections.sort(roots, GitUtil.VIRTUAL_FILE_COMPARATOR);
// get default root
final VirtualFile[] vFiles = e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
VirtualFile defaultRootVar = null;
@@ -8,6 +8,7 @@ import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeListImpl;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import git4idea.GitContentRevision;
import git4idea.GitRevisionNumber;
@@ -35,6 +36,45 @@ public class GitChangeUtils {
private GitChangeUtils() {
}
/**
* Parse changes from lines
*
* @param project the context project
* @param root the git root
* @return a set of unmerged files
* @throws VcsException if the input format does not matches expected format
*/
public static List<VirtualFile> unmergedFiles(Project project, VirtualFile root) throws VcsException {
HashSet<VirtualFile> unmerged = new HashSet<VirtualFile>();
String rootPath = root.getPath();
GitSimpleHandler h = new GitSimpleHandler(project, root, GitHandler.LS_FILES);
h.setNoSSH(true);
h.setSilent(true);
h.addParameters("--unmerged");
LocalFileSystem lfs = LocalFileSystem.getInstance();
for (StringScanner s = new StringScanner(h.run()); s.hasMoreData();) {
if (s.isEol()) {
s.nextLine();
continue;
}
s.boundedToken('\t');
final String relative = s.line();
String path = rootPath + "/" + GitUtil.unescapePath(relative);
VirtualFile file = lfs.refreshAndFindFileByPath(path);
assert file != null : "The unmerged file is not found " + path;
file.refresh(false, false);
unmerged.add(file);
}
if(unmerged.size() == 0) {
return Collections.emptyList();
} else {
ArrayList<VirtualFile> rc = new ArrayList<VirtualFile>(unmerged.size());
rc.addAll(unmerged);
Collections.sort(rc, GitUtil.VIRTUAL_FILE_COMPARATOR);
return rc;
}
}
/**
* Parse changes from lines
*
@@ -57,7 +97,7 @@ public class GitChangeUtils {
StringScanner sc = new StringScanner(s);
parseChanges(project, vcsRoot, thisRevision, parentRevision, sc, changes, ignoreNames);
if (sc.hasMoreData()) {
throw new IllegalStateException("Uknown file status: " + sc.line());
throw new IllegalStateException("Unknown file status: " + sc.line());
}
}
@@ -87,6 +87,14 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings>
* IDEA SSH should be used instead of native SSH.
*/
public SshExecutable SSH_EXECUTABLE = DEFAULT_SSH;
/**
* True if stash/unstash operation should be performed before update.
*/
public boolean UPDATE_STASH = true;
/**
* The type of update operation to perform
*/
public UpdateType UPDATE_TYPE = UpdateType.BRANCH_DEFAULT;
/**
* Save an author of the commit and make it the first one. If amount of authors exceeds the limit, remove least recently selected author.
@@ -200,4 +208,16 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings>
* Naive SSH.
*/
NATIVE_SSH, }
/**
* The type of update to perform
*/
public enum UpdateType {
/** Use default specified in the config file for the branch */
BRANCH_DEFAULT,
/** Merge fetched commits with local branch */
MERGE,
/** Rebase local commits upon the fetched branch*/
REBASE
}
}
@@ -1,385 +1,401 @@
action.text.show.all.submitted=Show all files changed by this commit
add.action.name=Add
addrefspec.button=Add
addrefspec.get.references.tooltip=Get remote tag and branch references (depending on checkbox state).
addrefspec.get.references=&Get References
addrefspec.getting.references.title=Getting remote references for {0}
addrefspec.include.branches.tooltip=The next update references wil retrieve remote branches.
addrefspec.include.branches=Include &branches
addrefspec.include.tags.tooltip=The next update references wil retrieve remote tags.
addrefspec.include.tags=Include &tags
addrefspec.node.branches=Branches
addrefspec.node.tags=Tags
addrefspec.reference.chooser.tooltip=Select remote branch and tag references
addrefspec.title=Add Reference(s)
annotate.action.name=Annotate
annotation.tool.tip=commit {0}\nAuthor: {1}\nDate: {2}\n\n{3}
checking.out=Checkout {0}
checkout.action.name=Checkout
checkout.branch.label=&Checkout
checkout.branch.name.exists=Branch with the same name exists. Use override option to force branch creation.
checkout.branch=Checkout
checkout.create.ref.log.tooltip=If checked the reference log is created for the branch. It allows time based searches. (the option \"-l\")
checkout.create.ref.log=Create ref &log
checkout.include.tags.tooltip=If checked, the combobox will inclue tags names as well as branches.
checkout.include.tags=&Include tags
checkout.invalid.new.branch.name=Invalid new branch name
checkout.new.branch.tooltip=Enter name of new branch here. Leave blank if you do not want to create a new branch.
checkout.new.branch=As &new branch
checkout.override.branch=&Override
checkout.override.tooltip=If ckecked a branch will be created even if a branch with the same name already exists. The previous branch will be deleted.
checkout.ref.tooltip=Select branch, tag, or enter commit reference
checkout.retrieving.branches.and.tags=Retrieving branches and tags
checkout.track.branch=&Track branch
checkout.track.tooltip=If checked, the newly created branch will track original branch during pull.
checkout.validate.tooltip=Use this button to validate reference expression if entered manually.
checkout.validate=&Validate
checkout.validation.failed=Source revision validation failed
clone.button=Clone
clone.destination.directory.description=Select a parent directory destination directory for clone
clone.destination.directory.title=Parent Directory
clone.destination.exists.error=The path {0} exists. The Git cannot clone to existing directory.
clone.dir.name=Directory &Name
clone.invalid.origin=The origin name is in invalid format.
clone.invalid.url=Repository URL is a malformed URL or non-existent directory.
clone.origin=&Origin Name
clone.parent.dir=&Parent Directory
clone.parent.missing.error=The parent path {0} must exist.
clone.repository.url=Git &Repository URL
clone.test.failed.error=Repository test has failed.
clone.test.success.message=<html>Connection to repository <tt>{0}</tt> has been successful.</html>
clone.test.success=Connection successful
clone.test=&Test
clone.testing=Testing repository {0}
clone.title=Clone Repository
clone.url.is.not.directory.error=Repository URL is not a directory.
cloning.repository=Cloning source repository {0}
command.cancelled=The command was cancelled.
commit.action.name=Commit
commit.author.tooltip=<html>Specify a commit author here if it is different from committer. The author should be in the format: Author Name &lt;author@ema.il&gt;</html>
commit.author=&Author:
commit.partial.merge.message=<html>The following files are not included in commit.<ul>{0}</ul>Perform commit with all files included?</html>
commit.partial.merge.title=Partial Merge Commit
commit.push.changes.tooltip=When this option is enabled, changes are pushed to the server after commit.
commit.push.changes=&Push Changes
common.current.branch.tooltip=The currently checked out branch.
common.current.branch=Current Branch:
common.git.root.tooltip=Select git vcs root
common.git.root=Git &Root:
common.no.active.branch=<no active branch>
computing.annotation=Computing annotation for {0}
current.branch.action.name=CurrentBranch
current.branch.change.tracked=Change Tracked Branch
current.branch.message=Checked out branch: {0}
current.branch.title=Current Branch
current.branch.tracked.branch.none=<none>
current.branch.tracked.branch.tooltip=Select the branch to track
current.branch.tracked.branch=&Branch:
current.branch.tracked.remote.none=<none>
current.branch.tracked.remote.this=<this repository>
current.branch.tracked.repository.tooltip=Select repository to track
current.branch.tracked.repository=Re&pository:
current.branch.tracked.title=Tracked Branch
debug.git.exec=DEBUG: work-dir: [{0}] exec: [{1}]
delete.action.name=Delete
diff.find.error=Finding revision for diff: {0}
error.dialog.title=Error
error.list.title={0} Error:
error.occurred.during=Error occurred during ''{0}''
fetch.action.name=Fetch
fetch.button=Fetch
fetch.force.references.update.tooltip=Forces update of branch references for which update is not forced in refrence mapping.
fetch.force.references.update=Force references &update
fetch.remote.label=Re&mote:
fetch.remote.tooltip=Remote name or url for fetch
fetch.tags.label=Fetch &tags:
fetch.tags.policy.all=All
fetch.tags.policy.for.fetched.commits=For fetched commits
fetch.tags.policy.none=None
fetch.tags.tooltip=<html>Select fetched commits policy<ul><li><i>For fetched commits</i> means tags associated with commits on fetched branches are fetched.</li><li><i>All</i> means that all tags and reference commits are fetched</li><li><i>None</i> means that no tags are fetched.</li></ul></html>
fetch.title=Git Fetch
fetching.tags.title=Updating tags from {0}
fetching.title=Fetching from {0}
find.git.description=Select path to git executable
find.git.error.title=Error Running git
find.git.success.title=Git Executed Successfully
find.git.title=Git Configuration
find.git.unsupported.message=<html><tt>{0}</tt><br>This version is unsupported, and some plugin functionality could fail to work.<br>The minimal supported version is <em>{1}</em>.</html>
fix.roots.button=Accept
fix.roots.list.tooltip=The suggested list of Git VCS roots, new roots are marked as bold, removed roots are marked as overstriked.
fix.roots.message=The following Git vcs roots will be used instead of the current Git VCS roots.
fix.roots.title=Fix Git VCS Roots
fix.roots.valid.message=The invalid Git roots have been fixed already.
fix.roots.valid.title=All Git Roots Are Valid
getting.history=Getting history for {0}
git.default.commit.message=\n# Brief commit description here\n\n# Full commit description here (comment lines starting with '#' will not be included)\n\n
git.error.exit=The git process exited with the code {0}
git.running=<html>Running: {0}</html>
git.vcs.config.path.label=Path to &git executable:
git.vcs.config.ssh.mode.idea=IDEA ssh
git.vcs.config.ssh.mode.native=Native
git.vcs.config.ssh.mode.tooltip=<html>Specify which version of SSH to be used with git.<ul><li><b>Native</b> means that the native ssh will be used.</li><li><b>IDEA SSH</b> means that the implementation provided by the IDEA will be used.</li></ul>The native implementation might cause hangups on some platforms. In native case, you also might need to configure <em>ssh-askpass</em> for your platform to recieve GUI promopts for passwords.</html>
git.vcs.config.ssh.mode=&SSH executable:
git.vcs.config.test.label=Test
git.vcs.config.test=&Test
index.file.error=Updating file in the index failed
init.add.root.message=Do you want to add this directory as vcs root?
init.add.root.title=Git Init
init.destination.directory.description=Select directory where the new Git repository will be created.
init.destination.directory.title=Select directory for git init
init.error.already.under.git=The selected directory {0} is already under git. The submodules are not yet supported.
init.error.title=git init Error
merge.action.name=Merge
merge.add.log.information.tooltip=Add log information to the commit message (\"--log\" option)
merge.add.log.information=Add &log information
merge.branch.button=Merge
merge.branch.message=Select branch to merge into this one ({0})
merge.branch.title=Merge Branches
merge.branches.tooltip=<html>The chooser for braches. Select one or more braches to merge (already merged branches are not shown)</html>.
merge.branches=&Branches to merge:
merge.commit.message.tooltip=The commit message to use in case if merge results in commit (\"-m\" option)
merge.commit.message=Commit &Message
merge.default.strategy=<default>
merge.is.not.needed=Merge is not needed for the file {0}
merge.load.files=Loading files for merge
merge.no.commit.tooltip=Force no commit for merge (the \"--no-commit\" option)
merge.no.commit=No &commit
merge.no.fast.forward.tooltip=Disable fast forward (\"--no-ff\" option)
merge.no.fast.forward=No &fast forward
merge.retrieving.branches=Retrieving unmerged branches
merge.squash.commit=S&quash commit
merge.squash.tooltip=Squash all changes into the single commit (\"--squash\" option)
merge.strategy.tooltip=The merge strategy to use (\"-s\" option)
merge.strategy=&Strategy:
merge.tool.action.name=MergeTool
merge.tool.column.status.deleted=Deleted
merge.tool.column.status.modified=Modified
merge.tool.column.theirs.status=Theirs
merge.tool.column.yours.status=Yours
merging.branch=Merging branch {0}
merging.title=Merging changes to {0}
paths.affected.title=Paths affected in commit {0}
pull.action.name=Pull
pull.button=Pull
pull.force.reference.update=Force reference &update
pull.get.branches.tooltip=Get branch names from remote repository. Otherwise a locally cached information is used.
pull.get.branches=&Get Branches
pull.getting.remote.branches=Getting remote branches
pull.remote.tooltip=Registered remote name or URL.
pull.remote=Re&mote:
pull.retrieving.remotes=Retrieving remotes
pull.title=Pull changes
pull.url.message=Enter remote repository URL to pull/merge (empty for default):
pull.url.title=Pull URL
pulling.title=Pulling changes from {0}
push.action.name=Push
push.branches.tooltip=Select branches to push
push.branches=&Branches:
push.button=Push
push.force.update.tooltip=If selected remote ref is updated even if they are is not an ancestor of the local ref.
push.force.update=&Force update
push.policy.all=All
push.policy.default=Default
push.policy.mirror=Mirror
push.policy.selected=Selected branches
push.policy.tooltip=<html>Select push policy:<ul><li><em>Default</em> - the push is done according to the configuration of the remote.</li><li><em>Selected branches</em> - selected branches are pushed.</li><li><em>All</em> - all references under refs/heads are pushed.</li><li><em>Mirror</em> - all references under refs/ are pushed including tags and remotes.</li></ul></html>
push.policy=&Push:
push.remote.tooltip=Specify remote repository URL or remote name where to push changes.
push.remote=Re&mote:
push.show.tags.tooltip=If selected, the tags are shown in branch chooser as well.
push.show.tags=Show ta&gs
push.tags.tooltip=All tag refereneces are pushed in addition to references specified in references section.
push.tags=Push &tags
push.title=Push Changes
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.button=Rebase
rebase.continue.action.name=Continue Rebasing
rebase.editor.action.column=Action
rebase.editor.button=Start Rebasing
rebase.editor.comment.column=Comment
rebase.editor.commit.column=Commit
rebase.editor.invalid.entryset=No commits found to rebase
rebase.editor.invalid.squash=The first non-skip commint could not be marked as squashed since squash merges commit with the previous commit.
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.result.amend.title=Rebase Suspended
rebase.result.amend=Stopped for amending commit while rebasing ({0}/{1}).\nAmmed commit and continue the rebase process.
rebase.result.cancelled.title=Rebase Cancelled
rebase.result.cancelled=The rebase process was cancelled.
rebase.result.conflict.title=Rebase Suspended
rebase.result.conflict=Stopped rebasing because of conflict ({0}/{1}).\nResolve conflicts and continue the rebase process.
rebase.result.error.title=Rebase Error
rebase.result.error=Stopped rebasing because of error while rebasing ({0}/{1}).\nCheck vcs console for details.
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.unstructured.editor.button=Resume Rebasing
rebase.unstructured.editor.git.root=Git Root:
rebase.unstructured.editor.message=Git rebase operation requested additional &information through the editor:
rebase.unstructured.editor.title=Addtional Rebase Input
rebase.unstructured.editor.tooltip=Edit this text according to instructions provided inline
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.add.all.tags=Add All Ta&gs
refspec.add.ref.tooltip=Add branch or tag by name
refspec.add.ref=&Add...
refspec.branch.prefix.tooltip=Specify default branch prefix for the mapping.
refspec.branch.prefix=Remote &Name:
refspec.column.force=Force
refspec.column.local=Local
refspec.column.remote=Remote
refspec.default.tooltip=Restore default reference mapping
refspec.default=&Default
refspec.remove.tooltip=Delete refspec entry
refspec.remove=Remo&ve
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.
reset.action.name=Reset Head ...
reset.button=Reset
reset.commit.invalid=The specified commit expression did not pass validation.
reset.commit.label=To &Commit:
reset.commit.tooltip=The commit that will become the current HEAD\n as result of reset operation.
reset.title=Reset Head
reset.type.hard=Hard
reset.type.mixed=Mixed
reset.type.soft=Soft
reset.type.tooltip=<html>The reset type (see also <code>git reset</code> man page):<ul><li><b>Mixed</b> resets index but not working tree</li><li><b>Soft</b> leaves index and working tree, just moves head pointer</li><li><b>Hard</b> resets index and working tree.<em>Changes in the working tree will be lost</em></li></ul></html>
reset.type=Reset &Type:
reset.validate.tooltip=Validate the commit pointer and check the content of referenced commit.
reset.validate=&Validate
resetting.title=Resetting HEAD...
revert.action.name=Revert
revision.graph=RevisionGraph
root.tracker.message=Some configured Git VCS roots are not under Git or have Git repositories in subdirectories without configured VCS root.
select.branch.to.checkout=Select branch to checkout
show.all.paths.affected.action.name=Show All Affected Paths
ssh.ask.passphrase.title=SSH Key Passphrase
ssh.askPassphrase.message=Please enter passphrase for the private key {0} (the user name is {1})
ssh.changed.host.key=<html>The server host key for the host {0}:{1} has changed to {2} (type {3}).\nDo you want to accept the changed key?</html>
ssh.confirm.key.titile=Confirm SSH Server Key
ssh.error.title=Authentication error
ssh.keyboard.interactive.title=SSH Keyboard Interactive: {0}
ssh.keyboard.interactive.username=Username:
ssh.new.host.key=<html>Connecting to a new host {0}:{1} that has the key {2} (type {3}).\nDo you want to add this host to known hosts database?</html>
ssh.password.message=Please enter password for user {0}
ssh.password.title=SSH Password Login
sshmain.failed.to.verify.key=Failed to verify key: {0}
sshmain.forwarding.failed=Forwarding {0} failed: {1}
sshmain.invald.host.key=Invald host key {0} {1}
sshmain.invalid.amount.of.arguments=Invalid amount of arguments: {0}
sshmain.invalidpassphrase=Invalid passphrase for the key {0}
sshmain.keyboard.interactive.failed=Keyboard interactive authentication failed.
sshmain.password.failed=Invalid user or password.
sshmain.pk.authenitication.failed=Authentication using key {0} failed.
sshmain.too.mush.passphrase.guesses=Invalid passphrase for the key {0}({1} attempts)
stash.action.name=Stash
stash.button=Create Stash
stash.keep.index.tooltip=If this checkbox is selected, indexed changes are kept in the index.
stash.keep.index=Keep &index
stash.message.tooltip=Enter stash message here.
stash.message=&Message:
stash.title=Stash
stashing.title=Stashing changes...
tag.action.name=Tag
tag.button=Create Tag
tag.commit.label=&Commit:
tag.commit.tooltip=Enter name of commit or object to tag or leave blank to use HEAD.
tag.error.creating.message.file.message=Unable to create message file: {0}
tag.error.creating.message.file.title=Error creating message file
tag.error.invalid.commit=The commit or object name is invalid.
tag.error.tag.exists=The tag with the same name exists.
tag.force.tooltip=Force creation of the text even if tag with such name already exists.
tag.force=&Force
tag.getting.existing.tags=Getting existing tags...
tag.message.label=&Message:
tag.message.tooltip=If the message is not empty, an annotated tag is created.
tag.message=Specify tag name:
tag.name.label=Tag &Name:
tag.name.tooltip=Enter the new tag name here.
tag.nonvcs.error.message=ERROR: Files not tagged, not all are under VCS root!
tag.nonvcs.error.title=Tag Result
tag.title=Tag
tag.validate.tooltip=Click this button to the validate commit to be tagged.
tag.validate=&Validate
tagging.title=Tagging files...
unindexed.files.changlelist.name=Unindexed Files
unstash.action.name=UnStash
unstash.branch.label\:=As new &branch:
unstash.branch.tooltip=If non-empty name is entered, the stash is checked out as a new branch.
unstash.button.apply=Apply Stash
unstash.button.branch=Branch
unstash.button.pop=Pop Stash
unstash.clear.tooltip=Delete all stashes in the repository.
unstash.clear=&Clear
unstash.clearing.stashes=Clearing stashes...
unstash.drop.tooltip=Delete selected stash
unstash.drop=&Drop
unstash.dropping.stash=Dropping stash {0}...
unstash.error.branch.exists=The specified branch already exists
unstash.error.invalid.branch.name=Invalid branch name
unstash.pop.stash.tooltip=If selected the stash is dropped after it is applied.
unstash.pop.stash=&Pop stash
unstash.reinstate.index.tooltip=Attempt to reinstate index as well as working tree changes.
unstash.reinstate.index=Reinstate &index
unstash.stashes.item=<html><b><tt>{0}</tt></b>:<i>{1}</i>:{2}</html>
unstash.stashes.tooltip=Select a stash to operate for.
unstash.stashes=&Stashes:
unstash.title=UnStash Changes
unstash.view.tooltip=View selected stash
unstash.view=&View
unstashing.title=UnStashing changes...
util.remote.renderer.default=<html><b>{0}</b>(<i>{1}</i>)</html>
util.remote.renderer.none=<html><i>None</i></html>
util.remote.renderer.normal=<html><b>{0}</b>(<i>{1}</i>)</html>
util.remote.renderer.self=<html><i>Current repository</i></html>
vcs.unable.to.run.git=Unable to run git: {0} ({1})
vcs.unsupported.version=Unsupported version of git configured: {0}. The minimal supported version is {1}
vfs.listener.add.single.prompt=Do you want to add the following file to Git?\n{0}\n\nIf you say NO, you can still add it later manually.
vfs.listener.add.single.title=Add file to Git
vfs.listener.add.title=Add files to Git
vfs.listener.delete.single.prompt=Do you want to delete the following file from Git?\n{0}\n\nIf you say NO, you can still delete it later manually.
vfs.listener.delete.single.title=Delete file from Git
vfs.listener.delete.title=Delete files from Git
action.text.show.all.submitted=Show all files changed by this commit
add.action.name=Add
addrefspec.button=Add
addrefspec.get.references.tooltip=Get remote tag and branch references (depending on checkbox state).
addrefspec.get.references=&Get References
addrefspec.getting.references.title=Getting remote references for {0}
addrefspec.include.branches.tooltip=The next update references wil retrieve remote branches.
addrefspec.include.branches=Include &branches
addrefspec.include.tags.tooltip=The next update references wil retrieve remote tags.
addrefspec.include.tags=Include &tags
addrefspec.node.branches=Branches
addrefspec.node.tags=Tags
addrefspec.reference.chooser.tooltip=Select remote branch and tag references
addrefspec.title=Add Reference(s)
annotate.action.name=Annotate
annotation.tool.tip=commit {0}\nAuthor: {1}\nDate: {2}\n\n{3}
checking.out=Checkout {0}
checkout.action.name=Checkout
checkout.branch.label=&Checkout
checkout.branch.name.exists=Branch with the same name exists. Use override option to force branch creation.
checkout.branch=Checkout
checkout.create.ref.log.tooltip=If checked the reference log is created for the branch. It allows time based searches. (the option \"-l\")
checkout.create.ref.log=Create ref &log
checkout.include.tags.tooltip=If checked, the combobox will inclue tags names as well as branches.
checkout.include.tags=&Include tags
checkout.invalid.new.branch.name=Invalid new branch name
checkout.new.branch.tooltip=Enter name of new branch here. Leave blank if you do not want to create a new branch.
checkout.new.branch=As &new branch
checkout.override.branch=&Override
checkout.override.tooltip=If ckecked a branch will be created even if a branch with the same name already exists. The previous branch will be deleted.
checkout.ref.tooltip=Select branch, tag, or enter commit reference
checkout.retrieving.branches.and.tags=Retrieving branches and tags
checkout.track.branch=&Track branch
checkout.track.tooltip=If checked, the newly created branch will track original branch during pull.
checkout.validate.tooltip=Use this button to validate reference expression if entered manually.
checkout.validate=&Validate
checkout.validation.failed=Source revision validation failed
clone.button=Clone
clone.destination.directory.description=Select a parent directory destination directory for clone
clone.destination.directory.title=Parent Directory
clone.destination.exists.error=The path {0} exists. The Git cannot clone to existing directory.
clone.dir.name=Directory &Name
clone.invalid.origin=The origin name is in invalid format.
clone.invalid.url=Repository URL is a malformed URL or non-existent directory.
clone.origin=&Origin Name
clone.parent.dir=&Parent Directory
clone.parent.missing.error=The parent path {0} must exist.
clone.repository.url=Git &Repository URL
clone.test.failed.error=Repository test has failed.
clone.test.success.message=<html>Connection to repository <tt>{0}</tt> has been successful.</html>
clone.test.success=Connection successful
clone.test=&Test
clone.testing=Testing repository {0}
clone.title=Clone Repository
clone.url.is.not.directory.error=Repository URL is not a directory.
cloning.repository=Cloning source repository {0}
command.cancelled=The command was cancelled.
commit.action.name=Commit
commit.author.tooltip=<html>Specify a commit author here if it is different from committer. The author should be in the format: Author Name &lt;author@ema.il&gt;</html>
commit.author=&Author:
commit.partial.merge.message=<html>The following files are not included in commit.<ul>{0}</ul>Perform commit with all files included?</html>
commit.partial.merge.title=Partial Merge Commit
commit.push.changes.tooltip=When this option is enabled, changes are pushed to the server after commit.
commit.push.changes=&Push Changes
common.current.branch.tooltip=The currently checked out branch.
common.current.branch=Current Branch:
common.git.root.tooltip=Select git vcs root
common.git.root=Git &Root:
common.no.active.branch=<no active branch>
computing.annotation=Computing annotation for {0}
current.branch.action.name=CurrentBranch
current.branch.change.tracked=Change Tracked Branch
current.branch.message=Checked out branch: {0}
current.branch.title=Current Branch
current.branch.tracked.branch.none=<none>
current.branch.tracked.branch.tooltip=Select the branch to track
current.branch.tracked.branch=&Branch:
current.branch.tracked.remote.none=<none>
current.branch.tracked.remote.this=<this repository>
current.branch.tracked.repository.tooltip=Select repository to track
current.branch.tracked.repository=Re&pository:
current.branch.tracked.title=Tracked Branch
debug.git.exec=DEBUG: work-dir: [{0}] exec: [{1}]
delete.action.name=Delete
diff.find.error=Finding revision for diff: {0}
error.dialog.title=Error
error.list.title={0} Error:
error.occurred.during=Error occurred during ''{0}''
fetch.action.name=Fetch
fetch.button=Fetch
fetch.force.references.update.tooltip=Forces update of branch references for which update is not forced in refrence mapping.
fetch.force.references.update=Force references &update
fetch.remote.label=Re&mote:
fetch.remote.tooltip=Remote name or url for fetch
fetch.tags.label=Fetch &tags:
fetch.tags.policy.all=All
fetch.tags.policy.for.fetched.commits=For fetched commits
fetch.tags.policy.none=None
fetch.tags.tooltip=<html>Select fetched commits policy<ul><li><i>For fetched commits</i> means tags associated with commits on fetched branches are fetched.</li><li><i>All</i> means that all tags and reference commits are fetched</li><li><i>None</i> means that no tags are fetched.</li></ul></html>
fetch.title=Git Fetch
fetching.tags.title=Updating tags from {0}
fetching.title=Fetching from {0}
find.git.description=Select path to git executable
find.git.error.title=Error Running git
find.git.success.title=Git Executed Successfully
find.git.title=Git Configuration
find.git.unsupported.message=<html><tt>{0}</tt><br>This version is unsupported, and some plugin functionality could fail to work.<br>The minimal supported version is <em>{1}</em>.</html>
fix.roots.button=Accept
fix.roots.list.tooltip=The suggested list of Git VCS roots, new roots are marked as bold, removed roots are marked as overstriked.
fix.roots.message=The following Git vcs roots will be used instead of the current Git VCS roots.
fix.roots.title=Fix Git VCS Roots
fix.roots.valid.message=The invalid Git roots have been fixed already.
fix.roots.valid.title=All Git Roots Are Valid
getting.history=Getting history for {0}
git.default.commit.message=\n# Brief commit description here\n\n# Full commit description here (comment lines starting with '#' will not be included)\n\n
git.error.exit=The git process exited with the code {0}
git.running=<html>Running: {0}</html>
git.vcs.config.path.label=Path to &git executable:
git.vcs.config.ssh.mode.idea=IDEA ssh
git.vcs.config.ssh.mode.native=Native
git.vcs.config.ssh.mode.tooltip=<html>Specify which version of SSH to be used with git.<ul><li><b>Native</b> means that the native ssh will be used.</li><li><b>IDEA SSH</b> means that the implementation provided by the IDEA will be used.</li></ul>The native implementation might cause hangups on some platforms. In native case, you also might need to configure <em>ssh-askpass</em> for your platform to recieve GUI promopts for passwords.</html>
git.vcs.config.ssh.mode=&SSH executable:
git.vcs.config.test.label=Test
git.vcs.config.test=&Test
index.file.error=Updating file in the index failed
init.add.root.message=Do you want to add this directory as vcs root?
init.add.root.title=Git Init
init.destination.directory.description=Select directory where the new Git repository will be created.
init.destination.directory.title=Select directory for git init
init.error.already.under.git=The selected directory {0} is already under git. The submodules are not yet supported.
init.error.title=git init Error
merge.action.name=Merge
merge.add.log.information.tooltip=Add log information to the commit message (\"--log\" option)
merge.add.log.information=Add &log information
merge.branch.button=Merge
merge.branch.message=Select branch to merge into this one ({0})
merge.branch.title=Merge Branches
merge.branches.tooltip=<html>The chooser for braches. Select one or more braches to merge (already merged branches are not shown)</html>.
merge.branches=&Branches to merge:
merge.commit.message.tooltip=The commit message to use in case if merge results in commit (\"-m\" option)
merge.commit.message=Commit &Message
merge.default.strategy=<default>
merge.is.not.needed=Merge is not needed for the file {0}
merge.load.files=Loading files for merge
merge.no.commit.tooltip=Force no commit for merge (the \"--no-commit\" option)
merge.no.commit=No &commit
merge.no.fast.forward.tooltip=Disable fast forward (\"--no-ff\" option)
merge.no.fast.forward=No &fast forward
merge.retrieving.branches=Retrieving unmerged branches
merge.squash.commit=S&quash commit
merge.squash.tooltip=Squash all changes into the single commit (\"--squash\" option)
merge.strategy.tooltip=The merge strategy to use (\"-s\" option)
merge.strategy=&Strategy:
merge.tool.action.name=MergeTool
merge.tool.column.status.deleted=Deleted
merge.tool.column.status.modified=Modified
merge.tool.column.theirs.status=Theirs
merge.tool.column.yours.status=Yours
merging.branch=Merging branch {0}
merging.title=Merging changes to {0}
paths.affected.title=Paths affected in commit {0}
pull.action.name=Pull
pull.button=Pull
pull.force.reference.update=Force reference &update
pull.get.branches.tooltip=Get branch names from remote repository. Otherwise a locally cached information is used.
pull.get.branches=&Get Branches
pull.getting.remote.branches=Getting remote branches
pull.remote.tooltip=Registered remote name or URL.
pull.remote=Re&mote:
pull.retrieving.remotes=Retrieving remotes
pull.title=Pull changes
pull.url.message=Enter remote repository URL to pull/merge (empty for default):
pull.url.title=Pull URL
pulling.title=Pulling changes from {0}
push.action.name=Push
push.branches.tooltip=Select branches to push
push.branches=&Branches:
push.button=Push
push.force.update.tooltip=If selected remote ref is updated even if they are is not an ancestor of the local ref.
push.force.update=&Force update
push.policy.all=All
push.policy.default=Default
push.policy.mirror=Mirror
push.policy.selected=Selected branches
push.policy.tooltip=<html>Select push policy:<ul><li><em>Default</em> - the push is done according to the configuration of the remote.</li><li><em>Selected branches</em> - selected branches are pushed.</li><li><em>All</em> - all references under refs/heads are pushed.</li><li><em>Mirror</em> - all references under refs/ are pushed including tags and remotes.</li></ul></html>
push.policy=&Push:
push.remote.tooltip=Specify remote repository URL or remote name where to push changes.
push.remote=Re&mote:
push.show.tags.tooltip=If selected, the tags are shown in branch chooser as well.
push.show.tags=Show ta&gs
push.tags.tooltip=All tag refereneces are pushed in addition to references specified in references section.
push.tags=Push &tags
push.title=Push Changes
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.button=Rebase
rebase.continue.action.name=Continue Rebasing
rebase.editor.action.column=Action
rebase.editor.button=Start Rebasing
rebase.editor.comment.column=Comment
rebase.editor.commit.column=Commit
rebase.editor.invalid.entryset=No commits found to rebase
rebase.editor.invalid.squash=The first non-skip commint could not be marked as squashed since squash merges commit with the previous commit.
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.result.amend.title=Rebase Suspended
rebase.result.amend=Stopped for amending commit while rebasing ({0}/{1}).\nAmmed commit and continue the rebase process.
rebase.result.cancelled.title=Rebase Cancelled
rebase.result.cancelled=The rebase process was cancelled.
rebase.result.conflict.title=Rebase Suspended
rebase.result.conflict=Stopped rebasing because of conflict ({0}/{1}).\nResolve conflicts and continue the rebase process.
rebase.result.error.title=Rebase Error
rebase.result.error=Stopped rebasing because of error while rebasing ({0}/{1}).\nCheck vcs console for details.
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.unstructured.editor.button=Resume Rebasing
rebase.unstructured.editor.git.root=Git Root:
rebase.unstructured.editor.message=Git rebase operation requested additional &information through the editor:
rebase.unstructured.editor.title=Addtional Rebase Input
rebase.unstructured.editor.tooltip=Edit this text according to instructions provided inline
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.add.all.tags=Add All Ta&gs
refspec.add.ref.tooltip=Add branch or tag by name
refspec.add.ref=&Add...
refspec.branch.prefix.tooltip=Specify default branch prefix for the mapping.
refspec.branch.prefix=Remote &Name:
refspec.column.force=Force
refspec.column.local=Local
refspec.column.remote=Remote
refspec.default.tooltip=Restore default reference mapping
refspec.default=&Default
refspec.remove.tooltip=Delete refspec entry
refspec.remove=Remo&ve
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.
reset.action.name=Reset Head ...
reset.button=Reset
reset.commit.invalid=The specified commit expression did not pass validation.
reset.commit.label=To &Commit:
reset.commit.tooltip=The commit that will become the current HEAD\n as result of reset operation.
reset.title=Reset Head
reset.type.hard=Hard
reset.type.mixed=Mixed
reset.type.soft=Soft
reset.type.tooltip=<html>The reset type (see also <code>git reset</code> man page):<ul><li><b>Mixed</b> resets index but not working tree</li><li><b>Soft</b> leaves index and working tree, just moves head pointer</li><li><b>Hard</b> resets index and working tree.<em>Changes in the working tree will be lost</em></li></ul></html>
reset.type=Reset &Type:
reset.validate.tooltip=Validate the commit pointer and check the content of referenced commit.
reset.validate=&Validate
resetting.title=Resetting HEAD...
revert.action.name=Revert
revision.graph=RevisionGraph
root.tracker.message=Some configured Git VCS roots are not under Git or have Git repositories in subdirectories without configured VCS root.
select.branch.to.checkout=Select branch to checkout
show.all.paths.affected.action.name=Show All Affected Paths
ssh.ask.passphrase.title=SSH Key Passphrase
ssh.askPassphrase.message=Please enter passphrase for the private key {0} (the user name is {1})
ssh.changed.host.key=<html>The server host key for the host {0}:{1} has changed to {2} (type {3}).\nDo you want to accept the changed key?</html>
ssh.confirm.key.titile=Confirm SSH Server Key
ssh.error.title=Authentication error
ssh.keyboard.interactive.title=SSH Keyboard Interactive: {0}
ssh.keyboard.interactive.username=Username:
ssh.new.host.key=<html>Connecting to a new host {0}:{1} that has the key {2} (type {3}).\nDo you want to add this host to known hosts database?</html>
ssh.password.message=Please enter password for user {0}
ssh.password.title=SSH Password Login
sshmain.failed.to.verify.key=Failed to verify key: {0}
sshmain.forwarding.failed=Forwarding {0} failed: {1}
sshmain.invald.host.key=Invald host key {0} {1}
sshmain.invalid.amount.of.arguments=Invalid amount of arguments: {0}
sshmain.invalidpassphrase=Invalid passphrase for the key {0}
sshmain.keyboard.interactive.failed=Keyboard interactive authentication failed.
sshmain.password.failed=Invalid user or password.
sshmain.pk.authenitication.failed=Authentication using key {0} failed.
sshmain.too.mush.passphrase.guesses=Invalid passphrase for the key {0}({1} attempts)
stash.action.name=Stash
stash.button=Create Stash
stash.keep.index.tooltip=If this checkbox is selected, indexed changes are kept in the index.
stash.keep.index=Keep &index
stash.message.tooltip=Enter stash message here.
stash.message=&Message:
stash.title=Stash
stashing.title=Stashing changes...
tag.action.name=Tag
tag.button=Create Tag
tag.commit.label=&Commit:
tag.commit.tooltip=Enter name of commit or object to tag or leave blank to use HEAD.
tag.error.creating.message.file.message=Unable to create message file: {0}
tag.error.creating.message.file.title=Error creating message file
tag.error.invalid.commit=The commit or object name is invalid.
tag.error.tag.exists=The tag with the same name exists.
tag.force.tooltip=Force creation of the text even if tag with such name already exists.
tag.force=&Force
tag.getting.existing.tags=Getting existing tags...
tag.message.label=&Message:
tag.message.tooltip=If the message is not empty, an annotated tag is created.
tag.message=Specify tag name:
tag.name.label=Tag &Name:
tag.name.tooltip=Enter the new tag name here.
tag.nonvcs.error.message=ERROR: Files not tagged, not all are under VCS root!
tag.nonvcs.error.title=Tag Result
tag.title=Tag
tag.validate.tooltip=Click this button to the validate commit to be tagged.
tag.validate=&Validate
tagging.title=Tagging files...
unindexed.files.changlelist.name=Unindexed Files
unstash.action.name=UnStash
unstash.branch.label\:=As new &branch:
unstash.branch.tooltip=If non-empty name is entered, the stash is checked out as a new branch.
unstash.button.apply=Apply Stash
unstash.button.branch=Branch
unstash.button.pop=Pop Stash
unstash.clear.tooltip=Delete all stashes in the repository.
unstash.clear=&Clear
unstash.clearing.stashes=Clearing stashes...
unstash.drop.tooltip=Delete selected stash
unstash.drop=&Drop
unstash.dropping.stash=Dropping stash {0}...
unstash.error.branch.exists=The specified branch already exists
unstash.error.invalid.branch.name=Invalid branch name
unstash.pop.stash.tooltip=If selected the stash is dropped after it is applied.
unstash.pop.stash=&Pop stash
unstash.reinstate.index.tooltip=Attempt to reinstate index as well as working tree changes.
unstash.reinstate.index=Reinstate &index
unstash.stashes.item=<html><b><tt>{0}</tt></b>:<i>{1}</i>:{2}</html>
unstash.stashes.tooltip=Select a stash to operate for.
unstash.stashes=&Stashes:
unstash.title=UnStash Changes
unstash.view.tooltip=View selected stash
unstash.view=&View
unstashing.title=UnStashing changes...
update.options.display.name=Git Update Settings
update.options.no.commit=No &Commit
update.options.stash.tooltip=If selected, the current changes will be stashed before update, and than restored after update.
update.options.stash=&Stash changes before update
update.options.type.default=Branch Default
update.options.type.merge=Force Merge
update.options.type.rebase=Force Rebase
update.options.type.tooltip=Force update type (merge or rebase) or use branch default configuration
update.options.type=&Type:
update.rebase.no.change.cancel=Cancel Update
update.rebase.no.change.retry=Retry Continue
update.rebase.no.change.skip=Skip Commit
update.rebase.no.change.title=No Changes Staged
update.rebase.no.change=<html>No changes detected <tt>{0}</tt>. <ul><li>Skip Commit - skips current commit in the rebase process</li><li>Retry Continue - do it after you add changes to commit manually</li><li>Or cancel cancels update process for this root.</li></ul></html>
update.rebase.unmerged.title=Unresolved Rebase Conflicts
update.rebase.unmerged=<html><b>{0}</b> file(s) are not yet merged. Repeat merge operation (no cancels update for root <tt>{1}</tt>?</html>
util.remote.renderer.default=<html><b>{0}</b>(<i>{1}</i>)</html>
util.remote.renderer.none=<html><i>None</i></html>
util.remote.renderer.normal=<html><b>{0}</b>(<i>{1}</i>)</html>
util.remote.renderer.self=<html><i>Current repository</i></html>
vcs.unable.to.run.git=Unable to run git: {0} ({1})
vcs.unsupported.version=Unsupported version of git configured: {0}. The minimal supported version is {1}
vfs.listener.add.single.prompt=Do you want to add the following file to Git?\n{0}\n\nIf you say NO, you can still add it later manually.
vfs.listener.add.single.title=Add file to Git
vfs.listener.add.title=Add files to Git
vfs.listener.delete.single.prompt=Do you want to delete the following file from Git?\n{0}\n\nIf you say NO, you can still delete it later manually.
vfs.listener.delete.single.title=Delete file from Git
vfs.listener.delete.title=Delete files from Git
@@ -0,0 +1,45 @@
package git4idea.update;
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.NotNull;
/**
* The class contains utilities for creating and removing stashes.
*/
public class GitStashUtils {
private GitStashUtils() {
}
/**
* Create stash for later use
*
* @param project the project to use
* @param root the root
* @param message the message for the stash
* @return true if the stash was created, false otherwise
*/
public static boolean saveStash(@NotNull Project project, @NotNull VirtualFile root, final String message) throws VcsException {
GitSimpleHandler handler = new GitSimpleHandler(project, root, GitHandler.STASH);
handler.setNoSSH(true);
handler.addParameters("save", message);
String output = handler.run();
return !output.startsWith("No local changes to save");
}
/**
* Create stash for later use
*
* @param project the project to use
* @param root the root
*/
public static void popLastStash(@NotNull Project project, @NotNull VirtualFile root) throws VcsException {
GitSimpleHandler handler = new GitSimpleHandler(project, root, GitHandler.STASH);
handler.setNoSSH(true);
handler.addParameters("pop");
handler.run();
}
}
@@ -0,0 +1,85 @@
package git4idea.update;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import git4idea.config.GitVcsSettings;
import git4idea.i18n.GitBundle;
import org.jetbrains.annotations.Nls;
import javax.swing.*;
/**
* Configurable for the update session
*/
public class GitUpdateConfigurable implements Configurable {
/** The vcs settings for the configurable */
private final GitVcsSettings mySettings;
/** The options panel */
private GitUpdateOptionsPanel myPanel;
/**
* The constructor
* @param settings the settings object
*/
public GitUpdateConfigurable(GitVcsSettings settings) {
mySettings = settings;
}
/**
* {@inheritDoc}
*/
@Nls
public String getDisplayName() {
return GitBundle.getString("update.options.display.name");
}
/**
* {@inheritDoc}
*/
public Icon getIcon() {
return null;
}
/**
* {@inheritDoc}
*/
public String getHelpTopic() {
return null;
}
/**
* {@inheritDoc}
*/
public JComponent createComponent() {
myPanel = new GitUpdateOptionsPanel();
return myPanel.getPanel(); //To change body of implemented methods use File | Settings | File Templates.
}
/**
* {@inheritDoc}
*/
public boolean isModified() {
return myPanel.isModified(mySettings);
}
/**
* {@inheritDoc}
*/
public void apply() throws ConfigurationException {
myPanel.applyTo(mySettings);
}
/**
* {@inheritDoc}
*/
public void reset() {
myPanel.updateFrom(mySettings);
}
/**
* {@inheritDoc}
*/
public void disposeUIResources() {
myPanel = null;
}
}
@@ -19,7 +19,10 @@ import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vcs.AbstractVcsHelper;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.update.SequentialUpdatesContext;
@@ -27,13 +30,15 @@ import com.intellij.openapi.vcs.update.UpdateEnvironment;
import com.intellij.openapi.vcs.update.UpdateSession;
import com.intellij.openapi.vcs.update.UpdatedFiles;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ui.UIUtil;
import git4idea.GitBranch;
import git4idea.GitRevisionNumber;
import git4idea.GitUtil;
import git4idea.commands.GitHandler;
import git4idea.commands.GitHandlerUtil;
import git4idea.commands.GitLineHandler;
import git4idea.config.GitConfigUtil;
import git4idea.GitVcs;
import git4idea.changes.GitChangeUtils;
import git4idea.commands.*;
import git4idea.config.GitVcsSettings;
import git4idea.i18n.GitBundle;
import git4idea.merge.MergeChangeCollector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -42,24 +47,35 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Git update environment implementation. The environment does just a simple
* {@code git pull -v} for each content root.
*/
public class GitUpdateEnvironment implements UpdateEnvironment {
/**
* The vcs instance
*/
private GitVcs myVcs;
/**
* The context project
*/
private final Project myProject;
/**
* The project settings
*/
private final GitVcsSettings mySettings;
/**
* A constructor from settings
*
* @param project a project
*/
public GitUpdateEnvironment(@NotNull Project project) {
public GitUpdateEnvironment(@NotNull Project project, @NotNull GitVcs vcs, GitVcsSettings settings) {
myVcs = vcs;
myProject = project;
mySettings = settings;
}
/**
@@ -79,33 +95,131 @@ public class GitUpdateEnvironment implements UpdateEnvironment {
@NotNull Ref<SequentialUpdatesContext> sequentialUpdatesContextRef)
throws ProcessCanceledException {
List<VcsException> exceptions = new ArrayList<VcsException>();
for (VirtualFile root : GitUtil.gitRoots(Arrays.asList(filePaths))) {
for (final VirtualFile root : GitUtil.gitRoots(Arrays.asList(filePaths))) {
try {
// check if there is a remote for the branch
final GitBranch branch = GitBranch.current(myProject, root);
if (branch == null) {
continue;
}
final String value = GitConfigUtil.getValue(myProject, root, "branch." + branch.getName() + ".remote");
final String value = branch.getTrackedRemoteName(myProject, root);
if (value == null || value.length() == 0) {
continue;
}
// remember the current position
GitRevisionNumber before = GitRevisionNumber.resolve(myProject, root, "HEAD");
// do pull
GitLineHandler h = new GitLineHandler(myProject, root, GitHandler.PULL);
// ignore merge failure for the pull
h.ignoreErrorCode(1);
h.addParameters("--no-stat");
h.addParameters("-v");
boolean stashCreated =
mySettings.UPDATE_STASH && GitStashUtils.saveStash(myProject, root, "Uncommitted changes before update operation");
try {
GitHandlerUtil.doSynchronouslyWithExceptions(h, progressIndicator);
// remember the current position
GitRevisionNumber before = GitRevisionNumber.resolve(myProject, root, "HEAD");
// do pull
GitLineHandler h = new GitLineHandler(myProject, root, GitHandler.PULL);
// ignore merge failure for the pull
h.ignoreErrorCode(1);
switch (mySettings.UPDATE_TYPE) {
case REBASE:
h.addParameters("--rebase");
break;
case MERGE:
h.addParameters("--no-rebase");
break;
case BRANCH_DEFAULT:
// use default for the branch
break;
default:
assert false : "Unknown update type: " + mySettings.UPDATE_TYPE;
}
h.addParameters("--no-stat");
h.addParameters("-v");
final Ref<Boolean> cancelled = new Ref<Boolean>(false);
try {
RebaseConflictDetector rebaseConflictDetector = new RebaseConflictDetector();
h.addLineListener(rebaseConflictDetector);
try {
GitHandlerUtil.doSynchronouslyWithExceptions(h, progressIndicator);
}
finally {
if (!rebaseConflictDetector.isRebaseConflict()) {
exceptions.addAll(h.errors());
}
}
do {
final Ref<Throwable> ex = new Ref<Throwable>();
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
public void run() {
try {
List<VirtualFile> affectedFiles = GitChangeUtils.unmergedFiles(myProject, root);
while (affectedFiles.size() != 0) {
AbstractVcsHelper.getInstance(myProject).showMergeDialog(affectedFiles, myVcs.getMergeProvider());
affectedFiles = GitChangeUtils.unmergedFiles(myProject, root);
if (affectedFiles.size() != 0) {
int result = Messages.showYesNoDialog(myProject, GitBundle.message("update.rebase.unmerged", affectedFiles.size(),
root.getPresentableUrl()),
GitBundle.getString("update.rebase.unmerged.title"), Messages.getErrorIcon());
if (result != 0) {
cancelled.set(true);
return;
}
}
}
}
catch (Throwable t) {
ex.set(t);
}
}
});
//noinspection ThrowableResultOfMethodCallIgnored
if (ex.get() != null) {
//noinspection ThrowableResultOfMethodCallIgnored
throw GitUtil.rethrowVcsException(ex.get());
}
if (cancelled.get()) {
break;
}
doRebase(progressIndicator, root, rebaseConflictDetector, "--continue");
final Ref<Integer> result = new Ref<Integer>();
noChangeLoop:
while (rebaseConflictDetector.isNoChange()) {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
public void run() {
int rc = Messages.showDialog(myProject, GitBundle.message("update.rebase.no.change", root.getPresentableUrl()),
GitBundle.getString("update.rebase.no.change.title"),
new String[]{GitBundle.getString("update.rebase.no.change.skip"),
GitBundle.getString("update.rebase.no.change.retry"),
GitBundle.getString("update.rebase.no.change.cancel")}, 0, Messages.getErrorIcon());
result.set(rc);
}
});
switch (result.get()) {
case 0:
doRebase(progressIndicator, root, rebaseConflictDetector, "--skip");
continue noChangeLoop;
case 1:
continue noChangeLoop;
case 2:
cancelled.set(true);
break noChangeLoop;
}
}
}
while (rebaseConflictDetector.isRebaseConflict() && !cancelled.get());
if (cancelled.get()) {
//noinspection ThrowableInstanceNeverThrown
exceptions.add(new VcsException("The update process was cancelled for " + root.getPresentableUrl()));
doRebase(progressIndicator, root, rebaseConflictDetector, "--abort");
}
}
finally {
if (!cancelled.get()) {
// find out what have changed
MergeChangeCollector collector = new MergeChangeCollector(myProject, root, before, updatedFiles);
collector.collect(exceptions);
}
}
}
finally {
exceptions.addAll(h.errors());
// find out what have changed
MergeChangeCollector collector = new MergeChangeCollector(myProject, root, before, updatedFiles);
collector.collect(exceptions);
if (stashCreated) {
GitStashUtils.popLastStash(myProject, root);
}
}
}
catch (VcsException ex) {
@@ -115,6 +229,26 @@ public class GitUpdateEnvironment implements UpdateEnvironment {
return new GitUpdateSession(exceptions);
}
/**
* Do rebase operation as part of update operator
*
* @param progressIndicator the progress indicator for the update
* @param root the vcs root
* @param rebaseConflictDetector the detector of conflicts in rebase operation
* @param action the rebase action to execute
*/
private void doRebase(ProgressIndicator progressIndicator,
VirtualFile root,
RebaseConflictDetector rebaseConflictDetector,
final String action) {
GitLineHandler rh = new GitLineHandler(myProject, root, GitHandler.REBASE);
// ignore failure for abort
rh.ignoreErrorCode(1);
rh.addParameters(action);
rebaseConflictDetector.reset();
rh.addLineListener(rebaseConflictDetector);
GitHandlerUtil.doSynchronouslyWithExceptions(rh, progressIndicator);
}
/**
* {@inheritDoc}
@@ -133,6 +267,63 @@ public class GitUpdateEnvironment implements UpdateEnvironment {
*/
@Nullable
public Configurable createConfigurable(Collection<FilePath> files) {
return null;
return new GitUpdateConfigurable(mySettings);
}
/**
* The detector of conflict conditions for rebase operation
*/
static class RebaseConflictDetector extends GitLineHandlerAdapter {
/**
* The line that indicates that there is a rebase conflict.
*/
private final static String REBASE_CONFLICT_INDICATOR = "When you have resolved this problem run \"git rebase --continue\".";
/**
* The line that indicates "no change" condition.
*/
private static final String REBASE_NO_CHANGE_INDICATOR = "No changes - did you forget to use 'git add'?";
/**
* if true, the rebase conflict happened
*/
AtomicBoolean rebaseConflict = new AtomicBoolean(false);
/**
* if true, the no changes were detected in the rebase operations
*/
AtomicBoolean noChange = new AtomicBoolean(false);
/**
* Reset detector before new operation
*/
public void reset() {
rebaseConflict.set(false);
noChange.set(false);
}
/**
* @return true if "no change" condition was detected during the operation
*/
public boolean isNoChange() {
return noChange.get();
}
/**
* @return true if conflict during rebase was detected
*/
public boolean isRebaseConflict() {
return rebaseConflict.get();
}
/**
* {@inheritDoc}
*/
@Override
public void onLineAvailable(String line, Key outputType) {
if (line.startsWith(REBASE_CONFLICT_INDICATOR)) {
rebaseConflict.set(true);
}
if (line.startsWith(REBASE_NO_CHANGE_INDICATOR)) {
noChange.set(true);
}
}
}
}
@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="git4idea.update.GitUpdateOptionsPanel">
<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="332" height="82"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="1d8b2" 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="b73c5"/>
<text resource-bundle="git4idea/i18n/GitBundle" key="update.options.type"/>
</properties>
</component>
<component id="a20d7" class="javax.swing.JCheckBox" binding="myStashChangesCheckBox">
<constraints>
<grid row="1" 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="update.options.stash"/>
<toolTipText resource-bundle="git4idea/i18n/GitBundle" key="update.options.stash.tooltip"/>
</properties>
</component>
<grid id="f5eba" layout-manager="GridLayoutManager" row-count="1" 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="0" 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>
<hspacer id="c2e96">
<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="b73c5" class="javax.swing.JComboBox" binding="myTypeComboBox" default-binding="true">
<constraints>
<grid row="0" column="0" 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="update.options.type.tooltip"/>
</properties>
</component>
</children>
</grid>
<vspacer id="d3b1e">
<constraints>
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
</children>
</grid>
</form>
@@ -0,0 +1,113 @@
package git4idea.update;
import git4idea.config.GitVcsSettings;
import git4idea.config.GitVcsSettings.UpdateType;
import git4idea.i18n.GitBundle;
import javax.swing.*;
/**
* Update options
*/
public class GitUpdateOptionsPanel {
/**
* The merge policy
*/
private static final String MERGE = GitBundle.getString("update.options.type.merge");
/**
* The rebase policy
*/
private static final String REBASE = GitBundle.getString("update.options.type.rebase");
/**
* The rebase policy
*/
private static final String DEFAULT = GitBundle.getString("update.options.type.default");
/**
* The type combobox
*/
private JComboBox myTypeComboBox;
/**
* The stash changes checkbox
*/
private JCheckBox myStashChangesCheckBox;
/**
* The root panel
*/
private JPanel myPanel;
/**
* A constructor
*/
public GitUpdateOptionsPanel() {
myTypeComboBox.addItem(DEFAULT);
myTypeComboBox.addItem(REBASE);
myTypeComboBox.addItem(MERGE);
}
/**
* @return the panel component
*/
public JComponent getPanel() {
return myPanel;
}
/**
* Check if the panel is modified relatively to settings
* @param settings the settings to compare to
* @return true if the UI modified the settings
*/
public boolean isModified(GitVcsSettings settings) {
UpdateType type = getUpdateType();
return type != settings.UPDATE_TYPE || myStashChangesCheckBox.isSelected() != settings.UPDATE_STASH;
}
/**
* @return get the currently selected update type
*/
private UpdateType getUpdateType() {
UpdateType type = null;
String typeVal = (String)myTypeComboBox.getSelectedItem();
if (REBASE.equals(typeVal)) {
type = UpdateType.REBASE;
}
else if (MERGE.equals(typeVal)) {
type = UpdateType.MERGE;
} else if(DEFAULT.equals(typeVal)) {
type = UpdateType.BRANCH_DEFAULT;
}
assert type != null;
return type;
}
/**
* Save configuration to settings object
* @param settings the settings to save to
*/
public void applyTo(GitVcsSettings settings) {
settings.UPDATE_TYPE = getUpdateType();
settings.UPDATE_STASH = myStashChangesCheckBox.isSelected();
}
/**
* Update panel according to settings
* @param settings the settings to use
*/
public void updateFrom(GitVcsSettings settings) {
myStashChangesCheckBox.setSelected(settings.UPDATE_STASH);
String value = null;
switch(settings.UPDATE_TYPE) {
case REBASE:
value = REBASE;
break;
case MERGE:
value = MERGE;
break;
case BRANCH_DEFAULT:
value = DEFAULT;
break;
default:
assert false : "Unknown value of update type: "+settings.UPDATE_TYPE;
}
myTypeComboBox.setSelectedItem(value);
}
}