Use try-with-resource to avoid leaks with RevWalk and TreeWalk
[egit/eclipse.git] / org.eclipse.egit.core / src / org / eclipse / egit / core / RevUtils.java
blobc5e35a8f070741ec53dae64bf26c7f7957c368c2
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;
30 /**
31 * Utility class for obtaining Rev object instances.
33 public class RevUtils {
35 private RevUtils() {
36 // non instanciable utility class
39 /**
40 * Finds and returns instance of common ancestor commit for given to
41 * commit's
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
47 * @throws IOException
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);
62 rw.markStart(dstRev);
63 rw.markStart(srcRev);
65 RevCommit result = rw.next();
66 if (result != null) {
67 rw.parseBody(result);
68 return result;
69 } else {
70 return null;
75 /**
76 * @param repository
77 * @param path
78 * repository-relative path of file with conflicts
79 * @return an object with the interesting commits for this path
80 * @throws IOException
82 public static ConflictCommits getConflictCommits(Repository repository,
83 String path) throws IOException {
84 try (RevWalk walk = new RevWalk(repository)) {
85 RevCommit ourCommit;
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));
92 walk.markStart(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);
109 walk.reset();
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.
122 * @param repo
123 * the repo the commit is in
124 * @param commitId
125 * the commit ID to search for
126 * @param refs
127 * the refs to check
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.
135 for (Ref ref : refs)
136 if (commitId.equals(ref.getObjectId()))
137 return true;
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
148 // clock skew.
149 if (refCommit.getCommitTime() + skew < commit.getCommitTime())
150 continue;
152 boolean contained = walk.isMergedInto(commit, refCommit);
153 if (contained)
154 return true;
156 walk.dispose();
158 return false;
162 * The interesting commits from ours/theirs for a file in case of a
163 * conflict.
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() {
179 return ourCommit;
183 * @return the commit from "theirs" that last modified a file, or
184 * {@code null} if none found
186 public RevCommit getTheirCommit() {
187 return theirCommit;