Java Code Examples for org.eclipse.jgit.revwalk.RevCommit#getParentCount()

The following examples show how to use org.eclipse.jgit.revwalk.RevCommit#getParentCount() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: PathCriteria.java    From onedev with MIT License 6 votes vote down vote up
@Override
public boolean matches(RefUpdated event) {
	Project project = event.getProject();
	RevCommit commit = project.getRevCommit(event.getNewCommitId(), true);
	
	Collection<String> changedFiles;
	if (!event.getOldCommitId().equals(ObjectId.zeroId()))
		changedFiles = GitUtils.getChangedFiles(project.getRepository(), event.getOldCommitId(), event.getNewCommitId());
	else if (commit.getParentCount() != 0)
		changedFiles = GitUtils.getChangedFiles(project.getRepository(), commit.getParent(0), event.getNewCommitId());
	else
		changedFiles = new HashSet<>();
	
	Matcher matcher = new PathMatcher();
	for (String value: values) {
		for (String changedFile: changedFiles) {
			if (matcher.matches(value, changedFile)) 
				return true;
		}
	}
	return false;
}
 
Example 2
Source File: GitServiceImpl.java    From apidiff with MIT License 6 votes vote down vote up
@Override
		public final boolean include(final RevWalk walker, final RevCommit c) {
			
			Long diffTimestamp = 0L;
			diffTimestamp = this.calcDiffTimeCommit(c);
			
			if(c.getParentCount() > 1){//merge
				logger.info("Merge of the branches deleted. [commitId=" + c.getId().getName() + "]");
				return false;
			}
				
			//TODO: create other filter to date.
//			if(diffTimestamp > SEVEN_DAYS){//old
//				logger.info("Old commit old deleted. [commitId=" + c.getId().getName() + "][date=" + getDateCommitFormat(c) + "]");
//				return false;
//			}
			
			return true;
		}
 
Example 3
Source File: AbstractGitRepositoryTestCase.java    From wildfly-core with GNU Lesser General Public License v2.1 6 votes vote down vote up
protected List<String> listFilesInCommit(Repository repository) throws IOException, GitAPIException {
    List<String> result = new ArrayList<>();
    try (Git git = new Git(repository)) {
        RevCommit commit = git.log().add(git.getRepository().resolve(Constants.MASTER)).call().iterator().next();
        if (commit.getParentCount() > 0) {
            try (TreeWalk treeWalk = new TreeWalk(repository)) {
                treeWalk.addTree(commit.getParent(0).getTree());
                treeWalk.addTree(commit.getTree());
                treeWalk.setRecursive(true);
                List<DiffEntry> diff = DiffEntry.scan(treeWalk, false, null);
                for (DiffEntry diffEntry : diff) {
                    if(diffEntry.getChangeType() == DiffEntry.ChangeType.DELETE) {
                        result.add("-" + diffEntry.getOldPath());
                    } else {
                        result.add(diffEntry.getNewPath());
                    }
                }
            }
        }
    }
    Collections.sort(result);
    return result;
}
 
Example 4
Source File: GitServiceImpl.java    From RefactoringMiner with MIT License 6 votes vote down vote up
@Override
public Churn churn(Repository repository, RevCommit currentCommit) throws Exception {
	if (currentCommit.getParentCount() > 0) {
       	ObjectId oldTree = currentCommit.getParent(0).getTree();
        ObjectId newTree = currentCommit.getTree();
       	final TreeWalk tw = new TreeWalk(repository);
       	tw.setRecursive(true);
       	tw.addTree(oldTree);
       	tw.addTree(newTree);
       	
       	List<DiffEntry> diffs = DiffEntry.scan(tw);
       	DiffFormatter diffFormatter = new DiffFormatter(DisabledOutputStream.INSTANCE);
   		diffFormatter.setRepository(repository);
   		diffFormatter.setContext(0);
   		
       	int addedLines = 0;
   		int deletedLines = 0;
       	for (DiffEntry entry : diffs) {
   			FileHeader header = diffFormatter.toFileHeader(entry);
           	List<? extends HunkHeader> hunks = header.getHunks();
           	for (HunkHeader hunkHeader : hunks) {
           		for (Edit edit : hunkHeader.toEditList()) {
   					if (edit.getType() == Type.INSERT) {
   						addedLines += edit.getLengthB();
   					} else if (edit.getType() == Type.DELETE) {
   						deletedLines += edit.getLengthA();
   					} else if (edit.getType() == Type.REPLACE) {
   						deletedLines += edit.getLengthA();
   						addedLines += edit.getLengthB();
   					}
   				}
           	}
       	}
       	diffFormatter.close();
       	return new Churn(addedLines, deletedLines);
	}
	return null;
}
 
Example 5
Source File: GitHistoryRefactoringMinerImpl.java    From RefactoringMiner with MIT License 6 votes vote down vote up
@Override
public Churn churnAtCommit(Repository repository, String commitId, RefactoringHandler handler) {
	GitService gitService = new GitServiceImpl();
	RevWalk walk = new RevWalk(repository);
	try {
		RevCommit commit = walk.parseCommit(repository.resolve(commitId));
		if (commit.getParentCount() > 0) {
			walk.parseCommit(commit.getParent(0));
			return gitService.churn(repository, commit);
		}
		else {
			logger.warn(String.format("Ignored revision %s because it has no parent", commitId));
		}
	} catch (MissingObjectException moe) {
		logger.warn(String.format("Ignored revision %s due to missing commit", commitId), moe);
	} catch (Exception e) {
		logger.warn(String.format("Ignored revision %s due to error", commitId), e);
		handler.handleException(commitId, e);
	} finally {
		walk.close();
		walk.dispose();
	}
	return null;
}
 
Example 6
Source File: RepositoryResource.java    From fabric8-forge with Apache License 2.0 6 votes vote down vote up
public CommitInfo createCommitInfo(RevCommit entry) {
    final Date date = GitUtils.getCommitDate(entry);
    PersonIdent authorIdent = entry.getAuthorIdent();
    String author = null;
    String name = null;
    String email = null;
    String avatarUrl = null;
    if (authorIdent != null) {
        author = authorIdent.getName();
        name = authorIdent.getName();
        email = authorIdent.getEmailAddress();

        // lets try default the avatar
        if (Strings.isNotBlank(email)) {
            avatarUrl = getAvatarUrl(email);
        }
    }
    boolean merge = entry.getParentCount() > 1;
    String shortMessage = entry.getShortMessage();
    String sha = entry.getName();
    return new CommitInfo(sha, author, name, email, avatarUrl, date, merge, shortMessage);
}
 
Example 7
Source File: GitRepo.java    From git-changelog-lib with Apache License 2.0 5 votes vote down vote up
private GitCommit toGitCommit(final RevCommit revCommit) {
  final Boolean merge = revCommit.getParentCount() > 1;
  return new GitCommit( //
      revCommit.getAuthorIdent().getName(), //
      revCommit.getAuthorIdent().getEmailAddress(), //
      new Date(revCommit.getCommitTime() * 1000L), //
      revCommit.getFullMessage(), //
      revCommit.getId().getName(), //
      merge);
}
 
Example 8
Source File: JGitHelper.java    From go-plugins with Apache License 2.0 5 votes vote down vote up
private Revision getRevisionObj(Repository repository, RevCommit commit) throws IOException {
    String commitSHA = commit.getName();
    Date commitTime = commit.getAuthorIdent().getWhen();
    String comment = commit.getFullMessage().trim();
    String user = commit.getAuthorIdent().getName();
    String emailId = commit.getAuthorIdent().getEmailAddress();
    List<ModifiedFile> modifiedFiles = new ArrayList<ModifiedFile>();
    if (commit.getParentCount() == 0) {
        TreeWalk treeWalk = new TreeWalk(repository);
        treeWalk.addTree(commit.getTree());
        treeWalk.setRecursive(false);
        while (treeWalk.next()) {
            modifiedFiles.add(new ModifiedFile(treeWalk.getPathString(), "added"));
        }
    } else {
        RevWalk rw = new RevWalk(repository);
        RevCommit parent = rw.parseCommit(commit.getParent(0).getId());
        DiffFormatter diffFormatter = new DiffFormatter(DisabledOutputStream.INSTANCE);
        diffFormatter.setRepository(repository);
        diffFormatter.setDiffComparator(RawTextComparator.DEFAULT);
        diffFormatter.setDetectRenames(true);
        List<DiffEntry> diffEntries = diffFormatter.scan(parent.getTree(), commit.getTree());
        for (DiffEntry diffEntry : diffEntries) {
            modifiedFiles.add(new ModifiedFile(diffEntry.getNewPath(), getAction(diffEntry.getChangeType().name())));
        }
    }

    return new Revision(commitSHA, commitTime, comment, user, emailId, modifiedFiles);
}
 
Example 9
Source File: GitCommit.java    From compiler with Apache License 2.0 5 votes vote down vote up
void updateChangedFiles(RevCommit rc) {
	if (rc.getParentCount() == 0) {
		TreeWalk tw = new TreeWalk(repository);
		tw.reset();
		try {
			tw.addTree(rc.getTree());
			tw.setRecursive(true);
			while (tw.next()) {
				if (!tw.isSubtree()) {
					String path = tw.getPathString();
					getChangedFile(path, ChangeKind.ADDED);
					filePathGitObjectIds.put(path, tw.getObjectId(0));
				}
			}
		} catch (IOException e) {
			if (debug)
				System.err.println(e.getMessage());
		}
		tw.close();
	} else {
		parentIndices = new int[rc.getParentCount()];
		for (int i = 0; i < rc.getParentCount(); i++) {
			int parentIndex = connector.revisionMap.get(rc.getParent(i).getName());
			// merged commit in git only store diffs between the first parent and the child
			if (i == 0)
				updateChangedFiles(rc.getParent(i), parentIndex, rc);
			parentIndices[i] = parentIndex;
		}
	}
}
 
Example 10
Source File: ExtractProjectCommitsAdapter.java    From coderadar with MIT License 5 votes vote down vote up
private List<Commit> getCommits(DateRange range, String repositoryRoot) {
  List<RevCommit> revCommits = RevCommitHelper.getRevCommits(repositoryRoot);

  int revCommitsSize = revCommits.size();
  HashMap<String, Commit> map = new HashMap<>(revCommitsSize);
  for (RevCommit rc : revCommits) {
    if (isInDateRange(range, rc)) {
      Commit commit = map.get(rc.getName());
      if (commit == null) {
        commit = mapRevCommitToCommit(rc);
      }
      List<Commit> parents =
          rc.getParentCount() > 0
              ? new ArrayList<>(rc.getParentCount())
              : Collections.emptyList();
      for (RevCommit parent : rc.getParents()) {
        if (isInDateRange(range, parent)) {
          Commit parentCommit = map.get(parent.getId().getName());
          if (parentCommit == null) {
            parentCommit = mapRevCommitToCommit(parent);
            map.put(parent.getName(), parentCommit);
          }
          parents.add(parentCommit);
        }
      }
      commit.setParents(parents);
      map.put(rc.getName(), commit);
    }
  }
  return new ArrayList<>(map.values());
}
 
Example 11
Source File: GitServiceImpl.java    From RefactoringMiner with MIT License 5 votes vote down vote up
public void fileTreeDiff(Repository repository, RevCommit currentCommit, List<String> javaFilesBefore, List<String> javaFilesCurrent, Map<String, String> renamedFilesHint) throws Exception {
       if (currentCommit.getParentCount() > 0) {
       	ObjectId oldTree = currentCommit.getParent(0).getTree();
        ObjectId newTree = currentCommit.getTree();
       	final TreeWalk tw = new TreeWalk(repository);
       	tw.setRecursive(true);
       	tw.addTree(oldTree);
       	tw.addTree(newTree);

       	final RenameDetector rd = new RenameDetector(repository);
       	rd.setRenameScore(80);
       	rd.addAll(DiffEntry.scan(tw));

       	for (DiffEntry diff : rd.compute(tw.getObjectReader(), null)) {
       		ChangeType changeType = diff.getChangeType();
       		String oldPath = diff.getOldPath();
       		String newPath = diff.getNewPath();
       		if (changeType != ChangeType.ADD) {
        		if (isJavafile(oldPath)) {
        			javaFilesBefore.add(oldPath);
        		}
        	}
       		if (changeType != ChangeType.DELETE) {
        		if (isJavafile(newPath)) {
        			javaFilesCurrent.add(newPath);
        		}
       		}
       		if (changeType == ChangeType.RENAME && diff.getScore() >= rd.getRenameScore()) {
       			if (isJavafile(oldPath) && isJavafile(newPath)) {
       				renamedFilesHint.put(oldPath, newPath);
       			}
       		}
       	}
       }
}
 
Example 12
Source File: GitHistoryRefactoringMinerImpl.java    From RefactoringMiner with MIT License 5 votes vote down vote up
protected List<Refactoring> detectRefactorings(GitService gitService, Repository repository, final RefactoringHandler handler, File projectFolder, RevCommit currentCommit) throws Exception {
	List<Refactoring> refactoringsAtRevision;
	String commitId = currentCommit.getId().getName();
	List<String> filePathsBefore = new ArrayList<String>();
	List<String> filePathsCurrent = new ArrayList<String>();
	Map<String, String> renamedFilesHint = new HashMap<String, String>();
	gitService.fileTreeDiff(repository, currentCommit, filePathsBefore, filePathsCurrent, renamedFilesHint);
	
	Set<String> repositoryDirectoriesBefore = new LinkedHashSet<String>();
	Set<String> repositoryDirectoriesCurrent = new LinkedHashSet<String>();
	Map<String, String> fileContentsBefore = new LinkedHashMap<String, String>();
	Map<String, String> fileContentsCurrent = new LinkedHashMap<String, String>();
	try (RevWalk walk = new RevWalk(repository)) {
		// If no java files changed, there is no refactoring. Also, if there are
		// only ADD's or only REMOVE's there is no refactoring
		if (!filePathsBefore.isEmpty() && !filePathsCurrent.isEmpty() && currentCommit.getParentCount() > 0) {
			RevCommit parentCommit = currentCommit.getParent(0);
			populateFileContents(repository, parentCommit, filePathsBefore, fileContentsBefore, repositoryDirectoriesBefore);
			UMLModel parentUMLModel = createModel(fileContentsBefore, repositoryDirectoriesBefore);

			populateFileContents(repository, currentCommit, filePathsCurrent, fileContentsCurrent, repositoryDirectoriesCurrent);
			UMLModel currentUMLModel = createModel(fileContentsCurrent, repositoryDirectoriesCurrent);
			
			refactoringsAtRevision = parentUMLModel.diff(currentUMLModel, renamedFilesHint).getRefactorings();
			refactoringsAtRevision = filter(refactoringsAtRevision);
		} else {
			//logger.info(String.format("Ignored revision %s with no changes in java files", commitId));
			refactoringsAtRevision = Collections.emptyList();
		}
		handler.handle(commitId, refactoringsAtRevision);
		
		walk.dispose();
	}
	return refactoringsAtRevision;
}
 
Example 13
Source File: GitRepoMetaData.java    From GitFx with Apache License 2.0 5 votes vote down vote up
public ArrayList<String> getShortMessage() {
        for (RevCommit revision : walk) {
            shortMessage.add(revision.getShortMessage());
//[LOG]            logger.debug(revision.getShortMessage());
            DiffFormatter df = new DiffFormatter(DisabledOutputStream.INSTANCE);
            df.setRepository(repository);
            df.setDiffComparator(RawTextComparator.DEFAULT);
            df.setDetectRenames(true);
            RevCommit parent = null;
            if(revision.getParentCount()!=0) {
                try {
                    parent = walk.parseCommit(revision.getParent(0).getId());
                    RevTree tree = revision.getTree();
                    List<DiffEntry> diffs = df.scan(parent.getTree(), revision.getTree());
                    for (DiffEntry diff : diffs) {
                        String changeType = diff.getChangeType().name();
                        if(changeType.equals(ADD)|| changeType.equals(MODIFY))
                        {
//[LOG]                            logger.debug(diff.getChangeType().name());
//[LOG]                            logger.debug(diff.getNewPath());
                            tempCommitHistory.add(diff.getNewPath());
                        }
                    }
                }catch (IOException ex) {
//[LOG]                    logger.debug("IOException", ex);
                }
            }
            commitSHA.add(commitCount,revision.name());
            commitHistory.add(commitCount++,new ArrayList<String>(tempCommitHistory));
            tempCommitHistory.clear();
        }
        walk.reset();
        return shortMessage;
    }
 
Example 14
Source File: ChangingIdentifiersRepositoryWalker.java    From naturalize with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
@Override
public void visitCommitFiles(final RevCommit commit) {
	try {
		System.out.println(commit);
		if (commit.getParentCount() > 0) {
			editListRetriever.retrieveEditListBetweenAndCallback(commit,
					commit.getParent(0), this);
		} else {
			doFirstScan(repositoryDir, commit.getName());
		}
	} catch (LargeObjectException | GitAPIException | IOException e) {
		LOGGER.warning(ExceptionUtils.getFullStackTrace(e));
	}

}
 
Example 15
Source File: SimpleCommit.java    From spring-cloud-release-tools with Apache License 2.0 5 votes vote down vote up
SimpleCommit(RevCommit revCommit) {
	this(revCommit.abbreviate(8).name(), revCommit.name(),
			revCommit.getShortMessage(), revCommit.getFullMessage(),
			revCommit.getAuthorIdent().getName(),
			revCommit.getAuthorIdent().getEmailAddress(),
			revCommit.getCommitterIdent().getName(),
			revCommit.getCommitterIdent().getEmailAddress(),
			revCommit.getParentCount() > 1);
}
 
Example 16
Source File: ExportCommitCommand.java    From netbeans with Apache License 2.0 5 votes vote down vote up
@Override
protected void run() throws GitException {
    Repository repository = getRepository();
    String workTreePath = repository.getWorkTree().getAbsolutePath();
    RevCommit commit = Utils.findCommit(repository, revisionStr);
    if (commit.getParentCount() > 1) {
        throw new GitException("Unable to export a merge commit");
    }
    try (DiffFormatter formatter = new DiffFormatter(out)) {
        out.write(Constants.encode(formatCommitInfo(commit)));
        formatter.setRepository(repository);
        List<DiffEntry> diffEntries;
        if (commit.getParentCount() > 0) {
            formatter.setDetectRenames(true);
            diffEntries = formatter.scan(commit.getParent(0), commit);
        } else {
            TreeWalk walk = new TreeWalk(repository);
            walk.reset();
            walk.setRecursive(true);
            walk.addTree(new EmptyTreeIterator());
            walk.addTree(commit.getTree());
            walk.setFilter(AndTreeFilter.create(TreeFilter.ANY_DIFF, PathFilter.ANY_DIFF));
            diffEntries = DiffEntry.scan(walk);
        }
        for (DiffEntry ent : diffEntries) {
            if (monitor.isCanceled()) {
                break;
            }
            listener.notifyFile(new File(workTreePath + File.separator + ent.getNewPath()), ent.getNewPath());
            formatter.format(ent);
        }
        formatter.flush();
    } catch (IOException ex) {
        throw new GitException(ex);
    }
}
 
Example 17
Source File: APIDiff.java    From apidiff with MIT License 5 votes vote down vote up
private Result diffCommit(final RevCommit currentCommit, final Repository repository, String nameProject, Classifier classifierAPI) throws Exception{
	File projectFolder = new File(UtilTools.getPathProject(this.path, nameProject));
	if(currentCommit.getParentCount() != 0){//there is at least one parent
		try {
			APIVersion version1 = this.getAPIVersionByCommit(currentCommit.getParent(0).getName(), projectFolder, repository, currentCommit, classifierAPI);//old version
			APIVersion version2 = this.getAPIVersionByCommit(currentCommit.getId().getName(), projectFolder, repository, currentCommit, classifierAPI); //new version
			DiffProcessor diff = new DiffProcessorImpl();
			return diff.detectChange(version1, version2, repository, currentCommit);
		} catch (Exception e) {
			this.logger.error("Error during checkout [commit=" + currentCommit + "]");
		}
	}
	return new Result();
}
 
Example 18
Source File: GitSCM.java    From repositoryminer with Apache License 2.0 5 votes vote down vote up
private List<Change> getChangesForCommitedFiles(String hash) throws IOException {
	RevWalk revWalk = new RevWalk(git.getRepository());
	RevCommit commit = revWalk.parseCommit(ObjectId.fromString(hash));

	if (commit.getParentCount() > 1) {
		revWalk.close();
		return new ArrayList<Change>();
	}

	RevCommit parentCommit = commit.getParentCount() > 0
			? revWalk.parseCommit(ObjectId.fromString(commit.getParent(0).getName()))
			: null;

	DiffFormatter df = new DiffFormatter(DisabledOutputStream.INSTANCE);
	df.setBinaryFileThreshold(2048);
	df.setRepository(git.getRepository());
	df.setDiffComparator(RawTextComparator.DEFAULT);
	df.setDetectRenames(true);

	List<DiffEntry> diffEntries = df.scan(parentCommit, commit);
	df.close();
	revWalk.close();

	List<Change> changes = new ArrayList<Change>();
	for (DiffEntry entry : diffEntries) {
		Change change = new Change(entry.getNewPath(), entry.getOldPath(), 0, 0,
				ChangeType.valueOf(entry.getChangeType().name()));
		analyzeDiff(change, entry);
		changes.add(change);
	}

	return changes;
}
 
Example 19
Source File: RepositoryResource.java    From fabric8-forge with Apache License 2.0 4 votes vote down vote up
protected String doDiff(Git git, String objectId, String baseObjectId, String pathOrBlobPath) throws IOException {
    Repository r = git.getRepository();
    String blobPath = trimLeadingSlash(pathOrBlobPath);

    RevCommit commit;
    if (Strings.isNotBlank(objectId)) {
        commit = CommitUtils.getCommit(r, objectId);
    } else {
        commit = CommitUtils.getHead(r);
    }
    RevCommit baseCommit = null;
    if (Strings.isNotBlank(baseObjectId) && !Objects.equals(baseObjectId, objectId)) {
        baseCommit = CommitUtils.getCommit(r, baseObjectId);
    }

    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    DiffFormatter formatter = createDiffFormatter(r, buffer);

    RevTree commitTree = commit.getTree();
    RevTree baseTree;
    if (baseCommit == null) {
        if (commit.getParentCount() > 0) {
            final RevWalk rw = new RevWalk(r);
            RevCommit parent = rw.parseCommit(commit.getParent(0).getId());
            rw.dispose();
            baseTree = parent.getTree();
        } else {
            // FIXME initial commit. no parent?!
            baseTree = commitTree;
        }
    } else {
        baseTree = baseCommit.getTree();
    }

    List<DiffEntry> diffEntries = formatter.scan(baseTree, commitTree);
    if (blobPath != null && blobPath.length() > 0) {
        for (DiffEntry diffEntry : diffEntries) {
            if (diffEntry.getNewPath().equalsIgnoreCase(blobPath)) {
                formatter.format(diffEntry);
                break;
            }
        }
    } else {
        formatter.format(diffEntries);
    }
    formatter.flush();
    return buffer.toString();
}
 
Example 20
Source File: LayoutHelper.java    From git-as-svn with GNU General Public License v2.0 4 votes vote down vote up
/**
 * Get new revisions list.
 *
 * @param repository    Repository.
 * @param loaded        Already loaded commits.
 * @param targetCommits Target commits.
 * @return Return new commits ordered by creation time. Parent revision always are before child.
 */
public static List<RevCommit> getNewRevisions(@NotNull Repository repository, @NotNull Set<? extends ObjectId> loaded, @NotNull Collection<? extends ObjectId> targetCommits) throws IOException {
  final Map<RevCommit, RevisionNode> revisionChilds = new HashMap<>();
  final Deque<RevCommit> revisionFirst = new ArrayDeque<>();
  final Deque<RevCommit> revisionQueue = new ArrayDeque<>();
  final RevWalk revWalk = new RevWalk(repository);
  for (ObjectId target : targetCommits) {
    if (!loaded.contains(target)) {
      final RevCommit revCommit = revWalk.parseCommit(target);
      revisionQueue.add(revCommit);
      revisionChilds.put(revCommit, new RevisionNode());
    }
  }
  while (!revisionQueue.isEmpty()) {
    final RevCommit commit = revWalk.parseCommit(revisionQueue.remove());
    if (commit == null || loaded.contains(commit.getId())) {
      revisionFirst.add(commit);
      continue;
    }
    if (commit.getParentCount() > 0) {
      final RevisionNode commitNode = revisionChilds.get(commit);
      for (RevCommit parent : commit.getParents()) {
        commitNode.parents.add(parent);
        revisionChilds.computeIfAbsent(parent, (id) -> {
          revisionQueue.add(parent);
          return new RevisionNode();
        }).childs.add(commit);
      }
    } else {
      revisionFirst.add(commit);
    }
  }
  final List<RevCommit> result = new ArrayList<>(revisionChilds.size());
  while (!revisionChilds.isEmpty()) {
    RevCommit firstCommit = null;
    RevisionNode firstNode = null;
    final Iterator<RevCommit> iterator = revisionFirst.iterator();
    while (iterator.hasNext()) {
      final RevCommit iterCommit = iterator.next();
      final RevisionNode iterNode = revisionChilds.get(iterCommit);
      if (iterNode == null) {
        iterator.remove();
        continue;
      }
      if (!iterNode.parents.isEmpty()) {
        iterator.remove();
      } else if (firstCommit == null || firstCommit.getCommitTime() > iterCommit.getCommitTime()) {
        firstNode = iterNode;
        firstCommit = iterCommit;
      }
    }
    if (firstNode == null || firstCommit == null) {
      throw new IllegalStateException();
    }
    revisionChilds.remove(firstCommit);
    result.add(firstCommit);
    for (RevCommit childId : firstNode.childs) {
      final RevisionNode childNode = revisionChilds.get(childId);
      if (childNode != null) {
        childNode.parents.remove(firstCommit);
        if (childNode.parents.isEmpty()) {
          revisionFirst.add(childId);
        }
      }
    }
  }
  return result;
}