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