1 /*
2 * Copyright (C) 2011-2012, Robin Stocker <robin@nibor.org> and others
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Distribution License v. 1.0 which is available at
6 * https://www.eclipse.org/org/documents/edl-v10.php.
7 *
8 * SPDX-License-Identifier: BSD-3-Clause
9 */
10
11 package org.eclipse.jgit.revwalk;
12
13 import java.io.IOException;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.List;
17
18 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
19 import org.eclipse.jgit.errors.MissingObjectException;
20 import org.eclipse.jgit.internal.JGitText;
21 import org.eclipse.jgit.lib.NullProgressMonitor;
22 import org.eclipse.jgit.lib.ProgressMonitor;
23 import org.eclipse.jgit.lib.Ref;
24
25 /**
26 * Utility methods for {@link org.eclipse.jgit.revwalk.RevWalk}.
27 */
28 public final class RevWalkUtils {
29
30 private RevWalkUtils() {
31 // Utility class
32 }
33
34 /**
35 * Count the number of commits that are reachable from <code>start</code>
36 * until a commit that is reachable from <code>end</code> is encountered. In
37 * other words, count the number of commits that are in <code>start</code>,
38 * but not in <code>end</code>.
39 * <p>
40 * Note that this method calls
41 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning. Also
42 * note that the existing rev filter on the walk is left as-is, so be sure
43 * to set the right rev filter before calling this method.
44 *
45 * @param walk
46 * the rev walk to use
47 * @param start
48 * the commit to start counting from
49 * @param end
50 * the commit where counting should end, or null if counting
51 * should be done until there are no more commits
52 * @return the number of commits
53 * @throws org.eclipse.jgit.errors.MissingObjectException
54 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
55 * @throws java.io.IOException
56 */
57 public static int count(final RevWalk walk, final RevCommit start,
58 final RevCommit end) throws MissingObjectException,
59 IncorrectObjectTypeException, IOException {
60 return find(walk, start, end).size();
61 }
62
63 /**
64 * Find commits that are reachable from <code>start</code> until a commit
65 * that is reachable from <code>end</code> is encountered. In other words,
66 * Find of commits that are in <code>start</code>, but not in
67 * <code>end</code>.
68 * <p>
69 * Note that this method calls
70 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning. Also
71 * note that the existing rev filter on the walk is left as-is, so be sure
72 * to set the right rev filter before calling this method.
73 *
74 * @param walk
75 * the rev walk to use
76 * @param start
77 * the commit to start counting from
78 * @param end
79 * the commit where counting should end, or null if counting
80 * should be done until there are no more commits
81 * @return the commits found
82 * @throws org.eclipse.jgit.errors.MissingObjectException
83 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
84 * @throws java.io.IOException
85 */
86 public static List<RevCommit> find(final RevWalk walk,
87 final RevCommit start, final RevCommit end)
88 throws MissingObjectException, IncorrectObjectTypeException,
89 IOException {
90 walk.reset();
91 walk.markStart(start);
92 if (end != null)
93 walk.markUninteresting(end);
94
95 List<RevCommit> commits = new ArrayList<>();
96 for (RevCommit c : walk)
97 commits.add(c);
98 return commits;
99 }
100
101 /**
102 * Find the list of branches a given commit is reachable from when following
103 * parents.
104 * <p>
105 * Note that this method calls
106 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning.
107 * <p>
108 * In order to improve performance this method assumes clock skew among
109 * committers is never larger than 24 hours.
110 *
111 * @param commit
112 * the commit we are looking at
113 * @param revWalk
114 * The RevWalk to be used.
115 * @param refs
116 * the set of branches we want to see reachability from
117 * @return the list of branches a given commit is reachable from
118 * @throws org.eclipse.jgit.errors.MissingObjectException
119 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
120 * @throws java.io.IOException
121 */
122 public static List<Ref> findBranchesReachableFrom(RevCommit commit,
123 RevWalk revWalk, Collection<Ref> refs)
124 throws MissingObjectException, IncorrectObjectTypeException,
125 IOException {
126 return findBranchesReachableFrom(commit, revWalk, refs,
127 NullProgressMonitor.INSTANCE);
128 }
129
130 /**
131 * Find the list of branches a given commit is reachable from when following
132 * parents.
133 * <p>
134 * Note that this method calls
135 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning.
136 * <p>
137 * In order to improve performance this method assumes clock skew among
138 * committers is never larger than 24 hours.
139 *
140 * @param commit
141 * the commit we are looking at
142 * @param revWalk
143 * The RevWalk to be used.
144 * @param refs
145 * the set of branches we want to see reachability from
146 * @param monitor
147 * the callback for progress and cancellation
148 * @return the list of branches a given commit is reachable from
149 * @throws org.eclipse.jgit.errors.MissingObjectException
150 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
151 * @throws java.io.IOException
152 * @since 5.4
153 */
154 public static List<Ref> findBranchesReachableFrom(RevCommit commit,
155 RevWalk revWalk, Collection<Ref> refs, ProgressMonitor monitor)
156 throws MissingObjectException, IncorrectObjectTypeException,
157 IOException {
158
159 // Make sure commit is from the same RevWalk
160 commit = revWalk.parseCommit(commit.getId());
161 revWalk.reset();
162 List<Ref> filteredRefs = new ArrayList<>();
163 monitor.beginTask(JGitText.get().searchForReachableBranches,
164 refs.size());
165 final int SKEW = 24*3600; // one day clock skew
166
167 for (Ref ref : refs) {
168 RevObject maybehead = revWalk.parseAny(ref.getObjectId());
169 if (!(maybehead instanceof RevCommit))
170 continue;
171 RevCommit headCommit = (RevCommit) maybehead;
172
173 // if commit is in the ref branch, then the tip of ref should be
174 // newer than the commit we are looking for. Allow for a large
175 // clock skew.
176 if (headCommit.getCommitTime() + SKEW < commit.getCommitTime())
177 continue;
178
179 filteredRefs.add(ref);
180 }
181 List<Ref> result = revWalk.getMergedInto(commit, filteredRefs, monitor);
182 monitor.endTask();
183 return result;
184 }
185
186 }