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