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