Projects >> intellij-community >>a7a8315a03866f0f6c91b0234e44ed4195c2946d

Chunk
Conflicting content
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.FilePath;
<<<<<<< HEAD
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vcs.FileStatus;
=======
>>>>>>> 90cfcf81860e3236e1c811b87fc5855a77a30e59
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ChangeListManager;
Solution content
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ChangeListManager;
File
GitHistoryUtils.java
Developer's decision
Combination
Kind of conflict
Import
Chunk
Conflicting content
      }
    }

    h.setStdoutSuppressed(true);
    h.addParameters("-M", "--name-status", parser.getPretty(), "--encoding=UTF-8", commit);
    h.endOptions();
<<<<<<< HEAD
    h.addRelativePaths(filePath);
    parser.parseStatusBeforeName(true);
    final String output = h.run();
    final GitLogRecord record = parser.parseOneRecord(output);
    final List changes = record.coolChangesParser(project, root);

    final Change change = changes.get(0);
    if (change.isMoved() || change.isRenamed()) {
      final List paths = record.getFilePaths(root);
=======
    parser.setNameInOutput(true);
    final String output = h.run();
    final List records = parser.parse(output);

    // we have information about all changed files of the commit. Extracting information about the file we need.
    GitLogRecord fileRecord = null;
    for (GitLogRecord record : records) {
      final List paths = record.getPaths();
      if (!paths.isEmpty()) {
        String path = paths.get(paths.size()-1); // if the file is renamed, it has 2 paths - we are looking for the new name.
        if (path.equals(GitUtil.relativePath(root, filePath))) {
          fileRecord = record;
          break;
        }
    if (fileRecord != null && fileRecord.getNameStatus() == 'R') {
      final List paths = fileRecord.getFilePaths(root);
>>>>>>> 90cfcf81860e3236e1c811b87fc5855a77a30e59
      final String message = "Rename commit should have 2 paths. Commit: " + commit;
      if (!LOG.assertTrue(paths.size() == 2, message + " Output: [" + output + "]")) {
        throw new VcsException(message);
Solution content
    h.setStdoutSuppressed(true);
    h.addParameters("-M", "--name-status", parser.getPretty(), "--encoding=UTF-8", commit);
    h.endOptions();
    parser.parseStatusBeforeName(true);
    final String output = h.run();
    final List records = parser.parse(output);

    // we have information about all changed files of the commit. Extracting information about the file we need.
    GitLogRecord fileRecord = null;
    for (GitLogRecord record : records) {
      final List paths = record.getPaths();
      if (!paths.isEmpty()) {
        String path = paths.get(paths.size()-1); // if the file is renamed, it has 2 paths - we are looking for the new name.
        if (path.equals(GitUtil.relativePath(root, filePath))) {
          fileRecord = record;
          break;
        }
      }
    }

    if (fileRecord != null) {
      final List changes = fileRecord.coolChangesParser(project, root);
      final Change change = changes.get(0);
      if (change.isMoved() || change.isRenamed()) {
        final List paths = fileRecord.getFilePaths(root);
        final String message = "Rename commit should have 2 paths. Commit: " + commit;
        if (!LOG.assertTrue(paths.size() == 2, message + " Output: [" + output + "]")) {
          throw new VcsException(message);
        }
        return paths.get(0);
      }
    }
    return null;
  }

  private static class MyTokenAccumulator {
    private final StringBuilder myBuffer = new StringBuilder();

    private boolean myNotStarted = true;
    private GitLogParser myParser;

    public MyTokenAccumulator(GitLogParser parser) {
      myParser = parser;
    }

    @Nullable
    public GitLogRecord acceptLine(String s) {
      final boolean lineEnd = s.startsWith(GitLogParser.RECORD_START);
      if (lineEnd && (!myNotStarted)) {
        final String line = myBuffer.toString();
        myBuffer.setLength(0);
        myBuffer.append(s.substring(GitLogParser.RECORD_START.length()));

        return processResult(line);
      }
      else {
        myBuffer.append(lineEnd ? s.substring(GitLogParser.RECORD_START.length()) : s);
        myBuffer.append("\n");
      }
      myNotStarted = false;

      return null;
    }

    public GitLogRecord processLast() {
      return processResult(myBuffer.toString());
    }

    private GitLogRecord processResult(final String line) {
      return myParser.parseOneRecord(line);
    }

  }

  /**
   * Get history for the file
   *
   * @param project the context project
   * @param path    the file path
   * @return the list of the revisions
   * @throws VcsException if there is problem with running git
   */
  public static List history(final Project project, final FilePath path) throws VcsException {
    final VirtualFile root = GitUtil.getGitRoot(path);
    return history(project, path, root);
  }

  /**
   * Get history for the file
   *
   * @param project the context project
   * @param path    the file path
   * @return the list of the revisions
   * @throws VcsException if there is problem with running git
   */
  public static List history(final Project project, FilePath path, final VirtualFile root, final String... parameters) throws VcsException {
    final List rc = new ArrayList();
    final List exceptions = new ArrayList();

    history(project, path, root, new Consumer() {
      @Override public void consume(GitFileRevision gitFileRevision) {
        rc.add(gitFileRevision);
      }
    }, new Consumer() {
      @Override public void consume(VcsException e) {
        exceptions.add(e);
      }
    }, parameters);
    if (!exceptions.isEmpty()) {
      throw exceptions.get(0);
    }
    return rc;
  }

  public static List> onlyHashesHistory(Project project, FilePath path, final String... parameters)
    throws VcsException {
    final VirtualFile root = GitUtil.getGitRoot(path);
    return onlyHashesHistory(project, path, root, parameters);
  }

  public static List> onlyHashesHistory(Project project, FilePath path, final VirtualFile root, final String... parameters)
    throws VcsException {
    // adjust path using change manager
    path = getLastCommitName(project, path);
    GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.LOG);
    GitLogParser parser = new GitLogParser(HASH, COMMIT_TIME);
    h.setNoSSH(true);
    h.setStdoutSuppressed(true);
    h.addParameters(parameters);
    h.addParameters(parser.getPretty(), "--encoding=UTF-8");
    h.endOptions();
    h.addRelativePaths(path);
    String output = h.run();

    final List> rc = new ArrayList>();
    for (GitLogRecord record : parser.parse(output)) {
      rc.add(new Pair(new SHAHash(record.getHash()), record.getDate()));
    }
    return rc;
  }

  public static void historyWithLinks(final Project project,
                                                 FilePath path,
                                                 final SymbolicRefs refs,
                                                 final AsynchConsumer gitCommitConsumer,
                                                 final Getter isCanceled,
                                                 final String... parameters) throws VcsException {
    // adjust path using change manager
    path = getLastCommitName(project, path);
    final VirtualFile root = GitUtil.getGitRoot(path);
    final GitLineHandler h = new GitLineHandler(project, root, GitCommand.LOG);
    final GitLogParser parser = new GitLogParser(SHORT_HASH, HASH, COMMIT_TIME, AUTHOR_NAME, AUTHOR_TIME, AUTHOR_EMAIL, COMMITTER_NAME, COMMITTER_EMAIL, SHORT_PARENTS, REF_NAMES, SUBJECT, BODY);
    h.setNoSSH(true);
    h.setStdoutSuppressed(true);
    h.addParameters(parameters);
    parser.parseStatusBeforeName(true);
    h.addParameters("--name-status", parser.getPretty(), "--encoding=UTF-8");       // todo ?
    h.endOptions();
    h.addRelativePaths(path);

    final VcsException[] exc = new VcsException[1];
    final Semaphore semaphore = new Semaphore();
    final StringBuilder sb = new StringBuilder();
    h.addLineListener(new GitLineHandlerAdapter() {
      @Override
      public void onLineAvailable(final String line, final Key outputType) {
        try {
          if (ProcessOutputTypes.STDOUT.equals(outputType)) {
            if (isCanceled != null && isCanceled.get()) {
              h.cancel();
              return;
            }
            //if (line.charAt(line.length() - 1) != '\u0003') {
            if (! line.startsWith("\u0001")) {
              sb.append("\n").append(line);
              return;
            }
            takeLine(project, line, sb, parser, refs, root, exc, h, gitCommitConsumer);
          }
        } catch (ProcessCanceledException e) {
          h.cancel();
          semaphore.up();
        }
      }
      @Override
      public void processTerminated(int exitCode) {
        semaphore.up();
      }
      @Override
      public void startFailed(Throwable exception) {
      }
    });
    semaphore.down();
    h.start();
    semaphore.waitFor();
    takeLine(project, "", sb, parser, refs, root, exc, h, gitCommitConsumer);
    gitCommitConsumer.finished();
    if (exc[0] != null) {
      throw exc[0];
    }
  }

  private static void takeLine(final Project project, String line,
                               StringBuilder sb,
                               GitLogParser parser,
                               SymbolicRefs refs,
                               VirtualFile root,
                               VcsException[] exc, GitLineHandler h, AsynchConsumer gitCommitConsumer) {
    final String text = sb.toString();
    sb.setLength(0);
    sb.append(line);
    if (text.length() == 0) return;
    GitLogRecord record = parser.parseOneRecord(text);

    final GitCommit gitCommit;
    try {
      gitCommit = createCommit(project, refs, root, record);
    }
    catch (VcsException e) {
      exc[0] = e;
      h.cancel();
      return;
    }
    gitCommitConsumer.consume(gitCommit);
  }

  private static GitCommit createCommit(Project project, SymbolicRefs refs, VirtualFile root, GitLogRecord record) throws VcsException {
    GitCommit gitCommit;
    final Collection currentRefs = record.getRefs();
    List locals = new ArrayList();
    List remotes = new ArrayList();
    List tags = new ArrayList();
    final String s = parseRefs(refs, currentRefs, locals, remotes, tags);
    gitCommit = new GitCommit(AbstractHash.create(record.getShortHash()), new SHAHash(record.getHash()), record.getAuthorName(),
                                      record.getCommitterName(),
                                      record.getDate(), record.getFullMessage(),
                                      new HashSet(Arrays.asList(record.getParentsShortHashes())), record.getFilePaths(root),
                                      record.getAuthorEmail(),
                                      record.getCommitterEmail(), tags, locals, remotes,
                                      record.coolChangesParser(project, root), record.getAuthorTimeStamp() * 1000);
    gitCommit.setCurrentBranch(s);
    return gitCommit;
  }

  private static String parseRefs(SymbolicRefs refs,
                                Collection currentRefs,
                                List locals,
                                List remotes,
                                List tags) {
    for (String ref : currentRefs) {
      final SymbolicRefs.Kind kind = refs.getKind(ref);
      if (SymbolicRefs.Kind.LOCAL.equals(kind)) {
        locals.add(ref);
      } else if (SymbolicRefs.Kind.REMOTE.equals(kind)) {
        remotes.add(ref);
      } else {
        tags.add(ref);
      }
    }
    if (refs.getCurrent() != null && currentRefs.contains(refs.getCurrent().getName())) return refs.getCurrent().getName();
    return null;
  }

  public static List commitsDetails(Project project,
                                                 FilePath path, SymbolicRefs refs,
                                                 final Collection commitsIds) throws VcsException {
    // adjust path using change manager
    path = getLastCommitName(project, path);
    final VirtualFile root = GitUtil.getGitRoot(path);
    GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.SHOW);
    GitLogParser parser = new GitLogParser(SHORT_HASH, HASH, COMMIT_TIME, AUTHOR_NAME, AUTHOR_TIME, AUTHOR_EMAIL, COMMITTER_NAME, COMMITTER_EMAIL, SHORT_PARENTS, REF_NAMES, SUBJECT, BODY);
    h.setNoSSH(true);
    h.setStdoutSuppressed(true);
    h.addParameters("--name-only", parser.getPretty(), "--encoding=UTF-8");
    parser.parseStatusBeforeName(false);
    h.addParameters(new ArrayList(commitsIds));

    h.endOptions();
    h.addRelativePaths(path);
    String output = h.run();

    final List rc = new ArrayList();
    for (GitLogRecord record : parser.parse(output)) {
      final GitCommit gitCommit = createCommit(project, refs, root, record);
      rc.add(gitCommit);
    }
    return rc;
  }

  public static void hashesWithParents(Project project, FilePath path, final AsynchConsumer consumer,
                                       final Getter isCanceled,
                                       final String... parameters) throws VcsException {
    // adjust path using change manager
    path = getLastCommitName(project, path);
    final VirtualFile root = GitUtil.getGitRoot(path);
    final GitLineHandler h = new GitLineHandler(project, root, GitCommand.LOG);
    final GitLogParser parser = new GitLogParser(SHORT_HASH, COMMIT_TIME, SHORT_PARENTS, AUTHOR_NAME);
    parser.parseStatusBeforeName(false);
    h.setNoSSH(true);
    h.setStdoutSuppressed(true);
    h.addParameters(parameters);
    h.addParameters(parser.getPretty(), "--encoding=UTF-8");

    h.endOptions();
    h.addRelativePaths(path);

    final Semaphore semaphore = new Semaphore();
    h.addLineListener(new GitLineHandlerListener() {
      @Override
      public void onLineAvailable(final String line, final Key outputType) {
        try {
          if (ProcessOutputTypes.STDOUT.equals(outputType)) {
            if (isCanceled != null && isCanceled.get()) {
              h.cancel();
              return;
            }
            GitLogRecord record = parser.parseOneRecord(line);
            consumer.consume(new CommitHashPlusParents(record.getShortHash(),
                                                       record.getParentsShortHashes(), record.getLongTimeStamp() * 1000,
                                                       record.getAuthorName()));
          }
        } catch (ProcessCanceledException e) {
          h.cancel();
          semaphore.up();
        }
      }

      @Override
      public void processTerminated(int exitCode) {
        semaphore.up();
      }

      @Override
      public void startFailed(Throwable exception) {
        // todo
      }
    });
    semaphore.down();
    h.start();
    semaphore.waitFor();
    consumer.finished();
  }

  /**
   * Get name of the file in the last commit. If file was renamed, returns the previous name.
   *
   * @param project the context project
   * @param path    the path to check
   * @return the name of file in the last commit or argument
   */
  public static FilePath getLastCommitName(final Project project, FilePath path) {
    final ChangeListManager changeManager = ChangeListManager.getInstance(project);
    final Change change = changeManager.getChange(path);
    if (change != null && change.getType() == Change.Type.MOVED) {
      GitContentRevision r = (GitContentRevision)change.getBeforeRevision();
      assert r != null : "Move change always have beforeRevision";
      path = r.getFile();
    }
    return path;
  }
}
File
GitHistoryUtils.java
Developer's decision
Manual
Kind of conflict
Comment
For statement
If statement
Method invocation
Variable
Chunk
Conflicting content
   * @throws VcsException if there is problem with running git
   */
  public static List history(final Project project, FilePath path, final VirtualFile root, final String... parameters) throws VcsException {
<<<<<<< HEAD
    // adjust path using change manager
    path = getLastCommitName(project, path);
    GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.LOG);
    GitLogParser parser = new GitLogParser(HASH, COMMIT_TIME, AUTHOR_NAME, AUTHOR_EMAIL, COMMITTER_NAME, COMMITTER_EMAIL, SUBJECT, BODY);
    h.setNoSSH(true);
    h.setStdoutSuppressed(true);
    h.addParameters("-M", "--follow", "--name-only", parser.getPretty(), "--encoding=UTF-8");
    parser.parseStatusBeforeName(false);
    if (parameters != null && parameters.length > 0) {
      h.addParameters(parameters);
    }
    h.endOptions();
    h.addRelativePaths(path);
    String output = h.run();

    final List result = parser.parse(output);
=======
>>>>>>> 90cfcf81860e3236e1c811b87fc5855a77a30e59
    final List rc = new ArrayList();
    final List exceptions = new ArrayList();
Solution content
   * @throws VcsException if there is problem with running git
   */
  public static List history(final Project project, FilePath path, final VirtualFile root, final String... parameters) throws VcsException {
    final List rc = new ArrayList();
    final List exceptions = new ArrayList();
File
GitHistoryUtils.java
Developer's decision
Version 2
Kind of conflict
Comment
If statement
Method invocation
Variable
Chunk
Conflicting content
import git4idea.GitRevisionNumber;
import git4idea.history.wholeTree.AbstractHash;

<<<<<<< HEAD
import java.io.File;
import java.util.*;
=======
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
>>>>>>> 90cfcf81860e3236e1c811b87fc5855a77a30e59

/**
 * 

Parses the 'git log' output basing on the given number of options.

Solution content
import git4idea.GitRevisionNumber;
import git4idea.history.wholeTree.AbstractHash;

import java.io.File;
import java.util.*;

/**
 * 

Parses the 'git log' output basing on the given number of options.

File
GitLogParser.java
Developer's decision
Version 1
Kind of conflict
Import
Chunk
Conflicting content
    if (myNameStatusOutputted != NameStatus.NONE) {
      final String[] infoAndPath = line.split(RECORD_END);
<<<<<<< HEAD
      line = infoAndPath[0];
      if (infoAndPath.length > 1) {
        // separator is \n for paths, space for paths and status
        final List nameAndPathSplit = new ArrayList(Arrays.asList(infoAndPath[infoAndPath.length - 1].split("\n")));
        for (Iterator it = nameAndPathSplit.iterator(); it.hasNext();) {
          if (it.next().trim().isEmpty()) {
            it.remove();
          }
        }
        final int start = includeStatus ? 1 : 0;

        for (String pathLine : nameAndPathSplit) {
          final String[] partsArr = pathLine.split("[\\s]");
          final List stringList = Arrays.asList(partsArr);
          if (includeStatus) {
            parts.add(stringList);
=======
      line = infoAndPath[0]; // commit information
      if (infoAndPath.length > 1) { // safety check
        final String statusAndPaths = infoAndPath[1].replaceAll("[\\r\\n]", "");
        final String[] statusAndPathsSplit = statusAndPaths.split("\\t"); // file status and path(s) are separated by tabs

        if (statusAndPathsSplit.length > 0) { // safety check
          int index = 0;
          if (myNameStatusOutputted == NameStatus.STATUS) {
            nameStatus = statusAndPathsSplit[0].charAt(0); // for R100 we save R, it's enough for us.
            index = 1;
          }
          // extracting path or 2 paths in case of move/rename
          for (; index < statusAndPathsSplit.length; index++) {
            String path = statusAndPathsSplit[index];
            if (!path.isEmpty()) {
              paths.add(path);
            }
>>>>>>> 90cfcf81860e3236e1c811b87fc5855a77a30e59
          }
          paths.addAll(stringList.subList(start, stringList.size()));
        }
Solution content
    if (myNameStatusOutputted != NameStatus.NONE) {
      final String[] infoAndPath = line.split(RECORD_END);
      line = infoAndPath[0];
      if (infoAndPath.length > 1) {
        // separator is \n for paths, space for paths and status
        final List nameAndPathSplit = new ArrayList(Arrays.asList(infoAndPath[infoAndPath.length - 1].split("\n")));
        for (Iterator it = nameAndPathSplit.iterator(); it.hasNext();) {
          if (it.next().trim().isEmpty()) {
            it.remove();
          }
        }
        final int start = includeStatus ? 1 : 0;

        for (String pathLine : nameAndPathSplit) {
          final String[] partsArr = pathLine.split("[\\s]");
          final List stringList = Arrays.asList(partsArr);
          if (includeStatus) {
            parts.add(stringList);
          }
          paths.addAll(stringList.subList(start, stringList.size()));
        }
File
GitLogParser.java
Developer's decision
Version 1
Kind of conflict
Array access
Comment
For statement
If statement
Method invocation
Variable
Chunk
Conflicting content
  private final List myPaths;
  private final List> myParts;

<<<<<<< HEAD
  GitLogRecord(Map options, List paths, List> parts) {
=======
  GitLogRecord(@NotNull Map options, @NotNull List paths, char nameStatus) {
>>>>>>> 90cfcf81860e3236e1c811b87fc5855a77a30e59
    myOptions = options;
    myPaths = paths;
    myParts = parts;
Solution content
  private final List myPaths;
  private final List> myParts;

  GitLogRecord(Map options, List paths, List> parts) {
    myOptions = options;
    myPaths = paths;
    myParts = parts;
File
GitLogRecord.java
Developer's decision
Version 1
Kind of conflict
Method signature