View Javadoc
1   /*
2    * Copyright (C) 2011, Google Inc.
3    * and other copyright owners as documented in the project's IP log.
4    *
5    * This program and the accompanying materials are made available
6    * under the terms of the Eclipse Distribution License v1.0 which
7    * accompanies this distribution, is reproduced below, and is
8    * available at http://www.eclipse.org/org/documents/edl-v10.php
9    *
10   * All rights reserved.
11   *
12   * Redistribution and use in source and binary forms, with or
13   * without modification, are permitted provided that the following
14   * conditions are met:
15   *
16   * - Redistributions of source code must retain the above copyright
17   *   notice, this list of conditions and the following disclaimer.
18   *
19   * - Redistributions in binary form must reproduce the above
20   *   copyright notice, this list of conditions and the following
21   *   disclaimer in the documentation and/or other materials provided
22   *   with the distribution.
23   *
24   * - Neither the name of the Eclipse Foundation, Inc. nor the
25   *   names of its contributors may be used to endorse or promote
26   *   products derived from this software without specific prior
27   *   written permission.
28   *
29   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42   */
43  
44  package org.eclipse.jgit.blame;
45  
46  import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
47  import static org.eclipse.jgit.lib.FileMode.TYPE_FILE;
48  import static org.eclipse.jgit.lib.FileMode.TYPE_MASK;
49  
50  import java.io.IOException;
51  import java.util.Collection;
52  import java.util.Collections;
53  
54  import org.eclipse.jgit.annotations.Nullable;
55  import org.eclipse.jgit.blame.Candidate.BlobCandidate;
56  import org.eclipse.jgit.blame.Candidate.ReverseCandidate;
57  import org.eclipse.jgit.blame.ReverseWalk.ReverseCommit;
58  import org.eclipse.jgit.diff.DiffAlgorithm;
59  import org.eclipse.jgit.diff.DiffEntry;
60  import org.eclipse.jgit.diff.DiffEntry.ChangeType;
61  import org.eclipse.jgit.diff.EditList;
62  import org.eclipse.jgit.diff.HistogramDiff;
63  import org.eclipse.jgit.diff.RawText;
64  import org.eclipse.jgit.diff.RawTextComparator;
65  import org.eclipse.jgit.diff.RenameDetector;
66  import org.eclipse.jgit.internal.JGitText;
67  import org.eclipse.jgit.lib.AnyObjectId;
68  import org.eclipse.jgit.lib.MutableObjectId;
69  import org.eclipse.jgit.lib.ObjectId;
70  import org.eclipse.jgit.lib.ObjectLoader;
71  import org.eclipse.jgit.lib.ObjectReader;
72  import org.eclipse.jgit.lib.PersonIdent;
73  import org.eclipse.jgit.lib.Repository;
74  import org.eclipse.jgit.revwalk.RevCommit;
75  import org.eclipse.jgit.revwalk.RevFlag;
76  import org.eclipse.jgit.revwalk.RevWalk;
77  import org.eclipse.jgit.treewalk.TreeWalk;
78  import org.eclipse.jgit.treewalk.filter.PathFilter;
79  import org.eclipse.jgit.treewalk.filter.TreeFilter;
80  
81  /**
82   * Generate author information for lines based on a provided file.
83   * <p>
84   * Applications that want a simple one-shot computation of blame for a file
85   * should use {@link #computeBlameResult()} to prepare the entire result in one
86   * method call. This may block for significant time as the history of the
87   * repository must be traversed until information is gathered for every line.
88   * <p>
89   * Applications that want more incremental update behavior may use either the
90   * raw {@link #next()} streaming approach supported by this class, or construct
91   * a {@link BlameResult} using {@link BlameResult#create(BlameGenerator)} and
92   * incrementally construct the result with {@link BlameResult#computeNext()}.
93   * <p>
94   * This class is not thread-safe.
95   * <p>
96   * An instance of BlameGenerator can only be used once. To blame multiple files
97   * the application must create a new BlameGenerator.
98   * <p>
99   * During blame processing there are two files involved:
100  * <ul>
101  * <li>result - The file whose lines are being examined. This is the revision
102  * the user is trying to view blame/annotation information alongside of.</li>
103  * <li>source - The file that was blamed with supplying one or more lines of
104  * data into result. The source may be a different file path (due to copy or
105  * rename). Source line numbers may differ from result line numbers due to lines
106  * being added/removed in intermediate revisions.</li>
107  * </ul>
108  * <p>
109  * The blame algorithm is implemented by initially assigning responsibility for
110  * all lines of the result to the starting commit. A difference against the
111  * commit's ancestor is computed, and responsibility is passed to the ancestor
112  * commit for any lines that are common. The starting commit is blamed only for
113  * the lines that do not appear in the ancestor, if any. The loop repeats using
114  * the ancestor, until there are no more lines to acquire information on, or the
115  * file's creation point is discovered in history.
116  */
117 public class BlameGenerator implements AutoCloseable {
118 	private final Repository repository;
119 
120 	private final PathFilter resultPath;
121 
122 	private final MutableObjectId idBuf;
123 
124 	/** Revision pool used to acquire commits from. */
125 	private RevWalk revPool;
126 
127 	/** Indicates the commit was put into the queue at least once. */
128 	private RevFlag SEEN;
129 
130 	private ObjectReader reader;
131 
132 	private TreeWalk treeWalk;
133 
134 	private DiffAlgorithm diffAlgorithm = new HistogramDiff();
135 
136 	private RawTextComparator textComparator = RawTextComparator.DEFAULT;
137 
138 	private RenameDetector renameDetector;
139 
140 	/** Potential candidates, sorted by commit time descending. */
141 	private Candidate queue;
142 
143 	/** Number of lines that still need to be discovered. */
144 	private int remaining;
145 
146 	/** Blame is currently assigned to this source. */
147 	private Candidate outCandidate;
148 	private Region outRegion;
149 
150 	/**
151 	 * Create a blame generator for the repository and path (relative to
152 	 * repository)
153 	 *
154 	 * @param repository
155 	 *            repository to access revision data from.
156 	 * @param path
157 	 *            initial path of the file to start scanning (relative to the
158 	 *            repository).
159 	 */
160 	public BlameGenerator(Repository repository, String path) {
161 		this.repository = repository;
162 		this.resultPath = PathFilter.create(path);
163 
164 		idBuf = new MutableObjectId();
165 		setFollowFileRenames(true);
166 		initRevPool(false);
167 
168 		remaining = -1;
169 	}
170 
171 	private void initRevPool(boolean reverse) {
172 		if (queue != null)
173 			throw new IllegalStateException();
174 
175 		if (revPool != null)
176 			revPool.close();
177 
178 		if (reverse)
179 			revPool = new ReverseWalk(getRepository());
180 		else
181 			revPool = new RevWalk(getRepository());
182 
183 		SEEN = revPool.newFlag("SEEN"); //$NON-NLS-1$
184 		reader = revPool.getObjectReader();
185 		treeWalk = new TreeWalk(reader);
186 		treeWalk.setRecursive(true);
187 	}
188 
189 	/** @return repository being scanned for revision history. */
190 	public Repository getRepository() {
191 		return repository;
192 	}
193 
194 	/** @return path file path being processed. */
195 	public String getResultPath() {
196 		return resultPath.getPath();
197 	}
198 
199 	/**
200 	 * Difference algorithm to use when comparing revisions.
201 	 *
202 	 * @param algorithm
203 	 * @return {@code this}
204 	 */
205 	public BlameGenerator setDiffAlgorithm(DiffAlgorithm algorithm) {
206 		diffAlgorithm = algorithm;
207 		return this;
208 	}
209 
210 	/**
211 	 * Text comparator to use when comparing revisions.
212 	 *
213 	 * @param comparator
214 	 * @return {@code this}
215 	 */
216 	public BlameGenerator setTextComparator(RawTextComparator comparator) {
217 		textComparator = comparator;
218 		return this;
219 	}
220 
221 	/**
222 	 * Enable (or disable) following file renames, on by default.
223 	 * <p>
224 	 * If true renames are followed using the standard FollowFilter behavior
225 	 * used by RevWalk (which matches {@code git log --follow} in the C
226 	 * implementation). This is not the same as copy/move detection as
227 	 * implemented by the C implementation's of {@code git blame -M -C}.
228 	 *
229 	 * @param follow
230 	 *            enable following.
231 	 * @return {@code this}
232 	 */
233 	public BlameGenerator setFollowFileRenames(boolean follow) {
234 		if (follow)
235 			renameDetector = new RenameDetector(getRepository());
236 		else
237 			renameDetector = null;
238 		return this;
239 	}
240 
241 	/**
242 	 * Obtain the RenameDetector, allowing the application to configure its
243 	 * settings for rename score and breaking behavior.
244 	 *
245 	 * @return the rename detector, or {@code null} if
246 	 *         {@code setFollowFileRenames(false)}.
247 	 */
248 	@Nullable
249 	public RenameDetector getRenameDetector() {
250 		return renameDetector;
251 	}
252 
253 	/**
254 	 * Push a candidate blob onto the generator's traversal stack.
255 	 * <p>
256 	 * Candidates should be pushed in history order from oldest-to-newest.
257 	 * Applications should push the starting commit first, then the index
258 	 * revision (if the index is interesting), and finally the working tree
259 	 * copy (if the working tree is interesting).
260 	 *
261 	 * @param description
262 	 *            description of the blob revision, such as "Working Tree".
263 	 * @param contents
264 	 *            contents of the file.
265 	 * @return {@code this}
266 	 * @throws IOException
267 	 *             the repository cannot be read.
268 	 */
269 	public BlameGenerator push(String description, byte[] contents)
270 			throws IOException {
271 		return push(description, new RawText(contents));
272 	}
273 
274 	/**
275 	 * Push a candidate blob onto the generator's traversal stack.
276 	 * <p>
277 	 * Candidates should be pushed in history order from oldest-to-newest.
278 	 * Applications should push the starting commit first, then the index
279 	 * revision (if the index is interesting), and finally the working tree copy
280 	 * (if the working tree is interesting).
281 	 *
282 	 * @param description
283 	 *            description of the blob revision, such as "Working Tree".
284 	 * @param contents
285 	 *            contents of the file.
286 	 * @return {@code this}
287 	 * @throws IOException
288 	 *             the repository cannot be read.
289 	 */
290 	public BlameGenerator push(String description, RawText contents)
291 			throws IOException {
292 		if (description == null)
293 			description = JGitText.get().blameNotCommittedYet;
294 		BlobCandidate c = new BlobCandidate(description, resultPath);
295 		c.sourceText = contents;
296 		c.regionList = new Region(0, 0, contents.size());
297 		remaining = contents.size();
298 		push(c);
299 		return this;
300 	}
301 
302 	/**
303 	 * Push a candidate object onto the generator's traversal stack.
304 	 * <p>
305 	 * Candidates should be pushed in history order from oldest-to-newest.
306 	 * Applications should push the starting commit first, then the index
307 	 * revision (if the index is interesting), and finally the working tree copy
308 	 * (if the working tree is interesting).
309 	 *
310 	 * @param description
311 	 *            description of the blob revision, such as "Working Tree".
312 	 * @param id
313 	 *            may be a commit or a blob.
314 	 * @return {@code this}
315 	 * @throws IOException
316 	 *             the repository cannot be read.
317 	 */
318 	public BlameGenerator push(String description, AnyObjectId id)
319 			throws IOException {
320 		ObjectLoader ldr = reader.open(id);
321 		if (ldr.getType() == OBJ_BLOB) {
322 			if (description == null)
323 				description = JGitText.get().blameNotCommittedYet;
324 			BlobCandidate c = new BlobCandidate(description, resultPath);
325 			c.sourceBlob = id.toObjectId();
326 			c.sourceText = new RawText(ldr.getCachedBytes(Integer.MAX_VALUE));
327 			c.regionList = new Region(0, 0, c.sourceText.size());
328 			remaining = c.sourceText.size();
329 			push(c);
330 			return this;
331 		}
332 
333 		RevCommit commit = revPool.parseCommit(id);
334 		if (!find(commit, resultPath))
335 			return this;
336 
337 		Candidate c = new Candidate(commit, resultPath);
338 		c.sourceBlob = idBuf.toObjectId();
339 		c.loadText(reader);
340 		c.regionList = new Region(0, 0, c.sourceText.size());
341 		remaining = c.sourceText.size();
342 		push(c);
343 		return this;
344 	}
345 
346 	/**
347 	 * Configure the generator to compute reverse blame (history of deletes).
348 	 * <p>
349 	 * This method is expensive as it immediately runs a RevWalk over the
350 	 * history spanning the expression {@code start..end} (end being more recent
351 	 * than start) and then performs the equivalent operation as
352 	 * {@link #push(String, AnyObjectId)} to begin blame traversal from the
353 	 * commit named by {@code start} walking forwards through history until
354 	 * {@code end} blaming line deletions.
355 	 * <p>
356 	 * A reverse blame may produce multiple sources for the same result line,
357 	 * each of these is a descendant commit that removed the line, typically
358 	 * this occurs when the same deletion appears in multiple side branches such
359 	 * as due to a cherry-pick. Applications relying on reverse should use
360 	 * {@link BlameResult} as it filters these duplicate sources and only
361 	 * remembers the first (oldest) deletion.
362 	 *
363 	 * @param start
364 	 *            oldest commit to traverse from. The result file will be loaded
365 	 *            from this commit's tree.
366 	 * @param end
367 	 *            most recent commit to stop traversal at. Usually an active
368 	 *            branch tip, tag, or HEAD.
369 	 * @return {@code this}
370 	 * @throws IOException
371 	 *             the repository cannot be read.
372 	 */
373 	public BlameGenerator reverse(AnyObjectId start, AnyObjectId end)
374 			throws IOException {
375 		return reverse(start, Collections.singleton(end.toObjectId()));
376 	}
377 
378 	/**
379 	 * Configure the generator to compute reverse blame (history of deletes).
380 	 * <p>
381 	 * This method is expensive as it immediately runs a RevWalk over the
382 	 * history spanning the expression {@code start..end} (end being more recent
383 	 * than start) and then performs the equivalent operation as
384 	 * {@link #push(String, AnyObjectId)} to begin blame traversal from the
385 	 * commit named by {@code start} walking forwards through history until
386 	 * {@code end} blaming line deletions.
387 	 * <p>
388 	 * A reverse blame may produce multiple sources for the same result line,
389 	 * each of these is a descendant commit that removed the line, typically
390 	 * this occurs when the same deletion appears in multiple side branches such
391 	 * as due to a cherry-pick. Applications relying on reverse should use
392 	 * {@link BlameResult} as it filters these duplicate sources and only
393 	 * remembers the first (oldest) deletion.
394 	 *
395 	 * @param start
396 	 *            oldest commit to traverse from. The result file will be loaded
397 	 *            from this commit's tree.
398 	 * @param end
399 	 *            most recent commits to stop traversal at. Usually an active
400 	 *            branch tip, tag, or HEAD.
401 	 * @return {@code this}
402 	 * @throws IOException
403 	 *             the repository cannot be read.
404 	 */
405 	public BlameGenerator reverse(AnyObjectId start,
406 			Collection<? extends ObjectId> end) throws IOException {
407 		initRevPool(true);
408 
409 		ReverseCommit result = (ReverseCommit) revPool.parseCommit(start);
410 		if (!find(result, resultPath))
411 			return this;
412 
413 		revPool.markUninteresting(result);
414 		for (ObjectId id : end)
415 			revPool.markStart(revPool.parseCommit(id));
416 
417 		while (revPool.next() != null) {
418 			// just pump the queue
419 		}
420 
421 		ReverseCandidate c = new ReverseCandidate(result, resultPath);
422 		c.sourceBlob = idBuf.toObjectId();
423 		c.loadText(reader);
424 		c.regionList = new Region(0, 0, c.sourceText.size());
425 		remaining = c.sourceText.size();
426 		push(c);
427 		return this;
428 	}
429 
430 	/**
431 	 * Allocate a new RevFlag for use by the caller.
432 	 *
433 	 * @param name
434 	 *            unique name of the flag in the blame context.
435 	 * @return the newly allocated flag.
436 	 * @since 3.4
437 	 */
438 	public RevFlag newFlag(String name) {
439 		return revPool.newFlag(name);
440 	}
441 
442 	/**
443 	 * Execute the generator in a blocking fashion until all data is ready.
444 	 *
445 	 * @return the complete result. Null if no file exists for the given path.
446 	 * @throws IOException
447 	 *             the repository cannot be read.
448 	 */
449 	public BlameResult computeBlameResult() throws IOException {
450 		try {
451 			BlameResult r = BlameResult.create(this);
452 			if (r != null)
453 				r.computeAll();
454 			return r;
455 		} finally {
456 			close();
457 		}
458 	}
459 
460 	/**
461 	 * Step the blame algorithm one iteration.
462 	 *
463 	 * @return true if the generator has found a region's source. The getSource*
464 	 *         and {@link #getResultStart()}, {@link #getResultEnd()} methods
465 	 *         can be used to inspect the region found. False if there are no
466 	 *         more regions to describe.
467 	 * @throws IOException
468 	 *             repository cannot be read.
469 	 */
470 	public boolean next() throws IOException {
471 		// If there is a source still pending, produce the next region.
472 		if (outRegion != null) {
473 			Region r = outRegion;
474 			remaining -= r.length;
475 			if (r.next != null) {
476 				outRegion = r.next;
477 				return true;
478 			}
479 
480 			if (outCandidate.queueNext != null)
481 				return result(outCandidate.queueNext);
482 
483 			outCandidate = null;
484 			outRegion = null;
485 		}
486 
487 		// If there are no lines remaining, the entire result is done,
488 		// even if there are revisions still available for the path.
489 		if (remaining == 0)
490 			return done();
491 
492 		for (;;) {
493 			Candidate n = pop();
494 			if (n == null)
495 				return done();
496 
497 			int pCnt = n.getParentCount();
498 			if (pCnt == 1) {
499 				if (processOne(n))
500 					return true;
501 
502 			} else if (1 < pCnt) {
503 				if (processMerge(n))
504 					return true;
505 
506 			} else if (n instanceof ReverseCandidate) {
507 				// Do not generate a tip of a reverse. The region
508 				// survives and should not appear to be deleted.
509 
510 			} else /* if (pCnt == 0) */{
511 				// Root commit, with at least one surviving region.
512 				// Assign the remaining blame here.
513 				return result(n);
514 			}
515 		}
516 	}
517 
518 	private boolean done() {
519 		close();
520 		return false;
521 	}
522 
523 	private boolean result(Candidate n) throws IOException {
524 		n.beginResult(revPool);
525 		outCandidate = n;
526 		outRegion = n.regionList;
527 		return true;
528 	}
529 
530 	private boolean reverseResult(Candidate parent, Candidate source)
531 			throws IOException {
532 		// On a reverse blame present the application the parent
533 		// (as this is what did the removals), however the region
534 		// list to enumerate is the source's surviving list.
535 		Candidate res = parent.copy(parent.sourceCommit);
536 		res.regionList = source.regionList;
537 		return result(res);
538 	}
539 
540 	private Candidate pop() {
541 		Candidate n = queue;
542 		if (n != null) {
543 			queue = n.queueNext;
544 			n.queueNext = null;
545 		}
546 		return n;
547 	}
548 
549 	private void push(BlobCandidate toInsert) {
550 		Candidate c = queue;
551 		if (c != null) {
552 			c.remove(SEEN); // will be pushed by toInsert
553 			c.regionList = null;
554 			toInsert.parent = c;
555 		}
556 		queue = toInsert;
557 	}
558 
559 	private void push(Candidate toInsert) {
560 		if (toInsert.has(SEEN)) {
561 			// We have already added a Candidate for this commit to the queue,
562 			// this can happen if the commit is a merge base for two or more
563 			// parallel branches that were merged together.
564 			//
565 			// It is likely the candidate was not yet processed. The queue
566 			// sorts descending by commit time and usually descendant commits
567 			// have higher timestamps than the ancestors.
568 			//
569 			// Find the existing candidate and merge the new candidate's
570 			// region list into it.
571 			for (Candidate p = queue; p != null; p = p.queueNext) {
572 				if (p.canMergeRegions(toInsert)) {
573 					p.mergeRegions(toInsert);
574 					return;
575 				}
576 			}
577 		}
578 		toInsert.add(SEEN);
579 
580 		// Insert into the queue using descending commit time, so
581 		// the most recent commit will pop next.
582 		int time = toInsert.getTime();
583 		Candidate n = queue;
584 		if (n == null || time >= n.getTime()) {
585 			toInsert.queueNext = n;
586 			queue = toInsert;
587 			return;
588 		}
589 
590 		for (Candidate p = n;; p = n) {
591 			n = p.queueNext;
592 			if (n == null || time >= n.getTime()) {
593 				toInsert.queueNext = n;
594 				p.queueNext = toInsert;
595 				return;
596 			}
597 		}
598 	}
599 
600 	private boolean processOne(Candidate n) throws IOException {
601 		RevCommit parent = n.getParent(0);
602 		if (parent == null)
603 			return split(n.getNextCandidate(0), n);
604 		revPool.parseHeaders(parent);
605 
606 		if (find(parent, n.sourcePath)) {
607 			if (idBuf.equals(n.sourceBlob))
608 				return blameEntireRegionOnParent(n, parent);
609 			return splitBlameWithParent(n, parent);
610 		}
611 
612 		if (n.sourceCommit == null)
613 			return result(n);
614 
615 		DiffEntry r = findRename(parent, n.sourceCommit, n.sourcePath);
616 		if (r == null)
617 			return result(n);
618 
619 		if (0 == r.getOldId().prefixCompare(n.sourceBlob)) {
620 			// A 100% rename without any content change can also
621 			// skip directly to the parent.
622 			n.sourceCommit = parent;
623 			n.sourcePath = PathFilter.create(r.getOldPath());
624 			push(n);
625 			return false;
626 		}
627 
628 		Candidate next = n.create(parent, PathFilter.create(r.getOldPath()));
629 		next.sourceBlob = r.getOldId().toObjectId();
630 		next.renameScore = r.getScore();
631 		next.loadText(reader);
632 		return split(next, n);
633 	}
634 
635 	private boolean blameEntireRegionOnParent(Candidate n, RevCommit parent) {
636 		// File was not modified, blame parent.
637 		n.sourceCommit = parent;
638 		push(n);
639 		return false;
640 	}
641 
642 	private boolean splitBlameWithParent(Candidate n, RevCommit parent)
643 			throws IOException {
644 		Candidate next = n.create(parent, n.sourcePath);
645 		next.sourceBlob = idBuf.toObjectId();
646 		next.loadText(reader);
647 		return split(next, n);
648 	}
649 
650 	private boolean split(Candidate parent, Candidate source)
651 			throws IOException {
652 		EditList editList = diffAlgorithm.diff(textComparator,
653 				parent.sourceText, source.sourceText);
654 		if (editList.isEmpty()) {
655 			// Ignoring whitespace (or some other special comparator) can
656 			// cause non-identical blobs to have an empty edit list. In
657 			// a case like this push the parent alone.
658 			parent.regionList = source.regionList;
659 			push(parent);
660 			return false;
661 		}
662 
663 		parent.takeBlame(editList, source);
664 		if (parent.regionList != null)
665 			push(parent);
666 		if (source.regionList != null) {
667 			if (source instanceof ReverseCandidate)
668 				return reverseResult(parent, source);
669 			return result(source);
670 		}
671 		return false;
672 	}
673 
674 	private boolean processMerge(Candidate n) throws IOException {
675 		int pCnt = n.getParentCount();
676 
677 		// If any single parent exactly matches the merge, follow only
678 		// that one parent through history.
679 		ObjectId[] ids = null;
680 		for (int pIdx = 0; pIdx < pCnt; pIdx++) {
681 			RevCommit parent = n.getParent(pIdx);
682 			revPool.parseHeaders(parent);
683 			if (!find(parent, n.sourcePath))
684 				continue;
685 			if (!(n instanceof ReverseCandidate) && idBuf.equals(n.sourceBlob))
686 				return blameEntireRegionOnParent(n, parent);
687 			if (ids == null)
688 				ids = new ObjectId[pCnt];
689 			ids[pIdx] = idBuf.toObjectId();
690 		}
691 
692 		// If rename detection is enabled, search for any relevant names.
693 		DiffEntry[] renames = null;
694 		if (renameDetector != null) {
695 			renames = new DiffEntry[pCnt];
696 			for (int pIdx = 0; pIdx < pCnt; pIdx++) {
697 				RevCommit parent = n.getParent(pIdx);
698 				if (ids != null && ids[pIdx] != null)
699 					continue;
700 
701 				DiffEntry r = findRename(parent, n.sourceCommit, n.sourcePath);
702 				if (r == null)
703 					continue;
704 
705 				if (n instanceof ReverseCandidate) {
706 					if (ids == null)
707 						ids = new ObjectId[pCnt];
708 					ids[pCnt] = r.getOldId().toObjectId();
709 				} else if (0 == r.getOldId().prefixCompare(n.sourceBlob)) {
710 					// A 100% rename without any content change can also
711 					// skip directly to the parent. Note this bypasses an
712 					// earlier parent that had the path (above) but did not
713 					// have an exact content match. For performance reasons
714 					// we choose to follow the one parent over trying to do
715 					// possibly both parents.
716 					n.sourcePath = PathFilter.create(r.getOldPath());
717 					return blameEntireRegionOnParent(n, parent);
718 				}
719 
720 				renames[pIdx] = r;
721 			}
722 		}
723 
724 		// Construct the candidate for each parent.
725 		Candidate[] parents = new Candidate[pCnt];
726 		for (int pIdx = 0; pIdx < pCnt; pIdx++) {
727 			RevCommit parent = n.getParent(pIdx);
728 
729 			Candidate p;
730 			if (renames != null && renames[pIdx] != null) {
731 				p = n.create(parent,
732 						PathFilter.create(renames[pIdx].getOldPath()));
733 				p.renameScore = renames[pIdx].getScore();
734 				p.sourceBlob = renames[pIdx].getOldId().toObjectId();
735 			} else if (ids != null && ids[pIdx] != null) {
736 				p = n.create(parent, n.sourcePath);
737 				p.sourceBlob = ids[pIdx];
738 			} else {
739 				continue;
740 			}
741 
742 			EditList editList;
743 			if (n instanceof ReverseCandidate
744 					&& p.sourceBlob.equals(n.sourceBlob)) {
745 				// This special case happens on ReverseCandidate forks.
746 				p.sourceText = n.sourceText;
747 				editList = new EditList(0);
748 			} else {
749 				p.loadText(reader);
750 				editList = diffAlgorithm.diff(textComparator,
751 						p.sourceText, n.sourceText);
752 			}
753 
754 			if (editList.isEmpty()) {
755 				// Ignoring whitespace (or some other special comparator) can
756 				// cause non-identical blobs to have an empty edit list. In
757 				// a case like this push the parent alone.
758 				if (n instanceof ReverseCandidate) {
759 					parents[pIdx] = p;
760 					continue;
761 				}
762 
763 				p.regionList = n.regionList;
764 				n.regionList = null;
765 				parents[pIdx] = p;
766 				break;
767 			}
768 
769 			p.takeBlame(editList, n);
770 
771 			// Only remember this parent candidate if there is at least
772 			// one region that was blamed on the parent.
773 			if (p.regionList != null) {
774 				// Reverse blame requires inverting the regions. This puts
775 				// the regions the parent deleted from us into the parent,
776 				// and retains the common regions to look at other parents
777 				// for deletions.
778 				if (n instanceof ReverseCandidate) {
779 					Region r = p.regionList;
780 					p.regionList = n.regionList;
781 					n.regionList = r;
782 				}
783 
784 				parents[pIdx] = p;
785 			}
786 		}
787 
788 		if (n instanceof ReverseCandidate) {
789 			// On a reverse blame report all deletions found in the children,
790 			// and pass on to them a copy of our region list.
791 			Candidate resultHead = null;
792 			Candidate resultTail = null;
793 
794 			for (int pIdx = 0; pIdx < pCnt; pIdx++) {
795 				Candidate p = parents[pIdx];
796 				if (p == null)
797 					continue;
798 
799 				if (p.regionList != null) {
800 					Candidate r = p.copy(p.sourceCommit);
801 					if (resultTail != null) {
802 						resultTail.queueNext = r;
803 						resultTail = r;
804 					} else {
805 						resultHead = r;
806 						resultTail = r;
807 					}
808 				}
809 
810 				if (n.regionList != null) {
811 					p.regionList = n.regionList.deepCopy();
812 					push(p);
813 				}
814 			}
815 
816 			if (resultHead != null)
817 				return result(resultHead);
818 			return false;
819 		}
820 
821 		// Push any parents that are still candidates.
822 		for (int pIdx = 0; pIdx < pCnt; pIdx++) {
823 			if (parents[pIdx] != null)
824 				push(parents[pIdx]);
825 		}
826 
827 		if (n.regionList != null)
828 			return result(n);
829 		return false;
830 	}
831 
832 	/**
833 	 * Get the revision blamed for the current region.
834 	 * <p>
835 	 * The source commit may be null if the line was blamed to an uncommitted
836 	 * revision, such as the working tree copy, or during a reverse blame if the
837 	 * line survives to the end revision (e.g. the branch tip).
838 	 *
839 	 * @return current revision being blamed.
840 	 */
841 	public RevCommit getSourceCommit() {
842 		return outCandidate.sourceCommit;
843 	}
844 
845 	/** @return current author being blamed. */
846 	public PersonIdent getSourceAuthor() {
847 		return outCandidate.getAuthor();
848 	}
849 
850 	/** @return current committer being blamed. */
851 	public PersonIdent getSourceCommitter() {
852 		RevCommit c = getSourceCommit();
853 		return c != null ? c.getCommitterIdent() : null;
854 	}
855 
856 	/** @return path of the file being blamed. */
857 	public String getSourcePath() {
858 		return outCandidate.sourcePath.getPath();
859 	}
860 
861 	/** @return rename score if a rename occurred in {@link #getSourceCommit}. */
862 	public int getRenameScore() {
863 		return outCandidate.renameScore;
864 	}
865 
866 	/**
867 	 * @return first line of the source data that has been blamed for the
868 	 *         current region. This is line number of where the region was added
869 	 *         during {@link #getSourceCommit()} in file
870 	 *         {@link #getSourcePath()}.
871 	 */
872 	public int getSourceStart() {
873 		return outRegion.sourceStart;
874 	}
875 
876 	/**
877 	 * @return one past the range of the source data that has been blamed for
878 	 *         the current region. This is line number of where the region was
879 	 *         added during {@link #getSourceCommit()} in file
880 	 *         {@link #getSourcePath()}.
881 	 */
882 	public int getSourceEnd() {
883 		Region r = outRegion;
884 		return r.sourceStart + r.length;
885 	}
886 
887 	/**
888 	 * @return first line of the result that {@link #getSourceCommit()} has been
889 	 *         blamed for providing. Line numbers use 0 based indexing.
890 	 */
891 	public int getResultStart() {
892 		return outRegion.resultStart;
893 	}
894 
895 	/**
896 	 * @return one past the range of the result that {@link #getSourceCommit()}
897 	 *         has been blamed for providing. Line numbers use 0 based indexing.
898 	 *         Because a source cannot be blamed for an empty region of the
899 	 *         result, {@link #getResultEnd()} is always at least one larger
900 	 *         than {@link #getResultStart()}.
901 	 */
902 	public int getResultEnd() {
903 		Region r = outRegion;
904 		return r.resultStart + r.length;
905 	}
906 
907 	/**
908 	 * @return number of lines in the current region being blamed to
909 	 *         {@link #getSourceCommit()}. This is always the value of the
910 	 *         expression {@code getResultEnd() - getResultStart()}, but also
911 	 *         {@code getSourceEnd() - getSourceStart()}.
912 	 */
913 	public int getRegionLength() {
914 		return outRegion.length;
915 	}
916 
917 	/**
918 	 * @return complete contents of the source file blamed for the current
919 	 *         output region. This is the contents of {@link #getSourcePath()}
920 	 *         within {@link #getSourceCommit()}. The source contents is
921 	 *         temporarily available as an artifact of the blame algorithm. Most
922 	 *         applications will want the result contents for display to users.
923 	 */
924 	public RawText getSourceContents() {
925 		return outCandidate.sourceText;
926 	}
927 
928 	/**
929 	 * @return complete file contents of the result file blame is annotating.
930 	 *         This value is accessible only after being configured and only
931 	 *         immediately before the first call to {@link #next()}. Returns
932 	 *         null if the path does not exist.
933 	 * @throws IOException
934 	 *             repository cannot be read.
935 	 * @throws IllegalStateException
936 	 *             {@link #next()} has already been invoked.
937 	 */
938 	public RawText getResultContents() throws IOException {
939 		return queue != null ? queue.sourceText : null;
940 	}
941 
942 	/**
943 	 * Release the current blame session.
944 	 *
945 	 * @since 4.0
946 	 */
947 	@Override
948 	public void close() {
949 		revPool.close();
950 		queue = null;
951 		outCandidate = null;
952 		outRegion = null;
953 	}
954 
955 	private boolean find(RevCommit commit, PathFilter path) throws IOException {
956 		treeWalk.setFilter(path);
957 		treeWalk.reset(commit.getTree());
958 		if (treeWalk.next() && isFile(treeWalk.getRawMode(0))) {
959 			treeWalk.getObjectId(idBuf, 0);
960 			return true;
961 		}
962 		return false;
963 	}
964 
965 	private static final boolean isFile(int rawMode) {
966 		return (rawMode & TYPE_MASK) == TYPE_FILE;
967 	}
968 
969 	private DiffEntry findRename(RevCommit parent, RevCommit commit,
970 			PathFilter path) throws IOException {
971 		if (renameDetector == null)
972 			return null;
973 
974 		treeWalk.setFilter(TreeFilter.ANY_DIFF);
975 		treeWalk.reset(parent.getTree(), commit.getTree());
976 		renameDetector.reset();
977 		renameDetector.addAll(DiffEntry.scan(treeWalk));
978 		for (DiffEntry ent : renameDetector.compute()) {
979 			if (isRename(ent) && ent.getNewPath().equals(path.getPath()))
980 				return ent;
981 		}
982 		return null;
983 	}
984 
985 	private static boolean isRename(DiffEntry ent) {
986 		return ent.getChangeType() == ChangeType.RENAME
987 				|| ent.getChangeType() == ChangeType.COPY;
988 	}
989 }