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