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