@Nullable public static Pair<AbstractHash, AbstractHash> getStashTop( @NotNull Project project, @NotNull VirtualFile root) throws VcsException { GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.STASH.readLockingCommand()); GitLogParser parser = new GitLogParser(project, SHORT_HASH, SHORT_PARENTS); h.setSilent(true); h.setNoSSH(true); h.addParameters("list"); h.addParameters("-n1"); h.addParameters(parser.getPretty()); String out; h.setCharset(Charset.forName(GitConfigUtil.getLogEncoding(project, root))); out = h.run(); final List<GitLogRecord> gitLogRecords = parser.parse(out); for (GitLogRecord gitLogRecord : gitLogRecords) { ProgressManager.checkCanceled(); GitSimpleHandler h1 = new GitSimpleHandler(project, root, GitCommand.LOG); GitLogParser parser1 = new GitLogParser(project, SHORT_HASH, SHORT_PARENTS, SUBJECT); h1.setSilent(true); h1.setNoSSH(true); h1.addParameters("-n1"); h1.addParameters(parser1.getPretty()); // h1.endOptions(); h1.addParameters(gitLogRecord.getShortHash()); String out1; out1 = h1.run(); final List<GitLogRecord> gitLogRecords1 = parser1.parse(out1); assert gitLogRecords1.size() == 1; final GitLogRecord logRecord = gitLogRecords1.get(0); final String[] parentsShortHashes = logRecord.getParentsShortHashes(); String indexCommit = null; // heuristics if (parentsShortHashes.length == 2) { if (logRecord.getSubject().contains(parentsShortHashes[0])) { indexCommit = parentsShortHashes[1]; } if (logRecord.getSubject().contains(parentsShortHashes[1])) { indexCommit = parentsShortHashes[0]; } } return new Pair<AbstractHash, AbstractHash>( AbstractHash.create(gitLogRecord.getShortHash()), indexCommit == null ? null : AbstractHash.create(indexCommit)); } return null; }
/** * Get current revision for the file under git * * @param project a project * @param filePath a file path * @return a revision number or null if the file is unversioned or new * @throws VcsException if there is problem with running git */ @Nullable public static ItemLatestState getLastRevision(final Project project, FilePath filePath) throws VcsException { VirtualFile root = GitUtil.getGitRoot(filePath); GitBranch c = GitBranch.current(project, root); GitBranch t = c == null ? null : c.tracked(project, root); if (t == null) { return new ItemLatestState(getCurrentRevision(project, filePath, null), true, false); } filePath = getLastCommitName(project, filePath); GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.LOG); GitLogParser parser = new GitLogParser(project, GitLogParser.NameStatus.STATUS, HASH, COMMIT_TIME, SHORT_PARENTS); h.setNoSSH(true); h.setSilent(true); h.addParameters("-n1", parser.getPretty(), "--name-status", t.getFullName()); h.endOptions(); h.addRelativePaths(filePath); String result = h.run(); if (result.length() == 0) { return null; } GitLogRecord record = parser.parseOneRecord(result); if (record == null) { return null; } final List<Change> changes = record.parseChanges(project, root); boolean exists = !FileStatus.DELETED.equals(changes.get(0).getFileStatus()); record.setUsedHandler(h); return new ItemLatestState( new GitRevisionNumber(record.getHash(), record.getDate()), exists, false); }
@Nullable public static VcsRevisionNumber getCurrentRevision( final Project project, FilePath filePath, @Nullable String branch, final boolean shortHash) throws VcsException { filePath = getLastCommitName(project, filePath); GitSimpleHandler h = new GitSimpleHandler(project, GitUtil.getGitRoot(filePath), GitCommand.LOG); GitLogParser parser = shortHash ? new GitLogParser(project, SHORT_HASH, COMMIT_TIME) : new GitLogParser(project, HASH, COMMIT_TIME); h.setNoSSH(true); h.setSilent(true); h.addParameters("-n1", parser.getPretty()); if (branch != null && !branch.isEmpty()) { h.addParameters(branch); } else { h.addParameters("--all"); } h.endOptions(); h.addRelativePaths(filePath); String result = h.run(); if (result.length() == 0) { return null; } final GitLogRecord record = parser.parseOneRecord(result); if (record == null) { return null; } record.setUsedHandler(h); return shortHash ? new GitRevisionNumber(record.getShortHash(), record.getDate()) : new GitRevisionNumber(record.getHash(), record.getDate()); }
// relativePaths are guaranteed to fit into command line length limitations. @Override @NotNull public Collection<VirtualFile> untrackedFilesNoChunk( @NotNull Project project, @NotNull VirtualFile root, @Nullable List<String> relativePaths) throws VcsException { final Set<VirtualFile> untrackedFiles = new HashSet<VirtualFile>(); GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.LS_FILES); h.setNoSSH(true); h.setSilent(true); h.addParameters("--exclude-standard", "--others", "-z"); h.endOptions(); if (relativePaths != null) { h.addParameters(relativePaths); } final String output = h.run(); if (StringUtil.isEmptyOrSpaces(output)) { return untrackedFiles; } for (String relPath : output.split("\u0000")) { VirtualFile f = root.findFileByRelativePath(relPath); if (f == null) { // files was created on disk, but VirtualFile hasn't yet been created, // when the GitChangeProvider has already been requested about changes. LOG.info(String.format("VirtualFile for path [%s] is null", relPath)); } else { untrackedFiles.add(f); } } return untrackedFiles; }
/** * Resolve revision number for the specified revision * * @param project a project * @param vcsRoot a vcs root * @param rev a revision expression * @return a resolved revision number with correct time * @throws VcsException if there is a problem with running git */ public static GitRevisionNumber resolve(Project project, VirtualFile vcsRoot, @NonNls String rev) throws VcsException { GitSimpleHandler h = new GitSimpleHandler(project, vcsRoot, GitCommand.REV_LIST); h.setSilent(true); h.addParameters("--timestamp", "--max-count=1", rev); h.endOptions(); final String output = h.run(); return parseRevlistOutputAsRevisionNumber(h, output); }
protected boolean hasRemoteChanges(@NotNull String currentBranch, @NotNull String remoteBranch) throws VcsException { GitSimpleHandler handler = new GitSimpleHandler(myProject, myRoot, GitCommand.REV_LIST); handler.setSilent(true); handler.addParameters("-1"); handler.addParameters(currentBranch + ".." + remoteBranch); String output = handler.run(); return output != null && !output.isEmpty(); }
protected void add() throws ServerRuntimeException { try { GitSimpleHandler handler = new GitSimpleHandler(getProject(), myContentRoot, GitCommand.ADD); handler.setSilent(false); handler.addParameters("."); handler.run(); } catch (VcsException e) { throw new ServerRuntimeException(e); } }
/** * git diff --name-only [--cached] * * @return true if there is anything in the unstaged/staging area, false if the unstraed/staging * area is empty. * @param staged if true checks the staging area, if false checks unstaged files. * @param project * @param root */ public static boolean hasLocalChanges(boolean staged, Project project, VirtualFile root) throws VcsException { final GitSimpleHandler diff = new GitSimpleHandler(project, root, GitCommand.DIFF); diff.addParameters("--name-only"); if (staged) { diff.addParameters("--cached"); } diff.setStdoutSuppressed(true); diff.setStderrSuppressed(true); diff.setSilent(true); final String output = diff.run(); return !output.trim().isEmpty(); }
protected void commit() throws ServerRuntimeException { try { if (GitUtil.hasLocalChanges(true, getProject(), myContentRoot)) { GitSimpleHandler handler = new GitSimpleHandler(getProject(), myContentRoot, GitCommand.COMMIT); handler.setSilent(false); handler.addParameters("-a"); handler.addParameters("-m", "Deploy"); handler.endOptions(); handler.run(); } } catch (VcsException e) { throw new ServerRuntimeException(e); } }
protected void doGitRemote( String remoteName, CloudGitApplication application, String subCommand, String failMessage) throws ServerRuntimeException { try { final GitSimpleHandler handler = new GitSimpleHandler(myProject, myContentRoot, GitCommand.REMOTE); handler.setSilent(false); handler.addParameters(subCommand, remoteName, application.getGitUrl()); handler.run(); getRepository().update(); if (handler.getExitCode() != 0) { throw new ServerRuntimeException(failMessage); } } catch (VcsException e) { throw new ServerRuntimeException(e); } }
@Nullable public static GitRevisionNumber getMergeBase( final Project project, final VirtualFile root, @NotNull final String first, @NotNull final String second) throws VcsException { GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.MERGE_BASE); h.setNoSSH(true); h.setSilent(true); h.addParameters(first, second); String output = h.run().trim(); if (output.length() == 0) { return null; } else { return GitRevisionNumber.resolve(project, root, output); } }
@Nullable public static List<Pair<String, GitCommit>> loadStashStackAsCommits( @NotNull Project project, @NotNull VirtualFile root, SymbolicRefsI refs, final String... parameters) throws VcsException { GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.STASH.readLockingCommand()); GitLogParser parser = new GitLogParser( project, GitLogParser.NameStatus.STATUS, SHORT_HASH, HASH, COMMIT_TIME, AUTHOR_NAME, AUTHOR_TIME, AUTHOR_EMAIL, COMMITTER_NAME, COMMITTER_EMAIL, SHORT_PARENTS, REF_NAMES, SHORT_REF_LOG_SELECTOR, SUBJECT, BODY, RAW_BODY); h.setSilent(true); h.setNoSSH(true); h.addParameters("list"); h.addParameters(parameters); h.addParameters(parser.getPretty()); String out; h.setCharset(Charset.forName(GitConfigUtil.getLogEncoding(project, root))); out = h.run(); final List<GitLogRecord> gitLogRecords = parser.parse(out); final List<Pair<String, GitCommit>> result = new ArrayList<Pair<String, GitCommit>>(); for (GitLogRecord gitLogRecord : gitLogRecords) { ProgressManager.checkCanceled(); final GitCommit gitCommit = createCommit(project, refs, root, gitLogRecord); result.add(new Pair<String, GitCommit>(gitLogRecord.getShortenedRefLog(), gitCommit)); } return result; }
public static void getLocalCommittedChanges( final Project project, final VirtualFile root, final Consumer<GitSimpleHandler> parametersSpecifier, final Consumer<GitCommittedChangeList> consumer, boolean skipDiffsForMerge) throws VcsException { GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.LOG); h.setSilent(true); h.addParameters( "--pretty=format:%x04%x01" + GitChangeUtils.COMMITTED_CHANGELIST_FORMAT, "--name-status"); parametersSpecifier.consume(h); String output = h.run(); LOG.debug("getLocalCommittedChanges output: '" + output + "'"); StringScanner s = new StringScanner(output); final StringBuilder sb = new StringBuilder(); boolean firstStep = true; while (s.hasMoreData()) { final String line = s.line(); final boolean lineIsAStart = line.startsWith("\u0004\u0001"); if ((!firstStep) && lineIsAStart) { final StringScanner innerScanner = new StringScanner(sb.toString()); sb.setLength(0); consumer.consume( GitChangeUtils.parseChangeList( project, root, innerScanner, skipDiffsForMerge, h, false, false)); } sb.append(lineIsAStart ? line.substring(2) : line).append('\n'); firstStep = false; } if (sb.length() > 0) { final StringScanner innerScanner = new StringScanner(sb.toString()); sb.setLength(0); consumer.consume( GitChangeUtils.parseChangeList( project, root, innerScanner, skipDiffsForMerge, h, false, false)); } if (s.hasMoreData()) { throw new IllegalStateException("More input is avaialble: " + s.line()); } }
public static long getHeadTs(final Project project, FilePath filePath) throws VcsException { GitSimpleHandler h = new GitSimpleHandler(project, GitUtil.getGitRoot(filePath), GitCommand.LOG); GitLogParser parser = new GitLogParser(project, SHORT_HASH, COMMIT_TIME); h.setNoSSH(true); h.setSilent(true); h.addParameters("-n1", parser.getPretty()); h.addParameters("HEAD"); h.endOptions(); String result = h.run(); if (result.length() == 0) { return -1; } final GitLogRecord record = parser.parseOneRecord(result); if (record == null) { return -1; } record.setUsedHandler(h); return record.getDate().getTime(); }
@NotNull private static List<String> excludeIgnoredFiles( @NotNull Project project, @NotNull VirtualFile root, @NotNull List<String> paths) throws VcsException { GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.LS_FILES); handler.setNoSSH(true); handler.setSilent(true); handler.addParameters("--ignored", "--others", "--exclude-standard"); handler.endOptions(); handler.addParameters(paths); String output = handler.run(); List<String> nonIgnoredFiles = new ArrayList<String>(paths.size()); Set<String> ignoredPaths = new HashSet<String>(Arrays.asList(StringUtil.splitByLines(output))); for (String pathToCheck : paths) { if (!ignoredPaths.contains(pathToCheck)) { nonIgnoredFiles.add(pathToCheck); } } return nonIgnoredFiles; }
// TODO this is to be removed when tags will be supported by the GitRepositoryReader private Collection<? extends VcsRef> readTags(@NotNull VirtualFile root) throws VcsException { GitSimpleHandler tagHandler = new GitSimpleHandler(myProject, root, GitCommand.LOG); tagHandler.setSilent(true); tagHandler.addParameters( "--tags", "--no-walk", "--format=%H%d" + GitLogParser.RECORD_START_GIT, "--decorate=full"); String out = tagHandler.run(); Collection<VcsRef> refs = new ArrayList<VcsRef>(); try { for (String record : out.split(GitLogParser.RECORD_START)) { if (!StringUtil.isEmptyOrSpaces(record)) { refs.addAll(new RefParser(myVcsObjectsFactory).parseCommitRefs(record.trim(), root)); } } } catch (Exception e) { LOG.error( "Error during tags parsing", new Attachment("stack_trace.txt", ExceptionUtil.getThrowableText(e)), new Attachment("git_output.txt", out)); } return refs; }
/** * Scan working tree and detect locally modified files * * @param project the project to scan * @param root the root to scan * @param files the collection with files * @throws VcsException if there problem with running git or working tree is dirty in unsupported * way */ private static void scanFiles(Project project, VirtualFile root, List<String> files) throws VcsException { String rootPath = root.getPath(); GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.DIFF); h.addParameters("--name-status"); h.setNoSSH(true); h.setSilent(true); h.setStdoutSuppressed(true); StringScanner s = new StringScanner(h.run()); while (s.hasMoreData()) { if (s.isEol()) { s.line(); continue; } if (s.tryConsume("M\t")) { String path = rootPath + "/" + GitUtil.unescapePath(s.line()); files.add(path); } else { throw new VcsException("Working tree is dirty in unsupported way: " + s.line()); } } }
@Nullable public static VcsRevisionDescription getCurrentRevisionDescription( final Project project, FilePath filePath, @Nullable String branch) throws VcsException { filePath = getLastCommitName(project, filePath); GitSimpleHandler h = new GitSimpleHandler(project, GitUtil.getGitRoot(filePath), GitCommand.LOG); GitLogParser parser = new GitLogParser( project, HASH, COMMIT_TIME, AUTHOR_NAME, COMMITTER_NAME, SUBJECT, BODY, RAW_BODY); h.setNoSSH(true); h.setSilent(true); h.addParameters("-n1", parser.getPretty()); if (branch != null && !branch.isEmpty()) { h.addParameters(branch); } else { h.addParameters("--all"); } h.endOptions(); h.addRelativePaths(filePath); String result = h.run(); if (result.length() == 0) { return null; } final GitLogRecord record = parser.parseOneRecord(result); if (record == null) { return null; } record.setUsedHandler(h); final String author = Comparing.equal(record.getAuthorName(), record.getCommitterName()) ? record.getAuthorName() : record.getAuthorName() + " (" + record.getCommitterName() + ")"; return new VcsRevisionDescriptionImpl( new GitRevisionNumber(record.getHash(), record.getDate()), record.getDate(), author, record.getFullMessage()); }
/** * Preform a merge commit * * @param project a project * @param root a vcs root * @param added added files * @param removed removed files * @param messageFile a message file for commit * @param author an author * @param exceptions the list of exceptions to report * @param partialOperation * @return true if merge commit was successful */ private static boolean mergeCommit( final Project project, final VirtualFile root, final Set<FilePath> added, final Set<FilePath> removed, final File messageFile, final String author, List<VcsException> exceptions, @NotNull final PartialOperation partialOperation) { HashSet<FilePath> realAdded = new HashSet<FilePath>(); HashSet<FilePath> realRemoved = new HashSet<FilePath>(); // perform diff GitSimpleHandler diff = new GitSimpleHandler(project, root, GitCommand.DIFF); diff.setSilent(true); diff.setStdoutSuppressed(true); diff.addParameters("--diff-filter=ADMRUX", "--name-status", "HEAD"); diff.endOptions(); String output; try { output = diff.run(); } catch (VcsException ex) { exceptions.add(ex); return false; } String rootPath = root.getPath(); for (StringTokenizer lines = new StringTokenizer(output, "\n", false); lines.hasMoreTokens(); ) { String line = lines.nextToken().trim(); if (line.length() == 0) { continue; } String[] tk = line.split("\t"); switch (tk[0].charAt(0)) { case 'M': case 'A': realAdded.add(VcsUtil.getFilePath(rootPath + "/" + tk[1])); break; case 'D': realRemoved.add(VcsUtil.getFilePathForDeletedFile(rootPath + "/" + tk[1], false)); break; default: throw new IllegalStateException("Unexpected status: " + line); } } realAdded.removeAll(added); realRemoved.removeAll(removed); if (realAdded.size() != 0 || realRemoved.size() != 0) { final List<FilePath> files = new ArrayList<FilePath>(); files.addAll(realAdded); files.addAll(realRemoved); final Ref<Boolean> mergeAll = new Ref<Boolean>(); try { GuiUtils.runOrInvokeAndWait( new Runnable() { public void run() { String message = GitBundle.message("commit.partial.merge.message", partialOperation.getName()); SelectFilePathsDialog dialog = new SelectFilePathsDialog( project, files, message, null, "Commit All Files", CommonBundle.getCancelButtonText(), false); dialog.setTitle(GitBundle.getString("commit.partial.merge.title")); dialog.show(); mergeAll.set(dialog.isOK()); } }); } catch (RuntimeException ex) { throw ex; } catch (Exception ex) { throw new RuntimeException("Unable to invoke a message box on AWT thread", ex); } if (!mergeAll.get()) { return false; } // update non-indexed files if (!updateIndex(project, root, realAdded, realRemoved, exceptions)) { return false; } for (FilePath f : realAdded) { VcsDirtyScopeManager.getInstance(project).fileDirty(f); } for (FilePath f : realRemoved) { VcsDirtyScopeManager.getInstance(project).fileDirty(f); } } // perform merge commit try { GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.COMMIT); handler.setStdoutSuppressed(false); handler.addParameters("-F", messageFile.getAbsolutePath()); if (author != null) { handler.addParameters("--author=" + author); } handler.endOptions(); handler.run(); GitRepositoryManager manager = GitUtil.getRepositoryManager(project); manager.updateRepository(root); } catch (VcsException ex) { exceptions.add(ex); return false; } return true; }