View Javadoc
1   /*
2    * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
3    * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
4    * Copyright (C) 2014, Gustaf Lundh <gustaf.lundh@sonymobile.com> and others
5    *
6    * This program and the accompanying materials are made available under the
7    * terms of the Eclipse Distribution License v. 1.0 which is available at
8    * https://www.eclipse.org/org/documents/edl-v10.php.
9    *
10   * SPDX-License-Identifier: BSD-3-Clause
11   */
12  
13  package org.eclipse.jgit.revwalk;
14  
15  import java.io.IOException;
16  import java.text.MessageFormat;
17  import java.util.ArrayList;
18  import java.util.Collection;
19  import java.util.EnumSet;
20  import java.util.Iterator;
21  import java.util.List;
22  
23  import org.eclipse.jgit.annotations.NonNull;
24  import org.eclipse.jgit.annotations.Nullable;
25  import org.eclipse.jgit.errors.CorruptObjectException;
26  import org.eclipse.jgit.errors.IncorrectObjectTypeException;
27  import org.eclipse.jgit.errors.LargeObjectException;
28  import org.eclipse.jgit.errors.MissingObjectException;
29  import org.eclipse.jgit.errors.RevWalkException;
30  import org.eclipse.jgit.internal.JGitText;
31  import org.eclipse.jgit.lib.AnyObjectId;
32  import org.eclipse.jgit.lib.AsyncObjectLoaderQueue;
33  import org.eclipse.jgit.lib.Constants;
34  import org.eclipse.jgit.lib.MutableObjectId;
35  import org.eclipse.jgit.lib.NullProgressMonitor;
36  import org.eclipse.jgit.lib.ObjectId;
37  import org.eclipse.jgit.lib.ObjectIdOwnerMap;
38  import org.eclipse.jgit.lib.ObjectLoader;
39  import org.eclipse.jgit.lib.ObjectReader;
40  import org.eclipse.jgit.lib.ProgressMonitor;
41  import org.eclipse.jgit.lib.Ref;
42  import org.eclipse.jgit.lib.Repository;
43  import org.eclipse.jgit.revwalk.filter.RevFilter;
44  import org.eclipse.jgit.treewalk.filter.TreeFilter;
45  import org.eclipse.jgit.util.References;
46  
47  /**
48   * Walks a commit graph and produces the matching commits in order.
49   * <p>
50   * A RevWalk instance can only be used once to generate results. Running a
51   * second time requires creating a new RevWalk instance, or invoking
52   * {@link #reset()} before starting again. Resetting an existing instance may be
53   * faster for some applications as commit body parsing can be avoided on the
54   * later invocations.
55   * <p>
56   * RevWalk instances are not thread-safe. Applications must either restrict
57   * usage of a RevWalk instance to a single thread, or implement their own
58   * synchronization at a higher level.
59   * <p>
60   * Multiple simultaneous RevWalk instances per
61   * {@link org.eclipse.jgit.lib.Repository} are permitted, even from concurrent
62   * threads. Equality of {@link org.eclipse.jgit.revwalk.RevCommit}s from two
63   * different RevWalk instances is never true, even if their
64   * {@link org.eclipse.jgit.lib.ObjectId}s are equal (and thus they describe the
65   * same commit).
66   * <p>
67   * The offered iterator is over the list of RevCommits described by the
68   * configuration of this instance. Applications should restrict themselves to
69   * using either the provided Iterator or {@link #next()}, but never use both on
70   * the same RevWalk at the same time. The Iterator may buffer RevCommits, while
71   * {@link #next()} does not.
72   */
73  public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
74  	private static final int MB = 1 << 20;
75  
76  	/**
77  	 * Set on objects whose important header data has been loaded.
78  	 * <p>
79  	 * For a RevCommit this indicates we have pulled apart the tree and parent
80  	 * references from the raw bytes available in the repository and translated
81  	 * those to our own local RevTree and RevCommit instances. The raw buffer is
82  	 * also available for message and other header filtering.
83  	 * <p>
84  	 * For a RevTag this indicates we have pulled part the tag references to
85  	 * find out who the tag refers to, and what that object's type is.
86  	 */
87  	static final int PARSED = 1 << 0;
88  
89  	/**
90  	 * Set on RevCommit instances added to our {@link #pending} queue.
91  	 * <p>
92  	 * We use this flag to avoid adding the same commit instance twice to our
93  	 * queue, especially if we reached it by more than one path.
94  	 */
95  	static final int SEEN = 1 << 1;
96  
97  	/**
98  	 * Set on RevCommit instances the caller does not want output.
99  	 * <p>
100 	 * We flag commits as uninteresting if the caller does not want commits
101 	 * reachable from a commit given to {@link #markUninteresting(RevCommit)}.
102 	 * This flag is always carried into the commit's parents and is a key part
103 	 * of the "rev-list B --not A" feature; A is marked UNINTERESTING.
104 	 */
105 	static final int UNINTERESTING = 1 << 2;
106 
107 	/**
108 	 * Set on a RevCommit that can collapse out of the history.
109 	 * <p>
110 	 * If the {@link #treeFilter} concluded that this commit matches his
111 	 * parents' for all of the paths that the filter is interested in then we
112 	 * mark the commit REWRITE. Later we can rewrite the parents of a REWRITE
113 	 * child to remove chains of REWRITE commits before we produce the child to
114 	 * the application.
115 	 *
116 	 * @see RewriteGenerator
117 	 */
118 	static final int REWRITE = 1 << 3;
119 
120 	/**
121 	 * Temporary mark for use within generators or filters.
122 	 * <p>
123 	 * This mark is only for local use within a single scope. If someone sets
124 	 * the mark they must unset it before any other code can see the mark.
125 	 */
126 	static final int TEMP_MARK = 1 << 4;
127 
128 	/**
129 	 * Temporary mark for use within {@link TopoSortGenerator}.
130 	 * <p>
131 	 * This mark indicates the commit could not produce when it wanted to, as at
132 	 * least one child was behind it. Commits with this flag are delayed until
133 	 * all children have been output first.
134 	 */
135 	static final int TOPO_DELAY = 1 << 5;
136 
137 	/**
138 	 * Temporary mark for use within {@link TopoNonIntermixSortGenerator}.
139 	 * <p>
140 	 * This mark indicates the commit has been queued for emission in
141 	 * {@link TopoSortGenerator} and can be produced. This mark is removed when
142 	 * the commit has been produced.
143 	 */
144 	static final int TOPO_QUEUED = 1 << 6;
145 
146 	/** Number of flag bits we keep internal for our own use. See above flags. */
147 	static final int RESERVED_FLAGS = 7;
148 
149 	private static final int APP_FLAGS = -1 & ~((1 << RESERVED_FLAGS) - 1);
150 
151 	final ObjectReader reader;
152 
153 	private final boolean closeReader;
154 
155 	final MutableObjectId idBuffer;
156 
157 	ObjectIdOwnerMap<RevObject> objects;
158 
159 	int freeFlags = APP_FLAGS;
160 
161 	private int delayFreeFlags;
162 
163 	private int retainOnReset;
164 
165 	int carryFlags = UNINTERESTING;
166 
167 	final ArrayList<RevCommit> roots;
168 
169 	AbstractRevQueue queue;
170 
171 	Generator pending;
172 
173 	private final EnumSet<RevSort> sorting;
174 
175 	private RevFilter filter;
176 
177 	private TreeFilter treeFilter;
178 
179 	private boolean retainBody = true;
180 
181 	private boolean rewriteParents = true;
182 
183 	private boolean firstParent;
184 
185 	boolean shallowCommitsInitialized;
186 
187 	private enum GetMergedIntoStrategy {
188 		RETURN_ON_FIRST_FOUND,
189 		RETURN_ON_FIRST_NOT_FOUND,
190 		EVALUATE_ALL
191 	}
192 
193 	/**
194 	 * Create a new revision walker for a given repository.
195 	 *
196 	 * @param repo
197 	 *            the repository the walker will obtain data from. An
198 	 *            ObjectReader will be created by the walker, and will be closed
199 	 *            when the walker is closed.
200 	 */
201 	public RevWalk(Repository repo) {
202 		this(repo.newObjectReader(), true);
203 	}
204 
205 	/**
206 	 * Create a new revision walker for a given repository.
207 	 * <p>
208 	 *
209 	 * @param or
210 	 *            the reader the walker will obtain data from. The reader is not
211 	 *            closed when the walker is closed (but is closed by {@link
212 	 *            #dispose()}.
213 	 */
214 	public RevWalk(ObjectReader or) {
215 		this(or, false);
216 	}
217 
218 	private RevWalk(ObjectReader or, boolean closeReader) {
219 		reader = or;
220 		idBuffer = new MutableObjectId();
221 		objects = new ObjectIdOwnerMap<>();
222 		roots = new ArrayList<>();
223 		queue = new DateRevQueue(false);
224 		pending = new StartGenerator(this);
225 		sorting = EnumSet.of(RevSort.NONE);
226 		filter = RevFilter.ALL;
227 		treeFilter = TreeFilter.ALL;
228 		this.closeReader = closeReader;
229 	}
230 
231 	/**
232 	 * Get the reader this walker is using to load objects.
233 	 *
234 	 * @return the reader this walker is using to load objects.
235 	 */
236 	public ObjectReader getObjectReader() {
237 		return reader;
238 	}
239 
240 	/**
241 	 * Get a reachability checker for commits over this revwalk.
242 	 *
243 	 * @return the most efficient reachability checker for this repository.
244 	 * @throws IOException
245 	 *             if it cannot open any of the underlying indices.
246 	 *
247 	 * @since 5.4
248 	 * @deprecated use {@code ObjectReader#createReachabilityChecker(RevWalk)}
249 	 *             instead.
250 	 */
251 	@Deprecated
252 	public final ReachabilityChecker createReachabilityChecker()
253 			throws IOException {
254 		return reader.createReachabilityChecker(this);
255 	}
256 
257 	/**
258 	 * {@inheritDoc}
259 	 * <p>
260 	 * Release any resources used by this walker's reader.
261 	 * <p>
262 	 * A walker that has been released can be used again, but may need to be
263 	 * released after the subsequent usage.
264 	 *
265 	 * @since 4.0
266 	 */
267 	@Override
268 	public void close() {
269 		if (closeReader) {
270 			reader.close();
271 		}
272 	}
273 
274 	/**
275 	 * Mark a commit to start graph traversal from.
276 	 * <p>
277 	 * Callers are encouraged to use {@link #parseCommit(AnyObjectId)} to obtain
278 	 * the commit reference, rather than {@link #lookupCommit(AnyObjectId)}, as
279 	 * this method requires the commit to be parsed before it can be added as a
280 	 * root for the traversal.
281 	 * <p>
282 	 * The method will automatically parse an unparsed commit, but error
283 	 * handling may be more difficult for the application to explain why a
284 	 * RevCommit is not actually a commit. The object pool of this walker would
285 	 * also be 'poisoned' by the non-commit RevCommit.
286 	 *
287 	 * @param c
288 	 *            the commit to start traversing from. The commit passed must be
289 	 *            from this same revision walker.
290 	 * @throws org.eclipse.jgit.errors.MissingObjectException
291 	 *             the commit supplied is not available from the object
292 	 *             database. This usually indicates the supplied commit is
293 	 *             invalid, but the reference was constructed during an earlier
294 	 *             invocation to {@link #lookupCommit(AnyObjectId)}.
295 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
296 	 *             the object was not parsed yet and it was discovered during
297 	 *             parsing that it is not actually a commit. This usually
298 	 *             indicates the caller supplied a non-commit SHA-1 to
299 	 *             {@link #lookupCommit(AnyObjectId)}.
300 	 * @throws java.io.IOException
301 	 *             a pack file or loose object could not be read.
302 	 */
303 	public void markStart(RevCommit c) throws MissingObjectException,
304 			IncorrectObjectTypeException, IOException {
305 		if ((c.flags & SEEN) != 0)
306 			return;
307 		if ((c.flags & PARSED) == 0)
308 			c.parseHeaders(this);
309 		c.flags |= SEEN;
310 		roots.add(c);
311 		queue.add(c);
312 	}
313 
314 	/**
315 	 * Mark commits to start graph traversal from.
316 	 *
317 	 * @param list
318 	 *            commits to start traversing from. The commits passed must be
319 	 *            from this same revision walker.
320 	 * @throws org.eclipse.jgit.errors.MissingObjectException
321 	 *             one of the commits supplied is not available from the object
322 	 *             database. This usually indicates the supplied commit is
323 	 *             invalid, but the reference was constructed during an earlier
324 	 *             invocation to {@link #lookupCommit(AnyObjectId)}.
325 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
326 	 *             the object was not parsed yet and it was discovered during
327 	 *             parsing that it is not actually a commit. This usually
328 	 *             indicates the caller supplied a non-commit SHA-1 to
329 	 *             {@link #lookupCommit(AnyObjectId)}.
330 	 * @throws java.io.IOException
331 	 *             a pack file or loose object could not be read.
332 	 */
333 	public void markStart(Collection<RevCommit> list)
334 			throws MissingObjectException, IncorrectObjectTypeException,
335 			IOException {
336 		for (RevCommit c : list)
337 			markStart(c);
338 	}
339 
340 	/**
341 	 * Mark a commit to not produce in the output.
342 	 * <p>
343 	 * Uninteresting commits denote not just themselves but also their entire
344 	 * ancestry chain, back until the merge base of an uninteresting commit and
345 	 * an otherwise interesting commit.
346 	 * <p>
347 	 * Callers are encouraged to use {@link #parseCommit(AnyObjectId)} to obtain
348 	 * the commit reference, rather than {@link #lookupCommit(AnyObjectId)}, as
349 	 * this method requires the commit to be parsed before it can be added as a
350 	 * root for the traversal.
351 	 * <p>
352 	 * The method will automatically parse an unparsed commit, but error
353 	 * handling may be more difficult for the application to explain why a
354 	 * RevCommit is not actually a commit. The object pool of this walker would
355 	 * also be 'poisoned' by the non-commit RevCommit.
356 	 *
357 	 * @param c
358 	 *            the commit to start traversing from. The commit passed must be
359 	 *            from this same revision walker.
360 	 * @throws org.eclipse.jgit.errors.MissingObjectException
361 	 *             the commit supplied is not available from the object
362 	 *             database. This usually indicates the supplied commit is
363 	 *             invalid, but the reference was constructed during an earlier
364 	 *             invocation to {@link #lookupCommit(AnyObjectId)}.
365 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
366 	 *             the object was not parsed yet and it was discovered during
367 	 *             parsing that it is not actually a commit. This usually
368 	 *             indicates the caller supplied a non-commit SHA-1 to
369 	 *             {@link #lookupCommit(AnyObjectId)}.
370 	 * @throws java.io.IOException
371 	 *             a pack file or loose object could not be read.
372 	 */
373 	public void markUninteresting(RevCommit c)
374 			throws MissingObjectException, IncorrectObjectTypeException,
375 			IOException {
376 		c.flags |= UNINTERESTING;
377 		carryFlagsImpl(c);
378 		markStart(c);
379 	}
380 
381 	/**
382 	 * Determine if a commit is reachable from another commit.
383 	 * <p>
384 	 * A commit <code>base</code> is an ancestor of <code>tip</code> if we
385 	 * can find a path of commits that leads from <code>tip</code> and ends at
386 	 * <code>base</code>.
387 	 * <p>
388 	 * This utility function resets the walker, inserts the two supplied
389 	 * commits, and then executes a walk until an answer can be obtained.
390 	 * Currently allocated RevFlags that have been added to RevCommit instances
391 	 * will be retained through the reset.
392 	 *
393 	 * @param base
394 	 *            commit the caller thinks is reachable from <code>tip</code>.
395 	 * @param tip
396 	 *            commit to start iteration from, and which is most likely a
397 	 *            descendant (child) of <code>base</code>.
398 	 * @return true if there is a path directly from <code>tip</code> to
399 	 *         <code>base</code> (and thus <code>base</code> is fully merged
400 	 *         into <code>tip</code>); false otherwise.
401 	 * @throws org.eclipse.jgit.errors.MissingObjectException
402 	 *             one or more of the next commit's parents are not available
403 	 *             from the object database, but were thought to be candidates
404 	 *             for traversal. This usually indicates a broken link.
405 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
406 	 *             one or more of the next commit's parents are not actually
407 	 *             commit objects.
408 	 * @throws java.io.IOException
409 	 *             a pack file or loose object could not be read.
410 	 */
411 	public boolean isMergedInto(RevCommit base, RevCommit tip)
412 			throws MissingObjectException, IncorrectObjectTypeException,
413 			IOException {
414 		final RevFilter oldRF = filter;
415 		final TreeFilter oldTF = treeFilter;
416 		try {
417 			finishDelayedFreeFlags();
418 			reset(~freeFlags & APP_FLAGS);
419 			filter = RevFilter.MERGE_BASE;
420 			treeFilter = TreeFilter.ALL;
421 			markStart(tip);
422 			markStart(base);
423 			RevCommit mergeBase;
424 			while ((mergeBase = next()) != null) {
425 				if (References.isSameObject(mergeBase, base)) {
426 					return true;
427 				}
428 			}
429 			return false;
430 		} finally {
431 			filter = oldRF;
432 			treeFilter = oldTF;
433 		}
434 	}
435 
436 	/**
437 	 * Determine the Refs into which a commit is merged.
438 	 * <p>
439 	 * A commit is merged into a ref if we can find a path of commits that leads
440 	 * from that specific ref and ends at <code>commit</code>.
441 	 * <p>
442 	 *
443 	 * @param commit
444 	 *            commit the caller thinks is reachable from <code>refs</code>.
445 	 * @param refs
446 	 *            refs to start iteration from, and which is most likely a
447 	 *            descendant (child) of <code>commit</code>.
448 	 * @return list of refs that are reachable from <code>commit</code>.
449 	 * @throws java.io.IOException
450 	 *             a pack file or loose object could not be read.
451 	 * @since 5.12
452 	 */
453 	public List<Ref> getMergedInto(RevCommit commit, Collection<Ref> refs)
454 			throws IOException{
455 		return getMergedInto(commit, refs, NullProgressMonitor.INSTANCE);
456 	}
457 
458 	/**
459 	 * Determine the Refs into which a commit is merged.
460 	 * <p>
461 	 * A commit is merged into a ref if we can find a path of commits that leads
462 	 * from that specific ref and ends at <code>commit</code>.
463 	 * <p>
464 	 *
465 	 * @param commit
466 	 *            commit the caller thinks is reachable from <code>refs</code>.
467 	 * @param refs
468 	 *            refs to start iteration from, and which is most likely a
469 	 *            descendant (child) of <code>commit</code>.
470 	 * @param monitor
471 	 *            the callback for progress and cancellation
472 	 * @return list of refs that are reachable from <code>commit</code>.
473 	 * @throws java.io.IOException
474 	 *             a pack file or loose object could not be read.
475 	 * @since 5.12
476 	 */
477 	public List<Ref> getMergedInto(RevCommit commit, Collection<Ref> refs,
478 					ProgressMonitor monitor) throws IOException{
479 		return getMergedInto(commit, refs,
480 				GetMergedIntoStrategy.EVALUATE_ALL,
481 				monitor);
482 	}
483 
484 	/**
485 	 * Determine if a <code>commit</code> is merged into any of the given
486 	 * <code>refs</code>.
487 	 *
488 	 * @param commit
489 	 *            commit the caller thinks is reachable from <code>refs</code>.
490 	 * @param refs
491 	 *            refs to start iteration from, and which is most likely a
492 	 *            descendant (child) of <code>commit</code>.
493 	 * @return true if commit is merged into any of the refs; false otherwise.
494 	 * @throws java.io.IOException
495 	 *             a pack file or loose object could not be read.
496 	 * @since 5.12
497 	 */
498 	public boolean isMergedIntoAny(RevCommit commit, Collection<Ref> refs)
499 			throws IOException {
500 		return getMergedInto(commit, refs,
501 				GetMergedIntoStrategy.RETURN_ON_FIRST_FOUND,
502 				NullProgressMonitor.INSTANCE).size() > 0;
503 	}
504 
505 	/**
506 	 * Determine if a <code>commit</code> is merged into all of the given
507 	 * <code>refs</code>.
508 	 *
509 	 * @param commit
510 	 *            commit the caller thinks is reachable from <code>refs</code>.
511 	 * @param refs
512 	 *            refs to start iteration from, and which is most likely a
513 	 *            descendant (child) of <code>commit</code>.
514 	 * @return true if commit is merged into all of the refs; false otherwise.
515 	 * @throws java.io.IOException
516 	 *             a pack file or loose object could not be read.
517 	 * @since 5.12
518 	 */
519 	public boolean isMergedIntoAll(RevCommit commit, Collection<Ref> refs)
520 			throws IOException {
521 		return getMergedInto(commit, refs,
522 				GetMergedIntoStrategy.RETURN_ON_FIRST_NOT_FOUND,
523 				NullProgressMonitor.INSTANCE).size()
524 				== refs.size();
525 	}
526 
527 	private List<Ref> getMergedInto(RevCommit needle, Collection<Ref> haystacks,
528 				Enum returnStrategy, ProgressMonitor monitor) throws IOException {
529 		List<Ref> result = new ArrayList<>();
530 		List<RevCommit> uninteresting = new ArrayList<>();
531 		List<RevCommit> marked = new ArrayList<>();
532 		RevFilter oldRF = filter;
533 		TreeFilter oldTF = treeFilter;
534 		try {
535 			finishDelayedFreeFlags();
536 			reset(~freeFlags & APP_FLAGS);
537 			filter = RevFilter.ALL;
538 			treeFilter = TreeFilter.ALL;
539 			for (Ref r: haystacks) {
540 				if (monitor.isCancelled()) {
541 					return result;
542 				}
543 				monitor.update(1);
544 				RevObject o = peel(parseAny(r.getObjectId()));
545 				if (!(o instanceof RevCommit)) {
546 					continue;
547 				}
548 				RevCommit c = (RevCommit) o;
549 				reset(UNINTERESTING | TEMP_MARK);
550 				markStart(c);
551 				boolean commitFound = false;
552 				RevCommit next;
553 				while ((next = next()) != null) {
554 					if (References.isSameObject(next, needle)
555 							|| (next.flags & TEMP_MARK) != 0) {
556 						result.add(r);
557 						if (returnStrategy == GetMergedIntoStrategy.RETURN_ON_FIRST_FOUND) {
558 							return result;
559 						}
560 						commitFound = true;
561 						c.flags |= TEMP_MARK;
562 						marked.add(c);
563 						break;
564 					}
565 				}
566 				if(!commitFound){
567 					markUninteresting(c);
568 					uninteresting.add(c);
569 					if (returnStrategy == GetMergedIntoStrategy.RETURN_ON_FIRST_NOT_FOUND) {
570 						return result;
571 					}
572 				}
573 			}
574 		} finally {
575 			roots.addAll(uninteresting);
576 			filter = oldRF;
577 			treeFilter = oldTF;
578 			for (RevCommit c : marked) {
579 				c.flags &= ~TEMP_MARK;
580 			}
581 		}
582 		return result;
583 	}
584 
585 	/**
586 	 * Pop the next most recent commit.
587 	 *
588 	 * @return next most recent commit; null if traversal is over.
589 	 * @throws org.eclipse.jgit.errors.MissingObjectException
590 	 *             one or more of the next commit's parents are not available
591 	 *             from the object database, but were thought to be candidates
592 	 *             for traversal. This usually indicates a broken link.
593 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
594 	 *             one or more of the next commit's parents are not actually
595 	 *             commit objects.
596 	 * @throws java.io.IOException
597 	 *             a pack file or loose object could not be read.
598 	 */
599 	public RevCommit next() throws MissingObjectException,
600 			IncorrectObjectTypeException, IOException {
601 		return pending.next();
602 	}
603 
604 	/**
605 	 * Obtain the sort types applied to the commits returned.
606 	 *
607 	 * @return the sorting strategies employed. At least one strategy is always
608 	 *         used, but that strategy may be
609 	 *         {@link org.eclipse.jgit.revwalk.RevSort#NONE}.
610 	 */
611 	public EnumSet<RevSort> getRevSort() {
612 		return sorting.clone();
613 	}
614 
615 	/**
616 	 * Check whether the provided sorting strategy is enabled.
617 	 *
618 	 * @param sort
619 	 *            a sorting strategy to look for.
620 	 * @return true if this strategy is enabled, false otherwise
621 	 */
622 	public boolean hasRevSort(RevSort sort) {
623 		return sorting.contains(sort);
624 	}
625 
626 	/**
627 	 * Select a single sorting strategy for the returned commits.
628 	 * <p>
629 	 * Disables all sorting strategies, then enables only the single strategy
630 	 * supplied by the caller.
631 	 *
632 	 * @param s
633 	 *            a sorting strategy to enable.
634 	 */
635 	public void sort(RevSort s) {
636 		assertNotStarted();
637 		sorting.clear();
638 		sorting.add(s);
639 	}
640 
641 	/**
642 	 * Add or remove a sorting strategy for the returned commits.
643 	 * <p>
644 	 * Multiple strategies can be applied at once, in which case some strategies
645 	 * may take precedence over others. As an example,
646 	 * {@link org.eclipse.jgit.revwalk.RevSort#TOPO} must take precedence over
647 	 * {@link org.eclipse.jgit.revwalk.RevSort#COMMIT_TIME_DESC}, otherwise it
648 	 * cannot enforce its ordering.
649 	 *
650 	 * @param s
651 	 *            a sorting strategy to enable or disable.
652 	 * @param use
653 	 *            true if this strategy should be used, false if it should be
654 	 *            removed.
655 	 */
656 	public void sort(RevSort s, boolean use) {
657 		assertNotStarted();
658 		if (use)
659 			sorting.add(s);
660 		else
661 			sorting.remove(s);
662 
663 		if (sorting.size() > 1)
664 			sorting.remove(RevSort.NONE);
665 		else if (sorting.isEmpty())
666 			sorting.add(RevSort.NONE);
667 	}
668 
669 	/**
670 	 * Get the currently configured commit filter.
671 	 *
672 	 * @return the current filter. Never null as a filter is always needed.
673 	 */
674 	@NonNull
675 	public RevFilter getRevFilter() {
676 		return filter;
677 	}
678 
679 	/**
680 	 * Set the commit filter for this walker.
681 	 * <p>
682 	 * Multiple filters may be combined by constructing an arbitrary tree of
683 	 * <code>AndRevFilter</code> or <code>OrRevFilter</code> instances to
684 	 * describe the boolean expression required by the application. Custom
685 	 * filter implementations may also be constructed by applications.
686 	 * <p>
687 	 * Note that filters are not thread-safe and may not be shared by concurrent
688 	 * RevWalk instances. Every RevWalk must be supplied its own unique filter,
689 	 * unless the filter implementation specifically states it is (and always
690 	 * will be) thread-safe. Callers may use
691 	 * {@link org.eclipse.jgit.revwalk.filter.RevFilter#clone()} to create a
692 	 * unique filter tree for this RevWalk instance.
693 	 *
694 	 * @param newFilter
695 	 *            the new filter. If null the special
696 	 *            {@link org.eclipse.jgit.revwalk.filter.RevFilter#ALL} filter
697 	 *            will be used instead, as it matches every commit.
698 	 * @see org.eclipse.jgit.revwalk.filter.AndRevFilter
699 	 * @see org.eclipse.jgit.revwalk.filter.OrRevFilter
700 	 */
701 	public void setRevFilter(RevFilter newFilter) {
702 		assertNotStarted();
703 		filter = newFilter != null ? newFilter : RevFilter.ALL;
704 	}
705 
706 	/**
707 	 * Get the tree filter used to simplify commits by modified paths.
708 	 *
709 	 * @return the current filter. Never null as a filter is always needed. If
710 	 *         no filter is being applied
711 	 *         {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ALL} is
712 	 *         returned.
713 	 */
714 	@NonNull
715 	public TreeFilter getTreeFilter() {
716 		return treeFilter;
717 	}
718 
719 	/**
720 	 * Set the tree filter used to simplify commits by modified paths.
721 	 * <p>
722 	 * If null or {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ALL} the
723 	 * path limiter is removed. Commits will not be simplified.
724 	 * <p>
725 	 * If non-null and not
726 	 * {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ALL} then the tree
727 	 * filter will be installed. Commits will have their ancestry simplified to
728 	 * hide commits that do not contain tree entries matched by the filter,
729 	 * unless {@code setRewriteParents(false)} is called.
730 	 * <p>
731 	 * Usually callers should be inserting a filter graph including
732 	 * {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ANY_DIFF} along with
733 	 * one or more {@link org.eclipse.jgit.treewalk.filter.PathFilter}
734 	 * instances.
735 	 *
736 	 * @param newFilter
737 	 *            new filter. If null the special
738 	 *            {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ALL} filter
739 	 *            will be used instead, as it matches everything.
740 	 * @see org.eclipse.jgit.treewalk.filter.PathFilter
741 	 */
742 	public void setTreeFilter(TreeFilter newFilter) {
743 		assertNotStarted();
744 		treeFilter = newFilter != null ? newFilter : TreeFilter.ALL;
745 	}
746 
747 	/**
748 	 * Set whether to rewrite parent pointers when filtering by modified paths.
749 	 * <p>
750 	 * By default, when {@link #setTreeFilter(TreeFilter)} is called with non-
751 	 * null and non-{@link org.eclipse.jgit.treewalk.filter.TreeFilter#ALL}
752 	 * filter, commits will have their ancestry simplified and parents rewritten
753 	 * to hide commits that do not match the filter.
754 	 * <p>
755 	 * This behavior can be bypassed by passing false to this method.
756 	 *
757 	 * @param rewrite
758 	 *            whether to rewrite parents; defaults to true.
759 	 * @since 3.4
760 	 */
761 	public void setRewriteParents(boolean rewrite) {
762 		rewriteParents = rewrite;
763 	}
764 
765 	boolean getRewriteParents() {
766 		return rewriteParents;
767 	}
768 
769 	/**
770 	 * Should the body of a commit or tag be retained after parsing its headers?
771 	 * <p>
772 	 * Usually the body is always retained, but some application code might not
773 	 * care and would prefer to discard the body of a commit as early as
774 	 * possible, to reduce memory usage.
775 	 * <p>
776 	 * True by default on {@link org.eclipse.jgit.revwalk.RevWalk} and false by
777 	 * default for {@link org.eclipse.jgit.revwalk.ObjectWalk}.
778 	 *
779 	 * @return true if the body should be retained; false it is discarded.
780 	 */
781 	public boolean isRetainBody() {
782 		return retainBody;
783 	}
784 
785 	/**
786 	 * Set whether or not the body of a commit or tag is retained.
787 	 * <p>
788 	 * If a body of a commit or tag is not retained, the application must call
789 	 * {@link #parseBody(RevObject)} before the body can be safely accessed
790 	 * through the type specific access methods.
791 	 * <p>
792 	 * True by default on {@link org.eclipse.jgit.revwalk.RevWalk} and false by
793 	 * default for {@link org.eclipse.jgit.revwalk.ObjectWalk}.
794 	 *
795 	 * @param retain
796 	 *            true to retain bodies; false to discard them early.
797 	 */
798 	public void setRetainBody(boolean retain) {
799 		retainBody = retain;
800 	}
801 
802 	/**
803 	 * @return whether only first-parent links should be followed when walking.
804 	 *
805 	 * @since 5.5
806 	 */
807 	public boolean isFirstParent() {
808 		return firstParent;
809 	}
810 
811 	/**
812 	 * Set whether or not only first parent links should be followed.
813 	 * <p>
814 	 * If set, second- and higher-parent links are not traversed at all.
815 	 * <p>
816 	 * This must be called prior to {@link #markStart(RevCommit)}.
817 	 *
818 	 * @param enable
819 	 *            true to walk only first-parent links.
820 	 *
821 	 * @since 5.5
822 	 */
823 	public void setFirstParent(boolean enable) {
824 		assertNotStarted();
825 		assertNoCommitsMarkedStart();
826 		firstParent = enable;
827 		queue = new DateRevQueue(firstParent);
828 		pending = new StartGenerator(this);
829 	}
830 
831 	/**
832 	 * Locate a reference to a blob without loading it.
833 	 * <p>
834 	 * The blob may or may not exist in the repository. It is impossible to tell
835 	 * from this method's return value.
836 	 *
837 	 * @param id
838 	 *            name of the blob object.
839 	 * @return reference to the blob object. Never null.
840 	 */
841 	@NonNull
842 	public RevBlob lookupBlob(AnyObjectId id) {
843 		RevBlob c = (RevBlob) objects.get(id);
844 		if (c == null) {
845 			c = new RevBlob(id);
846 			objects.add(c);
847 		}
848 		return c;
849 	}
850 
851 	/**
852 	 * Locate a reference to a tree without loading it.
853 	 * <p>
854 	 * The tree may or may not exist in the repository. It is impossible to tell
855 	 * from this method's return value.
856 	 *
857 	 * @param id
858 	 *            name of the tree object.
859 	 * @return reference to the tree object. Never null.
860 	 */
861 	@NonNull
862 	public RevTree lookupTree(AnyObjectId id) {
863 		RevTree c = (RevTree) objects.get(id);
864 		if (c == null) {
865 			c = new RevTree(id);
866 			objects.add(c);
867 		}
868 		return c;
869 	}
870 
871 	/**
872 	 * Locate a reference to a commit without loading it.
873 	 * <p>
874 	 * The commit may or may not exist in the repository. It is impossible to
875 	 * tell from this method's return value.
876 	 * <p>
877 	 * See {@link #parseHeaders(RevObject)} and {@link #parseBody(RevObject)}
878 	 * for loading contents.
879 	 *
880 	 * @param id
881 	 *            name of the commit object.
882 	 * @return reference to the commit object. Never null.
883 	 */
884 	@NonNull
885 	public RevCommit lookupCommit(AnyObjectId id) {
886 		RevCommit c = (RevCommit) objects.get(id);
887 		if (c == null) {
888 			c = createCommit(id);
889 			objects.add(c);
890 		}
891 		return c;
892 	}
893 
894 	/**
895 	 * Locate a reference to a tag without loading it.
896 	 * <p>
897 	 * The tag may or may not exist in the repository. It is impossible to tell
898 	 * from this method's return value.
899 	 *
900 	 * @param id
901 	 *            name of the tag object.
902 	 * @return reference to the tag object. Never null.
903 	 */
904 	@NonNull
905 	public RevTag lookupTag(AnyObjectId id) {
906 		RevTag c = (RevTag) objects.get(id);
907 		if (c == null) {
908 			c = new RevTag(id);
909 			objects.add(c);
910 		}
911 		return c;
912 	}
913 
914 	/**
915 	 * Locate a reference to any object without loading it.
916 	 * <p>
917 	 * The object may or may not exist in the repository. It is impossible to
918 	 * tell from this method's return value.
919 	 *
920 	 * @param id
921 	 *            name of the object.
922 	 * @param type
923 	 *            type of the object. Must be a valid Git object type.
924 	 * @return reference to the object. Never null.
925 	 */
926 	@NonNull
927 	public RevObject lookupAny(AnyObjectId id, int type) {
928 		RevObject r = objects.get(id);
929 		if (r == null) {
930 			switch (type) {
931 			case Constants.OBJ_COMMIT:
932 				r = createCommit(id);
933 				break;
934 			case Constants.OBJ_TREE:
935 				r = new RevTree(id);
936 				break;
937 			case Constants.OBJ_BLOB:
938 				r = new RevBlob(id);
939 				break;
940 			case Constants.OBJ_TAG:
941 				r = new RevTag(id);
942 				break;
943 			default:
944 				throw new IllegalArgumentException(MessageFormat.format(
945 						JGitText.get().invalidGitType, Integer.valueOf(type)));
946 			}
947 			objects.add(r);
948 		}
949 		return r;
950 	}
951 
952 	/**
953 	 * Locate an object that was previously allocated in this walk.
954 	 *
955 	 * @param id
956 	 *            name of the object.
957 	 * @return reference to the object if it has been previously located;
958 	 *         otherwise null.
959 	 */
960 	public RevObject lookupOrNull(AnyObjectId id) {
961 		return objects.get(id);
962 	}
963 
964 	/**
965 	 * Locate a reference to a commit and immediately parse its content.
966 	 * <p>
967 	 * Unlike {@link #lookupCommit(AnyObjectId)} this method only returns
968 	 * successfully if the commit object exists, is verified to be a commit, and
969 	 * was parsed without error.
970 	 *
971 	 * @param id
972 	 *            name of the commit object.
973 	 * @return reference to the commit object. Never null.
974 	 * @throws org.eclipse.jgit.errors.MissingObjectException
975 	 *             the supplied commit does not exist.
976 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
977 	 *             the supplied id is not a commit or an annotated tag.
978 	 * @throws java.io.IOException
979 	 *             a pack file or loose object could not be read.
980 	 */
981 	@NonNull
982 	public RevCommit parseCommit(AnyObjectId id)
983 			throws MissingObjectException, IncorrectObjectTypeException,
984 			IOException {
985 		RevObject c = peel(parseAny(id));
986 		if (!(c instanceof RevCommit))
987 			throw new IncorrectObjectTypeException(id.toObjectId(),
988 					Constants.TYPE_COMMIT);
989 		return (RevCommit) c;
990 	}
991 
992 	/**
993 	 * Locate a reference to a tree.
994 	 * <p>
995 	 * This method only returns successfully if the tree object exists, is
996 	 * verified to be a tree.
997 	 *
998 	 * @param id
999 	 *            name of the tree object, or a commit or annotated tag that may
1000 	 *            reference a tree.
1001 	 * @return reference to the tree object. Never null.
1002 	 * @throws org.eclipse.jgit.errors.MissingObjectException
1003 	 *             the supplied tree does not exist.
1004 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
1005 	 *             the supplied id is not a tree, a commit or an annotated tag.
1006 	 * @throws java.io.IOException
1007 	 *             a pack file or loose object could not be read.
1008 	 */
1009 	@NonNull
1010 	public RevTree parseTree(AnyObjectId id)
1011 			throws MissingObjectException, IncorrectObjectTypeException,
1012 			IOException {
1013 		RevObject c = peel(parseAny(id));
1014 
1015 		final RevTree t;
1016 		if (c instanceof RevCommit)
1017 			t = ((RevCommit) c).getTree();
1018 		else if (!(c instanceof RevTree))
1019 			throw new IncorrectObjectTypeException(id.toObjectId(),
1020 					Constants.TYPE_TREE);
1021 		else
1022 			t = (RevTree) c;
1023 		parseHeaders(t);
1024 		return t;
1025 	}
1026 
1027 	/**
1028 	 * Locate a reference to an annotated tag and immediately parse its content.
1029 	 * <p>
1030 	 * Unlike {@link #lookupTag(AnyObjectId)} this method only returns
1031 	 * successfully if the tag object exists, is verified to be a tag, and was
1032 	 * parsed without error.
1033 	 *
1034 	 * @param id
1035 	 *            name of the tag object.
1036 	 * @return reference to the tag object. Never null.
1037 	 * @throws org.eclipse.jgit.errors.MissingObjectException
1038 	 *             the supplied tag does not exist.
1039 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
1040 	 *             the supplied id is not a tag or an annotated tag.
1041 	 * @throws java.io.IOException
1042 	 *             a pack file or loose object could not be read.
1043 	 */
1044 	@NonNull
1045 	public RevTag parseTag(AnyObjectId id) throws MissingObjectException,
1046 			IncorrectObjectTypeException, IOException {
1047 		RevObject c = parseAny(id);
1048 		if (!(c instanceof RevTag))
1049 			throw new IncorrectObjectTypeException(id.toObjectId(),
1050 					Constants.TYPE_TAG);
1051 		return (RevTag) c;
1052 	}
1053 
1054 	/**
1055 	 * Locate a reference to any object and immediately parse its headers.
1056 	 * <p>
1057 	 * This method only returns successfully if the object exists and was parsed
1058 	 * without error. Parsing an object can be expensive as the type must be
1059 	 * determined. For blobs this may mean the blob content was unpacked
1060 	 * unnecessarily, and thrown away.
1061 	 *
1062 	 * @param id
1063 	 *            name of the object.
1064 	 * @return reference to the object. Never null.
1065 	 * @throws org.eclipse.jgit.errors.MissingObjectException
1066 	 *             the supplied does not exist.
1067 	 * @throws java.io.IOException
1068 	 *             a pack file or loose object could not be read.
1069 	 */
1070 	@NonNull
1071 	public RevObject parseAny(AnyObjectId id)
1072 			throws MissingObjectException, IOException {
1073 		RevObject r = objects.get(id);
1074 		if (r == null)
1075 			r = parseNew(id, reader.open(id));
1076 		else
1077 			parseHeaders(r);
1078 		return r;
1079 	}
1080 
1081 	private RevObject parseNew(AnyObjectId id, ObjectLoader ldr)
1082 			throws LargeObjectException, CorruptObjectException,
1083 			MissingObjectException, IOException {
1084 		RevObject r;
1085 		int type = ldr.getType();
1086 		switch (type) {
1087 		case Constants.OBJ_COMMIT: {
1088 			final RevCommit c = createCommit(id);
1089 			c.parseCanonical(this, getCachedBytes(c, ldr));
1090 			r = c;
1091 			break;
1092 		}
1093 		case Constants.OBJ_TREE: {
1094 			r = new RevTree(id);
1095 			r.flags |= PARSED;
1096 			break;
1097 		}
1098 		case Constants.OBJ_BLOB: {
1099 			r = new RevBlob(id);
1100 			r.flags |= PARSED;
1101 			break;
1102 		}
1103 		case Constants.OBJ_TAG: {
1104 			final RevTag t = new RevTag(id);
1105 			t.parseCanonical(this, getCachedBytes(t, ldr));
1106 			r = t;
1107 			break;
1108 		}
1109 		default:
1110 			throw new IllegalArgumentException(MessageFormat.format(
1111 					JGitText.get().badObjectType, Integer.valueOf(type)));
1112 		}
1113 		objects.add(r);
1114 		return r;
1115 	}
1116 
1117 	byte[] getCachedBytes(RevObject obj) throws LargeObjectException,
1118 			MissingObjectException, IncorrectObjectTypeException, IOException {
1119 		return getCachedBytes(obj, reader.open(obj, obj.getType()));
1120 	}
1121 
1122 	byte[] getCachedBytes(RevObject obj, ObjectLoader ldr)
1123 			throws LargeObjectException, MissingObjectException, IOException {
1124 		try {
1125 			return ldr.getCachedBytes(5 * MB);
1126 		} catch (LargeObjectException tooBig) {
1127 			tooBig.setObjectId(obj);
1128 			throw tooBig;
1129 		}
1130 	}
1131 
1132 	/**
1133 	 * Asynchronous object parsing.
1134 	 *
1135 	 * @param objectIds
1136 	 *            objects to open from the object store. The supplied collection
1137 	 *            must not be modified until the queue has finished.
1138 	 * @param reportMissing
1139 	 *            if true missing objects are reported by calling failure with a
1140 	 *            MissingObjectException. This may be more expensive for the
1141 	 *            implementation to guarantee. If false the implementation may
1142 	 *            choose to report MissingObjectException, or silently skip over
1143 	 *            the object with no warning.
1144 	 * @return queue to read the objects from.
1145 	 */
1146 	public <T extends ObjectId> AsyncRevObjectQueue parseAny(
1147 			Iterable<T> objectIds, boolean reportMissing) {
1148 		List<T> need = new ArrayList<>();
1149 		List<RevObject> have = new ArrayList<>();
1150 		for (T id : objectIds) {
1151 			RevObject r = objects.get(id);
1152 			if (r != null && (r.flags & PARSED) != 0)
1153 				have.add(r);
1154 			else
1155 				need.add(id);
1156 		}
1157 
1158 		final Iterator<RevObject> objItr = have.iterator();
1159 		if (need.isEmpty()) {
1160 			return new AsyncRevObjectQueue() {
1161 				@Override
1162 				public RevObject next() {
1163 					return objItr.hasNext() ? objItr.next() : null;
1164 				}
1165 
1166 				@Override
1167 				public boolean cancel(boolean mayInterruptIfRunning) {
1168 					return true;
1169 				}
1170 
1171 				@Override
1172 				public void release() {
1173 					// In-memory only, no action required.
1174 				}
1175 			};
1176 		}
1177 
1178 		final AsyncObjectLoaderQueue<T> lItr = reader.open(need, reportMissing);
1179 		return new AsyncRevObjectQueue() {
1180 			@Override
1181 			public RevObject next() throws MissingObjectException,
1182 					IncorrectObjectTypeException, IOException {
1183 				if (objItr.hasNext())
1184 					return objItr.next();
1185 				if (!lItr.next())
1186 					return null;
1187 
1188 				ObjectId id = lItr.getObjectId();
1189 				ObjectLoader ldr = lItr.open();
1190 				RevObject r = objects.get(id);
1191 				if (r == null)
1192 					r = parseNew(id, ldr);
1193 				else if (r instanceof RevCommit) {
1194 					byte[] raw = ldr.getCachedBytes();
1195 					((RevCommit) r).parseCanonical(RevWalk.this, raw);
1196 				} else if (r instanceof RevTag) {
1197 					byte[] raw = ldr.getCachedBytes();
1198 					((RevTag) r).parseCanonical(RevWalk.this, raw);
1199 				} else
1200 					r.flags |= PARSED;
1201 				return r;
1202 			}
1203 
1204 			@Override
1205 			public boolean cancel(boolean mayInterruptIfRunning) {
1206 				return lItr.cancel(mayInterruptIfRunning);
1207 			}
1208 
1209 			@Override
1210 			public void release() {
1211 				lItr.release();
1212 			}
1213 		};
1214 	}
1215 
1216 	/**
1217 	 * Ensure the object's critical headers have been parsed.
1218 	 * <p>
1219 	 * This method only returns successfully if the object exists and was parsed
1220 	 * without error.
1221 	 *
1222 	 * @param obj
1223 	 *            the object the caller needs to be parsed.
1224 	 * @throws org.eclipse.jgit.errors.MissingObjectException
1225 	 *             the supplied does not exist.
1226 	 * @throws java.io.IOException
1227 	 *             a pack file or loose object could not be read.
1228 	 */
1229 	public void parseHeaders(RevObject obj)
1230 			throws MissingObjectException, IOException {
1231 		if ((obj.flags & PARSED) == 0)
1232 			obj.parseHeaders(this);
1233 	}
1234 
1235 	/**
1236 	 * Ensure the object's full body content is available.
1237 	 * <p>
1238 	 * This method only returns successfully if the object exists and was parsed
1239 	 * without error.
1240 	 *
1241 	 * @param obj
1242 	 *            the object the caller needs to be parsed.
1243 	 * @throws org.eclipse.jgit.errors.MissingObjectException
1244 	 *             the supplied does not exist.
1245 	 * @throws java.io.IOException
1246 	 *             a pack file or loose object could not be read.
1247 	 */
1248 	public void parseBody(RevObject obj)
1249 			throws MissingObjectException, IOException {
1250 		obj.parseBody(this);
1251 	}
1252 
1253 	/**
1254 	 * Peel back annotated tags until a non-tag object is found.
1255 	 *
1256 	 * @param obj
1257 	 *            the starting object.
1258 	 * @return If {@code obj} is not an annotated tag, {@code obj}. Otherwise
1259 	 *         the first non-tag object that {@code obj} references. The
1260 	 *         returned object's headers have been parsed.
1261 	 * @throws org.eclipse.jgit.errors.MissingObjectException
1262 	 *             a referenced object cannot be found.
1263 	 * @throws java.io.IOException
1264 	 *             a pack file or loose object could not be read.
1265 	 */
1266 	public RevObject peel(RevObject obj) throws MissingObjectException,
1267 			IOException {
1268 		while (obj instanceof RevTag) {
1269 			parseHeaders(obj);
1270 			obj = ((RevTag) obj).getObject();
1271 		}
1272 		parseHeaders(obj);
1273 		return obj;
1274 	}
1275 
1276 	/**
1277 	 * Create a new flag for application use during walking.
1278 	 * <p>
1279 	 * Applications are only assured to be able to create 24 unique flags on any
1280 	 * given revision walker instance. Any flags beyond 24 are offered only if
1281 	 * the implementation has extra free space within its internal storage.
1282 	 *
1283 	 * @param name
1284 	 *            description of the flag, primarily useful for debugging.
1285 	 * @return newly constructed flag instance.
1286 	 * @throws java.lang.IllegalArgumentException
1287 	 *             too many flags have been reserved on this revision walker.
1288 	 */
1289 	public RevFlag newFlag(String name) {
1290 		final int m = allocFlag();
1291 		return new RevFlag(this, name, m);
1292 	}
1293 
1294 	int allocFlag() {
1295 		if (freeFlags == 0)
1296 			throw new IllegalArgumentException(MessageFormat.format(
1297 					JGitText.get().flagsAlreadyCreated,
1298 					Integer.valueOf(32 - RESERVED_FLAGS)));
1299 		final int m = Integer.lowestOneBit(freeFlags);
1300 		freeFlags &= ~m;
1301 		return m;
1302 	}
1303 
1304 	/**
1305 	 * Automatically carry a flag from a child commit to its parents.
1306 	 * <p>
1307 	 * A carried flag is copied from the child commit onto its parents when the
1308 	 * child commit is popped from the lowest level of walk's internal graph.
1309 	 *
1310 	 * @param flag
1311 	 *            the flag to carry onto parents, if set on a descendant.
1312 	 */
1313 	public void carry(RevFlag flag) {
1314 		if ((freeFlags & flag.mask) != 0)
1315 			throw new IllegalArgumentException(MessageFormat.format(JGitText.get().flagIsDisposed, flag.name));
1316 		if (flag.walker != this)
1317 			throw new IllegalArgumentException(MessageFormat.format(JGitText.get().flagNotFromThis, flag.name));
1318 		carryFlags |= flag.mask;
1319 	}
1320 
1321 	/**
1322 	 * Automatically carry flags from a child commit to its parents.
1323 	 * <p>
1324 	 * A carried flag is copied from the child commit onto its parents when the
1325 	 * child commit is popped from the lowest level of walk's internal graph.
1326 	 *
1327 	 * @param set
1328 	 *            the flags to carry onto parents, if set on a descendant.
1329 	 */
1330 	public void carry(Collection<RevFlag> set) {
1331 		for (RevFlag flag : set)
1332 			carry(flag);
1333 	}
1334 
1335 	/**
1336 	 * Preserve a RevFlag during all {@code reset} methods.
1337 	 * <p>
1338 	 * Calling {@code retainOnReset(flag)} avoids needing to pass the flag
1339 	 * during each {@code resetRetain()} invocation on this instance.
1340 	 * <p>
1341 	 * Clearing flags marked retainOnReset requires disposing of the flag with
1342 	 * {@code #disposeFlag(RevFlag)} or disposing of the entire RevWalk by
1343 	 * {@code #dispose()}.
1344 	 *
1345 	 * @param flag
1346 	 *            the flag to retain during all resets.
1347 	 * @since 3.6
1348 	 */
1349 	public final void retainOnReset(RevFlag flag) {
1350 		if ((freeFlags & flag.mask) != 0)
1351 			throw new IllegalArgumentException(MessageFormat.format(JGitText.get().flagIsDisposed, flag.name));
1352 		if (flag.walker != this)
1353 			throw new IllegalArgumentException(MessageFormat.format(JGitText.get().flagNotFromThis, flag.name));
1354 		retainOnReset |= flag.mask;
1355 	}
1356 
1357 	/**
1358 	 * Preserve a set of RevFlags during all {@code reset} methods.
1359 	 * <p>
1360 	 * Calling {@code retainOnReset(set)} avoids needing to pass the flags
1361 	 * during each {@code resetRetain()} invocation on this instance.
1362 	 * <p>
1363 	 * Clearing flags marked retainOnReset requires disposing of the flag with
1364 	 * {@code #disposeFlag(RevFlag)} or disposing of the entire RevWalk by
1365 	 * {@code #dispose()}.
1366 	 *
1367 	 * @param flags
1368 	 *            the flags to retain during all resets.
1369 	 * @since 3.6
1370 	 */
1371 	public final void retainOnReset(Collection<RevFlag> flags) {
1372 		for (RevFlag f : flags)
1373 			retainOnReset(f);
1374 	}
1375 
1376 	/**
1377 	 * Allow a flag to be recycled for a different use.
1378 	 * <p>
1379 	 * Recycled flags always come back as a different Java object instance when
1380 	 * assigned again by {@link #newFlag(String)}.
1381 	 * <p>
1382 	 * If the flag was previously being carried, the carrying request is
1383 	 * removed. Disposing of a carried flag while a traversal is in progress has
1384 	 * an undefined behavior.
1385 	 *
1386 	 * @param flag
1387 	 *            the to recycle.
1388 	 */
1389 	public void disposeFlag(RevFlag flag) {
1390 		freeFlag(flag.mask);
1391 	}
1392 
1393 	void freeFlag(int mask) {
1394 		retainOnReset &= ~mask;
1395 		if (isNotStarted()) {
1396 			freeFlags |= mask;
1397 			carryFlags &= ~mask;
1398 		} else {
1399 			delayFreeFlags |= mask;
1400 		}
1401 	}
1402 
1403 	private void finishDelayedFreeFlags() {
1404 		if (delayFreeFlags != 0) {
1405 			freeFlags |= delayFreeFlags;
1406 			carryFlags &= ~delayFreeFlags;
1407 			delayFreeFlags = 0;
1408 		}
1409 	}
1410 
1411 	/**
1412 	 * Resets internal state and allows this instance to be used again.
1413 	 * <p>
1414 	 * Unlike {@link #dispose()} previously acquired RevObject (and RevCommit)
1415 	 * instances are not invalidated. RevFlag instances are not invalidated, but
1416 	 * are removed from all RevObjects.
1417 	 */
1418 	public final void reset() {
1419 		reset(0);
1420 	}
1421 
1422 	/**
1423 	 * Resets internal state and allows this instance to be used again.
1424 	 * <p>
1425 	 * Unlike {@link #dispose()} previously acquired RevObject (and RevCommit)
1426 	 * instances are not invalidated. RevFlag instances are not invalidated, but
1427 	 * are removed from all RevObjects.
1428 	 *
1429 	 * @param retainFlags
1430 	 *            application flags that should <b>not</b> be cleared from
1431 	 *            existing commit objects.
1432 	 */
1433 	public final void resetRetain(RevFlagSet retainFlags) {
1434 		reset(retainFlags.mask);
1435 	}
1436 
1437 	/**
1438 	 * Resets internal state and allows this instance to be used again.
1439 	 * <p>
1440 	 * Unlike {@link #dispose()} previously acquired RevObject (and RevCommit)
1441 	 * instances are not invalidated. RevFlag instances are not invalidated, but
1442 	 * are removed from all RevObjects.
1443 	 * <p>
1444 	 * See {@link #retainOnReset(RevFlag)} for an alternative that does not
1445 	 * require passing the flags during each reset.
1446 	 *
1447 	 * @param retainFlags
1448 	 *            application flags that should <b>not</b> be cleared from
1449 	 *            existing commit objects.
1450 	 */
1451 	public final void resetRetain(RevFlag... retainFlags) {
1452 		int mask = 0;
1453 		for (RevFlag flag : retainFlags)
1454 			mask |= flag.mask;
1455 		reset(mask);
1456 	}
1457 
1458 	/**
1459 	 * Resets internal state and allows this instance to be used again.
1460 	 * <p>
1461 	 * Unlike {@link #dispose()} previously acquired RevObject (and RevCommit)
1462 	 * instances are not invalidated. RevFlag instances are not invalidated, but
1463 	 * are removed from all RevObjects. The value of {@code firstParent} is
1464 	 * retained.
1465 	 *
1466 	 * @param retainFlags
1467 	 *            application flags that should <b>not</b> be cleared from
1468 	 *            existing commit objects.
1469 	 */
1470 	protected void reset(int retainFlags) {
1471 		finishDelayedFreeFlags();
1472 		retainFlags |= PARSED | retainOnReset;
1473 		final int clearFlags = ~retainFlags;
1474 
1475 		final FIFORevQueue q = new FIFORevQueue();
1476 		for (RevCommit c : roots) {
1477 			if ((c.flags & clearFlags) == 0)
1478 				continue;
1479 			c.flags &= retainFlags;
1480 			c.reset();
1481 			q.add(c);
1482 		}
1483 
1484 		for (;;) {
1485 			final RevCommit c = q.next();
1486 			if (c == null)
1487 				break;
1488 			if (c.parents == null)
1489 				continue;
1490 			for (RevCommit p : c.parents) {
1491 				if ((p.flags & clearFlags) == 0)
1492 					continue;
1493 				p.flags &= retainFlags;
1494 				p.reset();
1495 				q.add(p);
1496 			}
1497 		}
1498 
1499 		roots.clear();
1500 		queue = new DateRevQueue(firstParent);
1501 		pending = new StartGenerator(this);
1502 	}
1503 
1504 	/**
1505 	 * Dispose all internal state and invalidate all RevObject instances.
1506 	 * <p>
1507 	 * All RevObject (and thus RevCommit, etc.) instances previously acquired
1508 	 * from this RevWalk are invalidated by a dispose call. Applications must
1509 	 * not retain or use RevObject instances obtained prior to the dispose call.
1510 	 * All RevFlag instances are also invalidated, and must not be reused.
1511 	 */
1512 	public void dispose() {
1513 		reader.close();
1514 		freeFlags = APP_FLAGS;
1515 		delayFreeFlags = 0;
1516 		retainOnReset = 0;
1517 		carryFlags = UNINTERESTING;
1518 		firstParent = false;
1519 		objects.clear();
1520 		roots.clear();
1521 		queue = new DateRevQueue(firstParent);
1522 		pending = new StartGenerator(this);
1523 		shallowCommitsInitialized = false;
1524 	}
1525 
1526 	/**
1527 	 * Like {@link #next()}, but if a checked exception is thrown during the
1528 	 * walk it is rethrown as a {@link RevWalkException}.
1529 	 *
1530 	 * @throws RevWalkException if an {@link IOException} was thrown.
1531 	 * @return next most recent commit; null if traversal is over.
1532 	 */
1533 	@Nullable
1534 	private RevCommit nextForIterator() {
1535 		try {
1536 			return next();
1537 		} catch (IOException e) {
1538 			throw new RevWalkException(e);
1539 		}
1540 	}
1541 
1542 	/**
1543 	 * {@inheritDoc}
1544 	 * <p>
1545 	 * Returns an Iterator over the commits of this walker.
1546 	 * <p>
1547 	 * The returned iterator is only useful for one walk. If this RevWalk gets
1548 	 * reset a new iterator must be obtained to walk over the new results.
1549 	 * <p>
1550 	 * Applications must not use both the Iterator and the {@link #next()} API
1551 	 * at the same time. Pick one API and use that for the entire walk.
1552 	 * <p>
1553 	 * If a checked exception is thrown during the walk (see {@link #next()}) it
1554 	 * is rethrown from the Iterator as a {@link RevWalkException}.
1555 	 *
1556 	 * @see RevWalkException
1557 	 */
1558 	@Override
1559 	public Iterator<RevCommit> iterator() {
1560 		RevCommit first = nextForIterator();
1561 
1562 		return new Iterator<>() {
1563 			RevCommit next = first;
1564 
1565 			@Override
1566 			public boolean hasNext() {
1567 				return next != null;
1568 			}
1569 
1570 			@Override
1571 			public RevCommit next() {
1572 				RevCommit r = next;
1573 				next = nextForIterator();
1574 				return r;
1575 			}
1576 
1577 			@Override
1578 			public void remove() {
1579 				throw new UnsupportedOperationException();
1580 			}
1581 		};
1582 	}
1583 
1584 	/**
1585 	 * Throws an exception if we have started producing output.
1586 	 */
1587 	protected void assertNotStarted() {
1588 		if (isNotStarted())
1589 			return;
1590 		throw new IllegalStateException(JGitText.get().outputHasAlreadyBeenStarted);
1591 	}
1592 
1593 	/**
1594 	 * Throws an exception if any commits have been marked as start.
1595 	 * <p>
1596 	 * If {@link #markStart(RevCommit)} has already been called,
1597 	 * {@link #reset()} can be called to satisfy this condition.
1598 	 *
1599 	 * @since 5.5
1600 	 */
1601 	protected void assertNoCommitsMarkedStart() {
1602 		if (roots.isEmpty())
1603 			return;
1604 		throw new IllegalStateException(
1605 				JGitText.get().commitsHaveAlreadyBeenMarkedAsStart);
1606 	}
1607 
1608 	private boolean isNotStarted() {
1609 		return pending instanceof StartGenerator;
1610 	}
1611 
1612 	/**
1613 	 * Create and return an {@link org.eclipse.jgit.revwalk.ObjectWalk} using
1614 	 * the same objects.
1615 	 * <p>
1616 	 * Prior to using this method, the caller must reset this RevWalk to clean
1617 	 * any flags that were used during the last traversal.
1618 	 * <p>
1619 	 * The returned ObjectWalk uses the same ObjectReader, internal object pool,
1620 	 * and free RevFlags. Once the ObjectWalk is created, this RevWalk should
1621 	 * not be used anymore.
1622 	 *
1623 	 * @return a new walk, using the exact same object pool.
1624 	 */
1625 	public ObjectWalk toObjectWalkWithSameObjects() {
1626 		ObjectWalk ow = new ObjectWalk(reader);
1627 		RevWalk rw = ow;
1628 		rw.objects = objects;
1629 		rw.freeFlags = freeFlags;
1630 		return ow;
1631 	}
1632 
1633 	/**
1634 	 * Construct a new unparsed commit for the given object.
1635 	 *
1636 	 * @param id
1637 	 *            the object this walker requires a commit reference for.
1638 	 * @return a new unparsed reference for the object.
1639 	 */
1640 	protected RevCommit createCommit(AnyObjectId id) {
1641 		return new RevCommit(id);
1642 	}
1643 
1644 	void carryFlagsImpl(RevCommit c) {
1645 		final int carry = c.flags & carryFlags;
1646 		if (carry != 0)
1647 			RevCommit.carryFlags(c, carry);
1648 	}
1649 
1650 	/**
1651 	 * Assume additional commits are shallow (have no parents).
1652 	 * <p>
1653 	 * This method is a No-op if the collection is empty.
1654 	 *
1655 	 * @param ids
1656 	 *            commits that should be treated as shallow commits, in addition
1657 	 *            to any commits already known to be shallow by the repository.
1658 	 * @since 3.3
1659 	 */
1660 	public void assumeShallow(Collection<? extends ObjectId> ids) {
1661 		for (ObjectId id : ids)
1662 			lookupCommit(id).parents = RevCommit.NO_PARENTS;
1663 	}
1664 
1665 	/**
1666 	 * Reads the "shallow" file and applies it by setting the parents of shallow
1667 	 * commits to an empty array.
1668 	 * <p>
1669 	 * There is a sequencing problem if the first commit being parsed is a
1670 	 * shallow commit, since {@link RevCommit#parseCanonical(RevWalk, byte[])}
1671 	 * calls this method before its callers add the new commit to the
1672 	 * {@link RevWalk#objects} map. That means a call from this method to
1673 	 * {@link #lookupCommit(AnyObjectId)} fails to find that commit and creates
1674 	 * a new one, which is promptly discarded.
1675 	 * <p>
1676 	 * To avoid that, {@link RevCommit#parseCanonical(RevWalk, byte[])} passes
1677 	 * its commit to this method, so that this method can apply the shallow
1678 	 * state to it directly and avoid creating the duplicate commit object.
1679 	 *
1680 	 * @param rc
1681 	 *            the initial commit being parsed
1682 	 * @throws IOException
1683 	 *             if the shallow commits file can't be read
1684 	 */
1685 	void initializeShallowCommits(RevCommit rc) throws IOException {
1686 		if (shallowCommitsInitialized) {
1687 			throw new IllegalStateException(
1688 					JGitText.get().shallowCommitsAlreadyInitialized);
1689 		}
1690 
1691 		shallowCommitsInitialized = true;
1692 
1693 		if (reader == null) {
1694 			return;
1695 		}
1696 
1697 		for (ObjectId id : reader.getShallowCommits()) {
1698 			if (id.equals(rc.getId())) {
1699 				rc.parents = RevCommit.NO_PARENTS;
1700 			} else {
1701 				lookupCommit(id).parents = RevCommit.NO_PARENTS;
1702 			}
1703 		}
1704 	}
1705 }