1 /*******************************************************************************
2 * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org>
3 * Copyright (C) 2012, Robin Stocker <robin@nibor.org>
5 * All rights reserved. This program and the accompanying materials
6 * are made available under the terms of the Eclipse Public License v1.0
7 * which accompanies this distribution, and is available at
8 * http://www.eclipse.org/legal/epl-v10.html
9 *******************************************************************************/
10 package org
.eclipse
.egit
.core
;
12 import java
.io
.IOException
;
13 import java
.util
.Collection
;
14 import java
.util
.List
;
16 import org
.eclipse
.core
.runtime
.Assert
;
17 import org
.eclipse
.jgit
.lib
.AnyObjectId
;
18 import org
.eclipse
.jgit
.lib
.Constants
;
19 import org
.eclipse
.jgit
.lib
.ObjectId
;
20 import org
.eclipse
.jgit
.lib
.Ref
;
21 import org
.eclipse
.jgit
.lib
.Repository
;
22 import org
.eclipse
.jgit
.lib
.RepositoryState
;
23 import org
.eclipse
.jgit
.revwalk
.RevCommit
;
24 import org
.eclipse
.jgit
.revwalk
.RevWalk
;
25 import org
.eclipse
.jgit
.revwalk
.filter
.RevFilter
;
26 import org
.eclipse
.jgit
.treewalk
.filter
.AndTreeFilter
;
27 import org
.eclipse
.jgit
.treewalk
.filter
.PathFilter
;
28 import org
.eclipse
.jgit
.treewalk
.filter
.TreeFilter
;
31 * Utility class for obtaining Rev object instances.
33 public class RevUtils
{
36 // non instanciable utility class
40 * Finds and returns instance of common ancestor commit for given to
43 * @param repo repository in which common ancestor should be searched, cannot be null
44 * @param commit1 left commit id, cannot be null
45 * @param commit2 right commit id, cannot be null
46 * @return common ancestor for commit1 and commit2 parameters
49 public static RevCommit
getCommonAncestor(Repository repo
,
50 AnyObjectId commit1
, AnyObjectId commit2
) throws IOException
{
51 Assert
.isNotNull(repo
);
52 Assert
.isNotNull(commit1
);
53 Assert
.isNotNull(commit2
);
55 try (RevWalk rw
= new RevWalk(repo
)) {
56 rw
.setRetainBody(false);
57 rw
.setRevFilter(RevFilter
.MERGE_BASE
);
59 RevCommit srcRev
= rw
.lookupCommit(commit1
);
60 RevCommit dstRev
= rw
.lookupCommit(commit2
);
65 RevCommit result
= rw
.next();
78 * repository-relative path of file with conflicts
79 * @return an object with the interesting commits for this path
82 public static ConflictCommits
getConflictCommits(Repository repository
,
83 String path
) throws IOException
{
84 try (RevWalk walk
= new RevWalk(repository
)) {
86 RevCommit theirCommit
= null;
87 walk
.setTreeFilter(AndTreeFilter
.create(PathFilter
.create(path
),
88 TreeFilter
.ANY_DIFF
));
90 RevCommit head
= walk
.parseCommit(repository
91 .resolve(Constants
.HEAD
));
94 ourCommit
= walk
.next();
96 RepositoryState state
= repository
.getRepositoryState();
97 if (state
== RepositoryState
.REBASING
98 || state
== RepositoryState
.CHERRY_PICKING
) {
99 ObjectId cherryPickHead
= repository
.readCherryPickHead();
100 if (cherryPickHead
!= null) {
101 RevCommit cherryPickCommit
= walk
.parseCommit(cherryPickHead
);
102 theirCommit
= cherryPickCommit
;
104 } else if (state
== RepositoryState
.MERGING
) {
105 List
<ObjectId
> mergeHeads
= repository
.readMergeHeads();
106 if (mergeHeads
.size() == 1) {
107 ObjectId mergeHead
= mergeHeads
.get(0);
108 RevCommit mergeCommit
= walk
.parseCommit(mergeHead
);
110 walk
.markStart(mergeCommit
);
111 theirCommit
= walk
.next();
115 return new ConflictCommits(ourCommit
, theirCommit
);
120 * Check if commit is contained in any of the passed refs.
123 * the repo the commit is in
125 * the commit ID to search for
128 * @return true if the commit is contained, false otherwise
129 * @throws IOException
131 public static boolean isContainedInAnyRef(Repository repo
,
132 ObjectId commitId
, Collection
<Ref
> refs
) throws IOException
{
133 // It's likely that we don't have to walk commits at all, so
134 // check refs directly first.
136 if (commitId
.equals(ref
.getObjectId()))
139 final int skew
= 24 * 60 * 60; // one day clock skew
141 try (RevWalk walk
= new RevWalk(repo
)) {
142 RevCommit commit
= walk
.parseCommit(commitId
);
143 for (Ref ref
: refs
) {
144 RevCommit refCommit
= walk
.parseCommit(ref
.getObjectId());
146 // if commit is in the ref branch, then the tip of ref should be
147 // newer than the commit we are looking for. Allow for a large
149 if (refCommit
.getCommitTime() + skew
< commit
.getCommitTime())
152 boolean contained
= walk
.isMergedInto(commit
, refCommit
);
162 * The interesting commits from ours/theirs for a file in case of a
165 public static class ConflictCommits
{
166 private final RevCommit ourCommit
;
167 private final RevCommit theirCommit
;
169 private ConflictCommits(RevCommit ourCommit
, RevCommit theirCommit
) {
170 this.ourCommit
= ourCommit
;
171 this.theirCommit
= theirCommit
;
175 * @return the commit from "ours" that last modified a file, or
176 * {@code null} if none found
178 public RevCommit
getOurCommit() {
183 * @return the commit from "theirs" that last modified a file, or
184 * {@code null} if none found
186 public RevCommit
getTheirCommit() {