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