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