View Javadoc
1   /*
2    * Copyright (C) 2008-2009, Google Inc.
3    * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
4    * and other copyright owners as documented in the project's IP log.
5    *
6    * This program and the accompanying materials are made available
7    * under the terms of the Eclipse Distribution License v1.0 which
8    * accompanies this distribution, is reproduced below, and is
9    * available at http://www.eclipse.org/org/documents/edl-v10.php
10   *
11   * All rights reserved.
12   *
13   * Redistribution and use in source and binary forms, with or
14   * without modification, are permitted provided that the following
15   * conditions are met:
16   *
17   * - Redistributions of source code must retain the above copyright
18   *   notice, this list of conditions and the following disclaimer.
19   *
20   * - Redistributions in binary form must reproduce the above
21   *   copyright notice, this list of conditions and the following
22   *   disclaimer in the documentation and/or other materials provided
23   *   with the distribution.
24   *
25   * - Neither the name of the Eclipse Foundation, Inc. nor the
26   *   names of its contributors may be used to endorse or promote
27   *   products derived from this software without specific prior
28   *   written permission.
29   *
30   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
31   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
32   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
33   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
35   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
37   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
42   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43   */
44  
45  package org.eclipse.jgit.treewalk;
46  
47  import java.io.IOException;
48  import java.util.HashMap;
49  import java.util.Map;
50  import java.util.Set;
51  
52  import org.eclipse.jgit.annotations.Nullable;
53  import org.eclipse.jgit.api.errors.JGitInternalException;
54  import org.eclipse.jgit.attributes.Attribute;
55  import org.eclipse.jgit.attributes.Attributes;
56  import org.eclipse.jgit.attributes.AttributesHandler;
57  import org.eclipse.jgit.attributes.AttributesNodeProvider;
58  import org.eclipse.jgit.attributes.AttributesProvider;
59  import org.eclipse.jgit.attributes.FilterCommandRegistry;
60  import org.eclipse.jgit.dircache.DirCacheBuildIterator;
61  import org.eclipse.jgit.dircache.DirCacheIterator;
62  import org.eclipse.jgit.errors.CorruptObjectException;
63  import org.eclipse.jgit.errors.IncorrectObjectTypeException;
64  import org.eclipse.jgit.errors.MissingObjectException;
65  import org.eclipse.jgit.errors.StopWalkException;
66  import org.eclipse.jgit.lib.AnyObjectId;
67  import org.eclipse.jgit.lib.Config;
68  import org.eclipse.jgit.lib.ConfigConstants;
69  import org.eclipse.jgit.lib.Constants;
70  import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
71  import org.eclipse.jgit.lib.FileMode;
72  import org.eclipse.jgit.lib.MutableObjectId;
73  import org.eclipse.jgit.lib.ObjectId;
74  import org.eclipse.jgit.lib.ObjectReader;
75  import org.eclipse.jgit.lib.Repository;
76  import org.eclipse.jgit.revwalk.RevTree;
77  import org.eclipse.jgit.treewalk.filter.PathFilter;
78  import org.eclipse.jgit.treewalk.filter.TreeFilter;
79  import org.eclipse.jgit.util.QuotedString;
80  import org.eclipse.jgit.util.RawParseUtils;
81  import org.eclipse.jgit.util.io.EolStreamTypeUtil;
82  
83  /**
84   * Walks one or more {@link AbstractTreeIterator}s in parallel.
85   * <p>
86   * This class can perform n-way differences across as many trees as necessary.
87   * <p>
88   * Each tree added must have the same root as existing trees in the walk.
89   * <p>
90   * A TreeWalk instance can only be used once to generate results. Running a
91   * second time requires creating a new TreeWalk instance, or invoking
92   * {@link #reset()} and adding new trees before starting again. Resetting an
93   * existing instance may be faster for some applications as some internal
94   * buffers may be recycled.
95   * <p>
96   * TreeWalk instances are not thread-safe. Applications must either restrict
97   * usage of a TreeWalk instance to a single thread, or implement their own
98   * synchronization at a higher level.
99   * <p>
100  * Multiple simultaneous TreeWalk instances per {@link Repository} are
101  * permitted, even from concurrent threads.
102  */
103 public class TreeWalk implements AutoCloseable, AttributesProvider {
104 	private static final AbstractTreeIterator[] NO_TREES = {};
105 
106 	/**
107 	 * @since 4.2
108 	 */
109 	public static enum OperationType {
110 		/**
111 		 * Represents a checkout operation (for example a checkout or reset
112 		 * operation).
113 		 */
114 		CHECKOUT_OP,
115 
116 		/**
117 		 * Represents a checkin operation (for example an add operation)
118 		 */
119 		CHECKIN_OP
120 	}
121 
122 	/**
123 	 *            Type of operation you want to retrieve the git attributes for.
124 	 */
125 	private OperationType operationType = OperationType.CHECKOUT_OP;
126 
127 	/**
128 	 * The filter command as defined in gitattributes. The keys are
129 	 * filterName+"."+filterCommandType. E.g. "lfs.clean"
130 	 */
131 	private Map<String, String> filterCommandsByNameDotType = new HashMap<>();
132 
133 	/**
134 	 * @param operationType
135 	 * @since 4.2
136 	 */
137 	public void setOperationType(OperationType operationType) {
138 		this.operationType = operationType;
139 	}
140 
141 	/**
142 	 * Open a tree walk and filter to exactly one path.
143 	 * <p>
144 	 * The returned tree walk is already positioned on the requested path, so
145 	 * the caller should not need to invoke {@link #next()} unless they are
146 	 * looking for a possible directory/file name conflict.
147 	 *
148 	 * @param reader
149 	 *            the reader the walker will obtain tree data from.
150 	 * @param path
151 	 *            single path to advance the tree walk instance into.
152 	 * @param trees
153 	 *            one or more trees to walk through, all with the same root.
154 	 * @return a new tree walk configured for exactly this one path; null if no
155 	 *         path was found in any of the trees.
156 	 * @throws IOException
157 	 *             reading a pack file or loose object failed.
158 	 * @throws CorruptObjectException
159 	 *             an tree object could not be read as its data stream did not
160 	 *             appear to be a tree, or could not be inflated.
161 	 * @throws IncorrectObjectTypeException
162 	 *             an object we expected to be a tree was not a tree.
163 	 * @throws MissingObjectException
164 	 *             a tree object was not found.
165 	 */
166 	public static TreeWalk forPath(final ObjectReader reader, final String path,
167 			final AnyObjectId... trees) throws MissingObjectException,
168 			IncorrectObjectTypeException, CorruptObjectException, IOException {
169 		return forPath(null, reader, path, trees);
170 	}
171 
172 	/**
173 	 * Open a tree walk and filter to exactly one path.
174 	 * <p>
175 	 * The returned tree walk is already positioned on the requested path, so
176 	 * the caller should not need to invoke {@link #next()} unless they are
177 	 * looking for a possible directory/file name conflict.
178 	 *
179 	 * @param repo
180 	 *            repository to read config data and
181 	 *            {@link AttributesNodeProvider} from.
182 	 * @param reader
183 	 *            the reader the walker will obtain tree data from.
184 	 * @param path
185 	 *            single path to advance the tree walk instance into.
186 	 * @param trees
187 	 *            one or more trees to walk through, all with the same root.
188 	 * @return a new tree walk configured for exactly this one path; null if no
189 	 *         path was found in any of the trees.
190 	 * @throws IOException
191 	 *             reading a pack file or loose object failed.
192 	 * @throws CorruptObjectException
193 	 *             an tree object could not be read as its data stream did not
194 	 *             appear to be a tree, or could not be inflated.
195 	 * @throws IncorrectObjectTypeException
196 	 *             an object we expected to be a tree was not a tree.
197 	 * @throws MissingObjectException
198 	 *             a tree object was not found.
199 	 * @since 4.3
200 	 */
201 	public static TreeWalk forPath(final @Nullable Repository repo,
202 			final ObjectReader reader, final String path,
203 			final AnyObjectId... trees)
204 					throws MissingObjectException, IncorrectObjectTypeException,
205 					CorruptObjectException, IOException {
206 		TreeWalk tw = new TreeWalk(repo, reader);
207 		PathFilter f = PathFilter.create(path);
208 		tw.setFilter(f);
209 		tw.reset(trees);
210 		tw.setRecursive(false);
211 
212 		while (tw.next()) {
213 			if (f.isDone(tw)) {
214 				return tw;
215 			} else if (tw.isSubtree()) {
216 				tw.enterSubtree();
217 			}
218 		}
219 		return null;
220 	}
221 
222 	/**
223 	 * Open a tree walk and filter to exactly one path.
224 	 * <p>
225 	 * The returned tree walk is already positioned on the requested path, so
226 	 * the caller should not need to invoke {@link #next()} unless they are
227 	 * looking for a possible directory/file name conflict.
228 	 *
229 	 * @param db
230 	 *            repository to read tree object data from.
231 	 * @param path
232 	 *            single path to advance the tree walk instance into.
233 	 * @param trees
234 	 *            one or more trees to walk through, all with the same root.
235 	 * @return a new tree walk configured for exactly this one path; null if no
236 	 *         path was found in any of the trees.
237 	 * @throws IOException
238 	 *             reading a pack file or loose object failed.
239 	 * @throws CorruptObjectException
240 	 *             an tree object could not be read as its data stream did not
241 	 *             appear to be a tree, or could not be inflated.
242 	 * @throws IncorrectObjectTypeException
243 	 *             an object we expected to be a tree was not a tree.
244 	 * @throws MissingObjectException
245 	 *             a tree object was not found.
246 	 */
247 	public static TreeWalk forPath(final Repository db, final String path,
248 			final AnyObjectId... trees) throws MissingObjectException,
249 			IncorrectObjectTypeException, CorruptObjectException, IOException {
250 		try (ObjectReader reader = db.newObjectReader()) {
251 			return forPath(db, reader, path, trees);
252 		}
253 	}
254 
255 	/**
256 	 * Open a tree walk and filter to exactly one path.
257 	 * <p>
258 	 * The returned tree walk is already positioned on the requested path, so
259 	 * the caller should not need to invoke {@link #next()} unless they are
260 	 * looking for a possible directory/file name conflict.
261 	 *
262 	 * @param db
263 	 *            repository to read tree object data from.
264 	 * @param path
265 	 *            single path to advance the tree walk instance into.
266 	 * @param tree
267 	 *            the single tree to walk through.
268 	 * @return a new tree walk configured for exactly this one path; null if no
269 	 *         path was found in any of the trees.
270 	 * @throws IOException
271 	 *             reading a pack file or loose object failed.
272 	 * @throws CorruptObjectException
273 	 *             an tree object could not be read as its data stream did not
274 	 *             appear to be a tree, or could not be inflated.
275 	 * @throws IncorrectObjectTypeException
276 	 *             an object we expected to be a tree was not a tree.
277 	 * @throws MissingObjectException
278 	 *             a tree object was not found.
279 	 */
280 	public static TreeWalk forPath(final Repository db, final String path,
281 			final RevTree tree) throws MissingObjectException,
282 			IncorrectObjectTypeException, CorruptObjectException, IOException {
283 		return forPath(db, path, new ObjectId[] { tree });
284 	}
285 
286 	private final ObjectReader reader;
287 
288 	private final boolean closeReader;
289 
290 	private final MutableObjectId idBuffer = new MutableObjectId();
291 
292 	private TreeFilter filter;
293 
294 	AbstractTreeIterator[] trees;
295 
296 	private boolean recursive;
297 
298 	private boolean postOrderTraversal;
299 
300 	int depth;
301 
302 	private boolean advance;
303 
304 	private boolean postChildren;
305 
306 	private AttributesNodeProvider attributesNodeProvider;
307 
308 	AbstractTreeIterator currentHead;
309 
310 	/** Cached attribute for the current entry */
311 	private Attributes attrs = null;
312 
313 	/** Cached attributes handler */
314 	private AttributesHandler attributesHandler;
315 
316 	private Config config;
317 
318 	private Set<String> filterCommands;
319 
320 	/**
321 	 * Create a new tree walker for a given repository.
322 	 *
323 	 * @param repo
324 	 *            the repository the walker will obtain data from. An
325 	 *            ObjectReader will be created by the walker, and will be closed
326 	 *            when the walker is closed.
327 	 */
328 	public TreeWalk(final Repository repo) {
329 		this(repo, repo.newObjectReader(), true);
330 	}
331 
332 	/**
333 	 * Create a new tree walker for a given repository.
334 	 *
335 	 * @param repo
336 	 *            the repository the walker will obtain data from. An
337 	 *            ObjectReader will be created by the walker, and will be closed
338 	 *            when the walker is closed.
339 	 * @param or
340 	 *            the reader the walker will obtain tree data from. The reader
341 	 *            is not closed when the walker is closed.
342 	 * @since 4.3
343 	 */
344 	public TreeWalk(final @Nullable Repository repo, final ObjectReader or) {
345 		this(repo, or, false);
346 	}
347 
348 	/**
349 	 * Create a new tree walker for a given repository.
350 	 *
351 	 * @param or
352 	 *            the reader the walker will obtain tree data from. The reader
353 	 *            is not closed when the walker is closed.
354 	 */
355 	public TreeWalk(final ObjectReader or) {
356 		this(null, or, false);
357 	}
358 
359 	private TreeWalk(final @Nullable Repository repo, final ObjectReader or,
360 			final boolean closeReader) {
361 		if (repo != null) {
362 			config = repo.getConfig();
363 			attributesNodeProvider = repo.createAttributesNodeProvider();
364 			filterCommands = FilterCommandRegistry
365 					.getRegisteredFilterCommands();
366 		} else {
367 			config = null;
368 			attributesNodeProvider = null;
369 		}
370 		reader = or;
371 		filter = TreeFilter.ALL;
372 		trees = NO_TREES;
373 		this.closeReader = closeReader;
374 	}
375 
376 	/** @return the reader this walker is using to load objects. */
377 	public ObjectReader getObjectReader() {
378 		return reader;
379 	}
380 
381 	/**
382 	 * @return the {@link OperationType}
383 	 * @since 4.3
384 	 */
385 	public OperationType getOperationType() {
386 		return operationType;
387 	}
388 
389 	/**
390 	 * Release any resources used by this walker's reader.
391 	 * <p>
392 	 * A walker that has been released can be used again, but may need to be
393 	 * released after the subsequent usage.
394 	 *
395 	 * @since 4.0
396 	 */
397 	@Override
398 	public void close() {
399 		if (closeReader) {
400 			reader.close();
401 		}
402 	}
403 
404 	/**
405 	 * Get the currently configured filter.
406 	 *
407 	 * @return the current filter. Never null as a filter is always needed.
408 	 */
409 	public TreeFilter getFilter() {
410 		return filter;
411 	}
412 
413 	/**
414 	 * Set the tree entry filter for this walker.
415 	 * <p>
416 	 * Multiple filters may be combined by constructing an arbitrary tree of
417 	 * <code>AndTreeFilter</code> or <code>OrTreeFilter</code> instances to
418 	 * describe the boolean expression required by the application. Custom
419 	 * filter implementations may also be constructed by applications.
420 	 * <p>
421 	 * Note that filters are not thread-safe and may not be shared by concurrent
422 	 * TreeWalk instances. Every TreeWalk must be supplied its own unique
423 	 * filter, unless the filter implementation specifically states it is (and
424 	 * always will be) thread-safe. Callers may use {@link TreeFilter#clone()}
425 	 * to create a unique filter tree for this TreeWalk instance.
426 	 *
427 	 * @param newFilter
428 	 *            the new filter. If null the special {@link TreeFilter#ALL}
429 	 *            filter will be used instead, as it matches every entry.
430 	 * @see org.eclipse.jgit.treewalk.filter.AndTreeFilter
431 	 * @see org.eclipse.jgit.treewalk.filter.OrTreeFilter
432 	 */
433 	public void setFilter(final TreeFilter newFilter) {
434 		filter = newFilter != null ? newFilter : TreeFilter.ALL;
435 	}
436 
437 	/**
438 	 * Is this walker automatically entering into subtrees?
439 	 * <p>
440 	 * If the walker is recursive then the caller will not see a subtree node
441 	 * and instead will only receive file nodes in all relevant subtrees.
442 	 *
443 	 * @return true if automatically entering subtrees is enabled.
444 	 */
445 	public boolean isRecursive() {
446 		return recursive;
447 	}
448 
449 	/**
450 	 * Set the walker to enter (or not enter) subtrees automatically.
451 	 * <p>
452 	 * If recursive mode is enabled the walker will hide subtree nodes from the
453 	 * calling application and will produce only file level nodes. If a tree
454 	 * (directory) is deleted then all of the file level nodes will appear to be
455 	 * deleted, recursively, through as many levels as necessary to account for
456 	 * all entries.
457 	 *
458 	 * @param b
459 	 *            true to skip subtree nodes and only obtain files nodes.
460 	 */
461 	public void setRecursive(final boolean b) {
462 		recursive = b;
463 	}
464 
465 	/**
466 	 * Does this walker return a tree entry after it exits the subtree?
467 	 * <p>
468 	 * If post order traversal is enabled then the walker will return a subtree
469 	 * after it has returned the last entry within that subtree. This may cause
470 	 * a subtree to be seen by the application twice if {@link #isRecursive()}
471 	 * is false, as the application will see it once, call
472 	 * {@link #enterSubtree()}, and then see it again as it leaves the subtree.
473 	 * <p>
474 	 * If an application does not enable {@link #isRecursive()} and it does not
475 	 * call {@link #enterSubtree()} then the tree is returned only once as none
476 	 * of the children were processed.
477 	 *
478 	 * @return true if subtrees are returned after entries within the subtree.
479 	 */
480 	public boolean isPostOrderTraversal() {
481 		return postOrderTraversal;
482 	}
483 
484 	/**
485 	 * Set the walker to return trees after their children.
486 	 *
487 	 * @param b
488 	 *            true to get trees after their children.
489 	 * @see #isPostOrderTraversal()
490 	 */
491 	public void setPostOrderTraversal(final boolean b) {
492 		postOrderTraversal = b;
493 	}
494 
495 	/**
496 	 * Sets the {@link AttributesNodeProvider} for this {@link TreeWalk}.
497 	 * <p>
498 	 * This is a requirement for a correct computation of the git attributes.
499 	 * If this {@link TreeWalk} has been built using
500 	 * {@link #TreeWalk(Repository)} constructor, the
501 	 * {@link AttributesNodeProvider} has already been set. Indeed,the
502 	 * {@link Repository} can provide an {@link AttributesNodeProvider} using
503 	 * {@link Repository#createAttributesNodeProvider()} method. Otherwise you
504 	 * should provide one.
505 	 * </p>
506 	 *
507 	 * @see Repository#createAttributesNodeProvider()
508 	 * @param provider
509 	 * @since 4.2
510 	 */
511 	public void setAttributesNodeProvider(AttributesNodeProvider provider) {
512 		attributesNodeProvider = provider;
513 	}
514 
515 	/**
516 	 * @return the {@link AttributesNodeProvider} for this {@link TreeWalk}.
517 	 * @since 4.3
518 	 */
519 	public AttributesNodeProvider getAttributesNodeProvider() {
520 		return attributesNodeProvider;
521 	}
522 
523 	/**
524 	 * Retrieve the git attributes for the current entry.
525 	 *
526 	 * <h4>Git attribute computation</h4>
527 	 *
528 	 * <ul>
529 	 * <li>Get the attributes matching the current path entry from the info file
530 	 * (see {@link AttributesNodeProvider#getInfoAttributesNode()}).</li>
531 	 * <li>Completes the list of attributes using the .gitattributes files
532 	 * located on the current path (the further the directory that contains
533 	 * .gitattributes is from the path in question, the lower its precedence).
534 	 * For a checkin operation, it will look first on the working tree (if any).
535 	 * If there is no attributes file, it will fallback on the index. For a
536 	 * checkout operation, it will first use the index entry and then fallback
537 	 * on the working tree if none.</li>
538 	 * <li>In the end, completes the list of matching attributes using the
539 	 * global attribute file define in the configuration (see
540 	 * {@link AttributesNodeProvider#getGlobalAttributesNode()})</li>
541 	 *
542 	 * </ul>
543 	 *
544 	 *
545 	 * <h4>Iterator constraints</h4>
546 	 *
547 	 * <p>
548 	 * In order to have a correct list of attributes for the current entry, this
549 	 * {@link TreeWalk} requires to have at least one
550 	 * {@link AttributesNodeProvider} and a {@link DirCacheIterator} set up. An
551 	 * {@link AttributesNodeProvider} is used to retrieve the attributes from
552 	 * the info attributes file and the global attributes file. The
553 	 * {@link DirCacheIterator} is used to retrieve the .gitattributes files
554 	 * stored in the index. A {@link WorkingTreeIterator} can also be provided
555 	 * to access the local version of the .gitattributes files. If none is
556 	 * provided it will fallback on the {@link DirCacheIterator}.
557 	 * </p>
558 	 *
559 	 * @return a {@link Set} of {@link Attribute}s that match the current entry.
560 	 * @since 4.2
561 	 */
562 	@Override
563 	public Attributes getAttributes() {
564 		if (attrs != null)
565 			return attrs;
566 
567 		if (attributesNodeProvider == null) {
568 			// The work tree should have a AttributesNodeProvider to be able to
569 			// retrieve the info and global attributes node
570 			throw new IllegalStateException(
571 					"The tree walk should have one AttributesNodeProvider set in order to compute the git attributes."); //$NON-NLS-1$
572 		}
573 
574 		try {
575 			// Lazy create the attributesHandler on the first access of
576 			// attributes. This requires the info, global and root
577 			// attributes nodes
578 			if (attributesHandler == null) {
579 				attributesHandler = new AttributesHandler(this);
580 			}
581 			attrs = attributesHandler.getAttributes();
582 			return attrs;
583 		} catch (IOException e) {
584 			throw new JGitInternalException("Error while parsing attributes", //$NON-NLS-1$
585 					e);
586 		}
587 	}
588 
589 	/**
590 	 * @param opType
591 	 *            the operationtype (checkin/checkout) which should be used
592 	 * @return the EOL stream type of the current entry using the config and
593 	 *         {@link #getAttributes()} Note that this method may return null if
594 	 *         the {@link TreeWalk} is not based on a working tree
595 	 */
596 	// TODO(msohn) make this method public in 4.4
597 	@Nullable
598 	EolStreamType getEolStreamType(OperationType opType) {
599 			if (attributesNodeProvider == null || config == null)
600 				return null;
601 		return EolStreamTypeUtil.detectStreamType(opType,
602 					config.get(WorkingTreeOptions.KEY), getAttributes());
603 	}
604 
605 	/**
606 	 * @return the EOL stream type of the current entry using the config and
607 	 *         {@link #getAttributes()} Note that this method may return null if
608 	 *         the {@link TreeWalk} is not based on a working tree
609 	 * @since 4.3
610 	 */
611 	// TODO(msohn) deprecate this method in 4.4
612 	public @Nullable EolStreamType getEolStreamType() {
613 		return (getEolStreamType(operationType));
614 	}
615 
616 	/** Reset this walker so new tree iterators can be added to it. */
617 	public void reset() {
618 		attrs = null;
619 		attributesHandler = null;
620 		trees = NO_TREES;
621 		advance = false;
622 		depth = 0;
623 	}
624 
625 	/**
626 	 * Reset this walker to run over a single existing tree.
627 	 *
628 	 * @param id
629 	 *            the tree we need to parse. The walker will execute over this
630 	 *            single tree if the reset is successful.
631 	 * @throws MissingObjectException
632 	 *             the given tree object does not exist in this repository.
633 	 * @throws IncorrectObjectTypeException
634 	 *             the given object id does not denote a tree, but instead names
635 	 *             some other non-tree type of object. Note that commits are not
636 	 *             trees, even if they are sometimes called a "tree-ish".
637 	 * @throws CorruptObjectException
638 	 *             the object claimed to be a tree, but its contents did not
639 	 *             appear to be a tree. The repository may have data corruption.
640 	 * @throws IOException
641 	 *             a loose object or pack file could not be read.
642 	 */
643 	public void reset(final AnyObjectId id) throws MissingObjectException,
644 			IncorrectObjectTypeException, CorruptObjectException, IOException {
645 		if (trees.length == 1) {
646 			AbstractTreeIterator o = trees[0];
647 			while (o.parent != null)
648 				o = o.parent;
649 			if (o instanceof CanonicalTreeParser) {
650 				o.matches = null;
651 				o.matchShift = 0;
652 				((CanonicalTreeParser) o).reset(reader, id);
653 				trees[0] = o;
654 			} else {
655 				trees[0] = parserFor(id);
656 			}
657 		} else {
658 			trees = new AbstractTreeIterator[] { parserFor(id) };
659 		}
660 
661 		advance = false;
662 		depth = 0;
663 		attrs = null;
664 	}
665 
666 	/**
667 	 * Reset this walker to run over a set of existing trees.
668 	 *
669 	 * @param ids
670 	 *            the trees we need to parse. The walker will execute over this
671 	 *            many parallel trees if the reset is successful.
672 	 * @throws MissingObjectException
673 	 *             the given tree object does not exist in this repository.
674 	 * @throws IncorrectObjectTypeException
675 	 *             the given object id does not denote a tree, but instead names
676 	 *             some other non-tree type of object. Note that commits are not
677 	 *             trees, even if they are sometimes called a "tree-ish".
678 	 * @throws CorruptObjectException
679 	 *             the object claimed to be a tree, but its contents did not
680 	 *             appear to be a tree. The repository may have data corruption.
681 	 * @throws IOException
682 	 *             a loose object or pack file could not be read.
683 	 */
684 	public void reset(final AnyObjectId... ids) throws MissingObjectException,
685 			IncorrectObjectTypeException, CorruptObjectException, IOException {
686 		final int oldLen = trees.length;
687 		final int newLen = ids.length;
688 		final AbstractTreeIterator[] r = newLen == oldLen ? trees
689 				: new AbstractTreeIterator[newLen];
690 		for (int i = 0; i < newLen; i++) {
691 			AbstractTreeIterator o;
692 
693 			if (i < oldLen) {
694 				o = trees[i];
695 				while (o.parent != null)
696 					o = o.parent;
697 				if (o instanceof CanonicalTreeParser && o.pathOffset == 0) {
698 					o.matches = null;
699 					o.matchShift = 0;
700 					((CanonicalTreeParser) o).reset(reader, ids[i]);
701 					r[i] = o;
702 					continue;
703 				}
704 			}
705 
706 			o = parserFor(ids[i]);
707 			r[i] = o;
708 		}
709 
710 		trees = r;
711 		advance = false;
712 		depth = 0;
713 		attrs = null;
714 	}
715 
716 	/**
717 	 * Add an already existing tree object for walking.
718 	 * <p>
719 	 * The position of this tree is returned to the caller, in case the caller
720 	 * has lost track of the order they added the trees into the walker.
721 	 * <p>
722 	 * The tree must have the same root as existing trees in the walk.
723 	 *
724 	 * @param id
725 	 *            identity of the tree object the caller wants walked.
726 	 * @return position of this tree within the walker.
727 	 * @throws MissingObjectException
728 	 *             the given tree object does not exist in this repository.
729 	 * @throws IncorrectObjectTypeException
730 	 *             the given object id does not denote a tree, but instead names
731 	 *             some other non-tree type of object. Note that commits are not
732 	 *             trees, even if they are sometimes called a "tree-ish".
733 	 * @throws CorruptObjectException
734 	 *             the object claimed to be a tree, but its contents did not
735 	 *             appear to be a tree. The repository may have data corruption.
736 	 * @throws IOException
737 	 *             a loose object or pack file could not be read.
738 	 */
739 	public int addTree(final AnyObjectId id) throws MissingObjectException,
740 			IncorrectObjectTypeException, CorruptObjectException, IOException {
741 		return addTree(parserFor(id));
742 	}
743 
744 	/**
745 	 * Add an already created tree iterator for walking.
746 	 * <p>
747 	 * The position of this tree is returned to the caller, in case the caller
748 	 * has lost track of the order they added the trees into the walker.
749 	 * <p>
750 	 * The tree which the iterator operates on must have the same root as
751 	 * existing trees in the walk.
752 	 *
753 	 * @param p
754 	 *            an iterator to walk over. The iterator should be new, with no
755 	 *            parent, and should still be positioned before the first entry.
756 	 *            The tree which the iterator operates on must have the same
757 	 *            root as other trees in the walk.
758 	 * @return position of this tree within the walker.
759 	 */
760 	public int addTree(AbstractTreeIterator p) {
761 		int n = trees.length;
762 		AbstractTreeIterator[] newTrees = new AbstractTreeIterator[n + 1];
763 
764 		System.arraycopy(trees, 0, newTrees, 0, n);
765 		newTrees[n] = p;
766 		p.matches = null;
767 		p.matchShift = 0;
768 
769 		trees = newTrees;
770 		return n;
771 	}
772 
773 	/**
774 	 * Get the number of trees known to this walker.
775 	 *
776 	 * @return the total number of trees this walker is iterating over.
777 	 */
778 	public int getTreeCount() {
779 		return trees.length;
780 	}
781 
782 	/**
783 	 * Advance this walker to the next relevant entry.
784 	 *
785 	 * @return true if there is an entry available; false if all entries have
786 	 *         been walked and the walk of this set of tree iterators is over.
787 	 * @throws MissingObjectException
788 	 *             {@link #isRecursive()} was enabled, a subtree was found, but
789 	 *             the subtree object does not exist in this repository. The
790 	 *             repository may be missing objects.
791 	 * @throws IncorrectObjectTypeException
792 	 *             {@link #isRecursive()} was enabled, a subtree was found, and
793 	 *             the subtree id does not denote a tree, but instead names some
794 	 *             other non-tree type of object. The repository may have data
795 	 *             corruption.
796 	 * @throws CorruptObjectException
797 	 *             the contents of a tree did not appear to be a tree. The
798 	 *             repository may have data corruption.
799 	 * @throws IOException
800 	 *             a loose object or pack file could not be read.
801 	 */
802 	public boolean next() throws MissingObjectException,
803 			IncorrectObjectTypeException, CorruptObjectException, IOException {
804 		try {
805 			if (advance) {
806 				advance = false;
807 				postChildren = false;
808 				popEntriesEqual();
809 			}
810 
811 			for (;;) {
812 				attrs = null;
813 				final AbstractTreeIterator t = min();
814 				if (t.eof()) {
815 					if (depth > 0) {
816 						exitSubtree();
817 						if (postOrderTraversal) {
818 							advance = true;
819 							postChildren = true;
820 							return true;
821 						}
822 						popEntriesEqual();
823 						continue;
824 					}
825 					return false;
826 				}
827 
828 				currentHead = t;
829 				if (filter.matchFilter(this) == 1) {
830 					skipEntriesEqual();
831 					continue;
832 				}
833 
834 				if (recursive && FileMode.TREE.equals(t.mode)) {
835 					enterSubtree();
836 					continue;
837 				}
838 
839 				advance = true;
840 				return true;
841 			}
842 		} catch (StopWalkException stop) {
843 			stopWalk();
844 			return false;
845 		}
846 	}
847 
848 	/**
849 	 * Notify iterators the walk is aborting.
850 	 * <p>
851 	 * Primarily to notify {@link DirCacheBuildIterator} the walk is aborting so
852 	 * that it can copy any remaining entries.
853 	 *
854 	 * @throws IOException
855 	 *             if traversal of remaining entries throws an exception during
856 	 *             object access. This should never occur as remaining trees
857 	 *             should already be in memory, however the methods used to
858 	 *             finish traversal are declared to throw IOException.
859 	 */
860 	void stopWalk() throws IOException {
861 		for (AbstractTreeIterator t : trees) {
862 			t.stopWalk();
863 		}
864 	}
865 
866 	/**
867 	 * Obtain the tree iterator for the current entry.
868 	 * <p>
869 	 * Entering into (or exiting out of) a subtree causes the current tree
870 	 * iterator instance to be changed for the nth tree. This allows the tree
871 	 * iterators to manage only one list of items, with the diving handled by
872 	 * recursive trees.
873 	 *
874 	 * @param <T>
875 	 *            type of the tree iterator expected by the caller.
876 	 * @param nth
877 	 *            tree to obtain the current iterator of.
878 	 * @param clazz
879 	 *            type of the tree iterator expected by the caller.
880 	 * @return r the current iterator of the requested type; null if the tree
881 	 *         has no entry to match the current path.
882 	 */
883 	@SuppressWarnings("unchecked")
884 	public <T extends AbstractTreeIterator> T getTree(final int nth,
885 			final Class<T> clazz) {
886 		final AbstractTreeIterator t = trees[nth];
887 		return t.matches == currentHead ? (T) t : null;
888 	}
889 
890 	/**
891 	 * Obtain the raw {@link FileMode} bits for the current entry.
892 	 * <p>
893 	 * Every added tree supplies mode bits, even if the tree does not contain
894 	 * the current entry. In the latter case {@link FileMode#MISSING}'s mode
895 	 * bits (0) are returned.
896 	 *
897 	 * @param nth
898 	 *            tree to obtain the mode bits from.
899 	 * @return mode bits for the current entry of the nth tree.
900 	 * @see FileMode#fromBits(int)
901 	 */
902 	public int getRawMode(final int nth) {
903 		final AbstractTreeIterator t = trees[nth];
904 		return t.matches == currentHead ? t.mode : 0;
905 	}
906 
907 	/**
908 	 * Obtain the {@link FileMode} for the current entry.
909 	 * <p>
910 	 * Every added tree supplies a mode, even if the tree does not contain the
911 	 * current entry. In the latter case {@link FileMode#MISSING} is returned.
912 	 *
913 	 * @param nth
914 	 *            tree to obtain the mode from.
915 	 * @return mode for the current entry of the nth tree.
916 	 */
917 	public FileMode getFileMode(final int nth) {
918 		return FileMode.fromBits(getRawMode(nth));
919 	}
920 
921 	/**
922 	 * Obtain the {@link FileMode} for the current entry on the currentHead tree
923 	 *
924 	 * @return mode for the current entry of the currentHead tree.
925 	 * @since 4.3
926 	 */
927 	public FileMode getFileMode() {
928 		return FileMode.fromBits(currentHead.mode);
929 	}
930 
931 	/**
932 	 * Obtain the ObjectId for the current entry.
933 	 * <p>
934 	 * Using this method to compare ObjectId values between trees of this walker
935 	 * is very inefficient. Applications should try to use
936 	 * {@link #idEqual(int, int)} or {@link #getObjectId(MutableObjectId, int)}
937 	 * whenever possible.
938 	 * <p>
939 	 * Every tree supplies an object id, even if the tree does not contain the
940 	 * current entry. In the latter case {@link ObjectId#zeroId()} is returned.
941 	 *
942 	 * @param nth
943 	 *            tree to obtain the object identifier from.
944 	 * @return object identifier for the current tree entry.
945 	 * @see #getObjectId(MutableObjectId, int)
946 	 * @see #idEqual(int, int)
947 	 */
948 	public ObjectId getObjectId(final int nth) {
949 		final AbstractTreeIterator t = trees[nth];
950 		return t.matches == currentHead ? t.getEntryObjectId() : ObjectId
951 				.zeroId();
952 	}
953 
954 	/**
955 	 * Obtain the ObjectId for the current entry.
956 	 * <p>
957 	 * Every tree supplies an object id, even if the tree does not contain the
958 	 * current entry. In the latter case {@link ObjectId#zeroId()} is supplied.
959 	 * <p>
960 	 * Applications should try to use {@link #idEqual(int, int)} when possible
961 	 * as it avoids conversion overheads.
962 	 *
963 	 * @param out
964 	 *            buffer to copy the object id into.
965 	 * @param nth
966 	 *            tree to obtain the object identifier from.
967 	 * @see #idEqual(int, int)
968 	 */
969 	public void getObjectId(final MutableObjectId out, final int nth) {
970 		final AbstractTreeIterator t = trees[nth];
971 		if (t.matches == currentHead)
972 			t.getEntryObjectId(out);
973 		else
974 			out.clear();
975 	}
976 
977 	/**
978 	 * Compare two tree's current ObjectId values for equality.
979 	 *
980 	 * @param nthA
981 	 *            first tree to compare the object id from.
982 	 * @param nthB
983 	 *            second tree to compare the object id from.
984 	 * @return result of
985 	 *         <code>getObjectId(nthA).equals(getObjectId(nthB))</code>.
986 	 * @see #getObjectId(int)
987 	 */
988 	public boolean idEqual(final int nthA, final int nthB) {
989 		final AbstractTreeIterator ch = currentHead;
990 		final AbstractTreeIterator a = trees[nthA];
991 		final AbstractTreeIterator b = trees[nthB];
992 		if (a.matches != ch && b.matches != ch) {
993 			// If neither tree matches the current path node then neither
994 			// tree has this entry. In such case the ObjectId is zero(),
995 			// and zero() is always equal to zero().
996 			//
997 			return true;
998 		}
999 		if (!a.hasId() || !b.hasId())
1000 			return false;
1001 		if (a.matches == ch && b.matches == ch)
1002 			return a.idEqual(b);
1003 		return false;
1004 	}
1005 
1006 	/**
1007 	 * Get the current entry's name within its parent tree.
1008 	 * <p>
1009 	 * This method is not very efficient and is primarily meant for debugging
1010 	 * and final output generation. Applications should try to avoid calling it,
1011 	 * and if invoked do so only once per interesting entry, where the name is
1012 	 * absolutely required for correct function.
1013 	 *
1014 	 * @return name of the current entry within the parent tree (or directory).
1015 	 *         The name never includes a '/'.
1016 	 */
1017 	public String getNameString() {
1018 		final AbstractTreeIterator t = currentHead;
1019 		final int off = t.pathOffset;
1020 		final int end = t.pathLen;
1021 		return RawParseUtils.decode(Constants.CHARSET, t.path, off, end);
1022 	}
1023 
1024 	/**
1025 	 * Get the current entry's complete path.
1026 	 * <p>
1027 	 * This method is not very efficient and is primarily meant for debugging
1028 	 * and final output generation. Applications should try to avoid calling it,
1029 	 * and if invoked do so only once per interesting entry, where the name is
1030 	 * absolutely required for correct function.
1031 	 *
1032 	 * @return complete path of the current entry, from the root of the
1033 	 *         repository. If the current entry is in a subtree there will be at
1034 	 *         least one '/' in the returned string.
1035 	 */
1036 	public String getPathString() {
1037 		return pathOf(currentHead);
1038 	}
1039 
1040 	/**
1041 	 * Get the current entry's complete path as a UTF-8 byte array.
1042 	 *
1043 	 * @return complete path of the current entry, from the root of the
1044 	 *         repository. If the current entry is in a subtree there will be at
1045 	 *         least one '/' in the returned string.
1046 	 */
1047 	public byte[] getRawPath() {
1048 		final AbstractTreeIterator t = currentHead;
1049 		final int n = t.pathLen;
1050 		final byte[] r = new byte[n];
1051 		System.arraycopy(t.path, 0, r, 0, n);
1052 		return r;
1053 	}
1054 
1055 	/**
1056 	 * @return The path length of the current entry.
1057 	 */
1058 	public int getPathLength() {
1059 		return currentHead.pathLen;
1060 	}
1061 
1062 	/**
1063 	 * Test if the supplied path matches the current entry's path.
1064 	 * <p>
1065 	 * This method detects if the supplied path is equal to, a subtree of, or
1066 	 * not similar at all to the current entry. It is faster to use this
1067 	 * method than to use {@link #getPathString()} to first create a String
1068 	 * object, then test <code>startsWith</code> or some other type of string
1069 	 * match function.
1070 	 * <p>
1071 	 * If the current entry is a subtree, then all paths within the subtree
1072 	 * are considered to match it.
1073 	 *
1074 	 * @param p
1075 	 *            path buffer to test. Callers should ensure the path does not
1076 	 *            end with '/' prior to invocation.
1077 	 * @param pLen
1078 	 *            number of bytes from <code>buf</code> to test.
1079 	 * @return -1 if the current path is a parent to p; 0 if p matches the current
1080 	 *         path; 1 if the current path is different and will never match
1081 	 *         again on this tree walk.
1082 	 * @since 4.7
1083 	 */
1084 	public int isPathMatch(final byte[] p, final int pLen) {
1085 		final AbstractTreeIterator t = currentHead;
1086 		final byte[] c = t.path;
1087 		final int cLen = t.pathLen;
1088 		int ci;
1089 
1090 		for (ci = 0; ci < cLen && ci < pLen; ci++) {
1091 			final int c_value = (c[ci] & 0xff) - (p[ci] & 0xff);
1092 			if (c_value != 0) {
1093 				// Paths do not and will never match
1094 				return 1;
1095 			}
1096 		}
1097 
1098 		if (ci < cLen) {
1099 			// Ran out of pattern but we still had current data.
1100 			// If c[ci] == '/' then pattern matches the subtree.
1101 			// Otherwise it is a partial match == miss
1102 			return c[ci] == '/' ? 0 : 1;
1103 		}
1104 
1105 		if (ci < pLen) {
1106 			// Ran out of current, but we still have pattern data.
1107 			// If p[ci] == '/' then this subtree is a parent in the pattern,
1108 			// otherwise it's a miss.
1109 			return p[ci] == '/' && FileMode.TREE.equals(t.mode) ? -1 : 1;
1110 		}
1111 
1112 		// Both strings are identical.
1113 		return 0;
1114 	}
1115 
1116 	/**
1117 	 * Test if the supplied path matches the current entry's path.
1118 	 * <p>
1119 	 * This method tests that the supplied path is exactly equal to the current
1120 	 * entry or is one of its parent directories. It is faster to use this
1121 	 * method then to use {@link #getPathString()} to first create a String
1122 	 * object, then test <code>startsWith</code> or some other type of string
1123 	 * match function.
1124 	 * <p>
1125 	 * If the current entry is a subtree, then all paths within the subtree
1126 	 * are considered to match it.
1127 	 *
1128 	 * @param p
1129 	 *            path buffer to test. Callers should ensure the path does not
1130 	 *            end with '/' prior to invocation.
1131 	 * @param pLen
1132 	 *            number of bytes from <code>buf</code> to test.
1133 	 * @return &lt; 0 if p is before the current path; 0 if p matches the current
1134 	 *         path; 1 if the current path is past p and p will never match
1135 	 *         again on this tree walk.
1136 	 */
1137 	public int isPathPrefix(final byte[] p, final int pLen) {
1138 		final AbstractTreeIterator t = currentHead;
1139 		final byte[] c = t.path;
1140 		final int cLen = t.pathLen;
1141 		int ci;
1142 
1143 		for (ci = 0; ci < cLen && ci < pLen; ci++) {
1144 			final int c_value = (c[ci] & 0xff) - (p[ci] & 0xff);
1145 			if (c_value != 0)
1146 				return c_value;
1147 		}
1148 
1149 		if (ci < cLen) {
1150 			// Ran out of pattern but we still had current data.
1151 			// If c[ci] == '/' then pattern matches the subtree.
1152 			// Otherwise we cannot be certain so we return -1.
1153 			//
1154 			return c[ci] == '/' ? 0 : -1;
1155 		}
1156 
1157 		if (ci < pLen) {
1158 			// Ran out of current, but we still have pattern data.
1159 			// If p[ci] == '/' then pattern matches this subtree,
1160 			// otherwise we cannot be certain so we return -1.
1161 			//
1162 			return p[ci] == '/' && FileMode.TREE.equals(t.mode) ? 0 : -1;
1163 		}
1164 
1165 		// Both strings are identical.
1166 		//
1167 		return 0;
1168 	}
1169 
1170 	/**
1171 	 * Test if the supplied path matches (being suffix of) the current entry's
1172 	 * path.
1173 	 * <p>
1174 	 * This method tests that the supplied path is exactly equal to the current
1175 	 * entry, or is relative to one of entry's parent directories. It is faster
1176 	 * to use this method then to use {@link #getPathString()} to first create
1177 	 * a String object, then test <code>endsWith</code> or some other type of
1178 	 * string match function.
1179 	 *
1180 	 * @param p
1181 	 *            path buffer to test.
1182 	 * @param pLen
1183 	 *            number of bytes from <code>buf</code> to test.
1184 	 * @return true if p is suffix of the current path;
1185 	 *         false if otherwise
1186 	 */
1187 	public boolean isPathSuffix(final byte[] p, final int pLen) {
1188 		final AbstractTreeIterator t = currentHead;
1189 		final byte[] c = t.path;
1190 		final int cLen = t.pathLen;
1191 
1192 		for (int i = 1; i <= pLen; i++) {
1193 			// Pattern longer than current path
1194 			if (i > cLen)
1195 				return false;
1196 			// Current path doesn't match pattern
1197 			if (c[cLen - i] != p[pLen - i])
1198 				return false;
1199 		}
1200 
1201 		// Whole pattern tested -> matches
1202 		return true;
1203 	}
1204 
1205 	/**
1206 	 * Get the current subtree depth of this walker.
1207 	 *
1208 	 * @return the current subtree depth of this walker.
1209 	 */
1210 	public int getDepth() {
1211 		return depth;
1212 	}
1213 
1214 	/**
1215 	 * Is the current entry a subtree?
1216 	 * <p>
1217 	 * This method is faster then testing the raw mode bits of all trees to see
1218 	 * if any of them are a subtree. If at least one is a subtree then this
1219 	 * method will return true.
1220 	 *
1221 	 * @return true if {@link #enterSubtree()} will work on the current node.
1222 	 */
1223 	public boolean isSubtree() {
1224 		return FileMode.TREE.equals(currentHead.mode);
1225 	}
1226 
1227 	/**
1228 	 * Is the current entry a subtree returned after its children?
1229 	 *
1230 	 * @return true if the current node is a tree that has been returned after
1231 	 *         its children were already processed.
1232 	 * @see #isPostOrderTraversal()
1233 	 */
1234 	public boolean isPostChildren() {
1235 		return postChildren && isSubtree();
1236 	}
1237 
1238 	/**
1239 	 * Enter into the current subtree.
1240 	 * <p>
1241 	 * If the current entry is a subtree this method arranges for its children
1242 	 * to be returned before the next sibling following the subtree is returned.
1243 	 *
1244 	 * @throws MissingObjectException
1245 	 *             a subtree was found, but the subtree object does not exist in
1246 	 *             this repository. The repository may be missing objects.
1247 	 * @throws IncorrectObjectTypeException
1248 	 *             a subtree was found, and the subtree id does not denote a
1249 	 *             tree, but instead names some other non-tree type of object.
1250 	 *             The repository may have data corruption.
1251 	 * @throws CorruptObjectException
1252 	 *             the contents of a tree did not appear to be a tree. The
1253 	 *             repository may have data corruption.
1254 	 * @throws IOException
1255 	 *             a loose object or pack file could not be read.
1256 	 */
1257 	public void enterSubtree() throws MissingObjectException,
1258 			IncorrectObjectTypeException, CorruptObjectException, IOException {
1259 		attrs = null;
1260 		final AbstractTreeIterator ch = currentHead;
1261 		final AbstractTreeIterator[] tmp = new AbstractTreeIterator[trees.length];
1262 		for (int i = 0; i < trees.length; i++) {
1263 			final AbstractTreeIterator t = trees[i];
1264 			final AbstractTreeIterator n;
1265 			// If we find a GITLINK when attempting to enter a subtree, then the
1266 			// GITLINK must exist as a TREE in the index, meaning the working tree
1267 			// entry should be treated as a TREE
1268 			if (t.matches == ch && !t.eof() &&
1269 					(FileMode.TREE.equals(t.mode)
1270 							|| (FileMode.GITLINK.equals(t.mode) && t.isWorkTree())))
1271 				n = t.createSubtreeIterator(reader, idBuffer);
1272 			else
1273 				n = t.createEmptyTreeIterator();
1274 			tmp[i] = n;
1275 		}
1276 		depth++;
1277 		advance = false;
1278 		System.arraycopy(tmp, 0, trees, 0, trees.length);
1279 	}
1280 
1281 	@SuppressWarnings("unused")
1282 	AbstractTreeIterator min() throws CorruptObjectException {
1283 		int i = 0;
1284 		AbstractTreeIterator minRef = trees[i];
1285 		while (minRef.eof() && ++i < trees.length)
1286 			minRef = trees[i];
1287 		if (minRef.eof())
1288 			return minRef;
1289 
1290 		minRef.matches = minRef;
1291 		while (++i < trees.length) {
1292 			final AbstractTreeIterator t = trees[i];
1293 			if (t.eof())
1294 				continue;
1295 			final int cmp = t.pathCompare(minRef);
1296 			if (cmp < 0) {
1297 				t.matches = t;
1298 				minRef = t;
1299 			} else if (cmp == 0) {
1300 				t.matches = minRef;
1301 			}
1302 		}
1303 
1304 		return minRef;
1305 	}
1306 
1307 	void popEntriesEqual() throws CorruptObjectException {
1308 		final AbstractTreeIterator ch = currentHead;
1309 		for (int i = 0; i < trees.length; i++) {
1310 			final AbstractTreeIterator t = trees[i];
1311 			if (t.matches == ch) {
1312 				t.next(1);
1313 				t.matches = null;
1314 			}
1315 		}
1316 	}
1317 
1318 	void skipEntriesEqual() throws CorruptObjectException {
1319 		final AbstractTreeIterator ch = currentHead;
1320 		for (int i = 0; i < trees.length; i++) {
1321 			final AbstractTreeIterator t = trees[i];
1322 			if (t.matches == ch) {
1323 				t.skip();
1324 				t.matches = null;
1325 			}
1326 		}
1327 	}
1328 
1329 	void exitSubtree() {
1330 		depth--;
1331 		for (int i = 0; i < trees.length; i++)
1332 			trees[i] = trees[i].parent;
1333 
1334 		AbstractTreeIterator minRef = null;
1335 		for (final AbstractTreeIterator t : trees) {
1336 			if (t.matches != t)
1337 				continue;
1338 			if (minRef == null || t.pathCompare(minRef) < 0)
1339 				minRef = t;
1340 		}
1341 		currentHead = minRef;
1342 	}
1343 
1344 	private CanonicalTreeParser parserFor(final AnyObjectId id)
1345 			throws IncorrectObjectTypeException, IOException {
1346 		final CanonicalTreeParser p = new CanonicalTreeParser();
1347 		p.reset(reader, id);
1348 		return p;
1349 	}
1350 
1351 	static String pathOf(final AbstractTreeIterator t) {
1352 		return RawParseUtils.decode(Constants.CHARSET, t.path, 0, t.pathLen);
1353 	}
1354 
1355 	static String pathOf(final byte[] buf, int pos, int end) {
1356 		return RawParseUtils.decode(Constants.CHARSET, buf, pos, end);
1357 	}
1358 
1359 	/**
1360 	 * @param type
1361 	 *            of the tree to be queried
1362 	 * @return the tree of that type or null if none is present
1363 	 * @since 4.3
1364 	 */
1365 	public <T extends AbstractTreeIterator> T getTree(
1366 			Class<T> type) {
1367 		for (int i = 0; i < trees.length; i++) {
1368 			AbstractTreeIterator tree = trees[i];
1369 			if (type.isInstance(tree)) {
1370 				return type.cast(tree);
1371 			}
1372 		}
1373 		return null;
1374 	}
1375 
1376 	/**
1377 	 * Inspect config and attributes to return a filtercommand applicable for
1378 	 * the current path
1379 	 *
1380 	 * @param filterCommandType
1381 	 *            which type of filterCommand should be executed. E.g. "clean",
1382 	 *            "smudge"
1383 	 * @return a filter command
1384 	 * @throws IOException
1385 	 * @since 4.2
1386 	 */
1387 	public String getFilterCommand(String filterCommandType)
1388 			throws IOException {
1389 		Attributes attributes = getAttributes();
1390 
1391 		Attribute f = attributes.get(Constants.ATTR_FILTER);
1392 		if (f == null) {
1393 			return null;
1394 		}
1395 		String filterValue = f.getValue();
1396 		if (filterValue == null) {
1397 			return null;
1398 		}
1399 
1400 		String filterCommand = getFilterCommandDefinition(filterValue,
1401 				filterCommandType);
1402 		if (filterCommand == null) {
1403 			return null;
1404 		}
1405 		return filterCommand.replaceAll("%f", //$NON-NLS-1$
1406 				QuotedString.BOURNE.quote((getPathString())));
1407 	}
1408 
1409 	/**
1410 	 * Get the filter command how it is defined in gitconfig. The returned
1411 	 * string may contain "%f" which needs to be replaced by the current path
1412 	 * before executing the filter command. These filter definitions are cached
1413 	 * for better performance.
1414 	 *
1415 	 * @param filterDriverName
1416 	 *            The name of the filter driver as it is referenced in the
1417 	 *            gitattributes file. E.g. "lfs". For each filter driver there
1418 	 *            may be many commands defined in the .gitconfig
1419 	 * @param filterCommandType
1420 	 *            The type of the filter command for a specific filter driver.
1421 	 *            May be "clean" or "smudge".
1422 	 * @return the definition of the command to be executed for this filter
1423 	 *         driver and filter command
1424 	 */
1425 	private String getFilterCommandDefinition(String filterDriverName,
1426 			String filterCommandType) {
1427 		String key = filterDriverName + "." + filterCommandType; //$NON-NLS-1$
1428 		String filterCommand = filterCommandsByNameDotType.get(key);
1429 		if (filterCommand != null)
1430 			return filterCommand;
1431 		filterCommand = config.getString(ConfigConstants.CONFIG_FILTER_SECTION,
1432 				filterDriverName, filterCommandType);
1433 		boolean useBuiltin = config.getBoolean(
1434 				ConfigConstants.CONFIG_FILTER_SECTION,
1435 				filterDriverName, ConfigConstants.CONFIG_KEY_USEJGITBUILTIN, false);
1436 		if (useBuiltin) {
1437 			String builtinFilterCommand = Constants.BUILTIN_FILTER_PREFIX
1438 					+ filterDriverName + '/' + filterCommandType;
1439 			if (filterCommands != null
1440 					&& filterCommands.contains(builtinFilterCommand)) {
1441 				filterCommand = builtinFilterCommand;
1442 			}
1443 		}
1444 		if (filterCommand != null) {
1445 			filterCommandsByNameDotType.put(key, filterCommand);
1446 		}
1447 		return filterCommand;
1448 	}
1449 }