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