Commit 25c47aaee2c36d78a11dcddf066b82abb53819b9

Ben Straub 2013-09-20T14:31:51

Detect boundaries, support limiting commit range

diff --git a/include/git2/blame.h b/include/git2/blame.h
index fe13113..652bc81 100644
--- a/include/git2/blame.h
+++ b/include/git2/blame.h
@@ -93,6 +93,8 @@ typedef struct git_blame_options {
  * - `orig_start_line_number` is the 1-based line number where this hunk begins
  *   in the file named by `orig_path` in the commit specified by
  *   `orig_commit_id`.
+ * - `boundary` is 1 iff the hunk has been tracked to a boundary commit (the
+ *   root, or the commit specified in git_blame_options.oldest_commit)
  */
 typedef struct git_blame_hunk {
 	uint16_t lines_in_hunk;
@@ -103,6 +105,8 @@ typedef struct git_blame_hunk {
 	git_oid orig_commit_id;
 	const char *orig_path;
 	uint16_t orig_start_line_number;
+
+	char boundary;
 } git_blame_hunk;
 
 
diff --git a/src/blame.c b/src/blame.c
index a4ac84f..b7886aa 100644
--- a/src/blame.c
+++ b/src/blame.c
@@ -247,6 +247,7 @@ static git_blame_hunk* hunk_from_entry(struct blame_entry *e)
 	git_blame_hunk *h = new_hunk(
 			e->lno+1, e->num_lines, e->s_lno+1, e->suspect->path);
 	git_oid_cpy(&h->final_commit_id, git_commit_id(e->suspect->commit));
+	h->boundary = e->is_boundary ? 1 : 0;
 	return h;
 }
 
diff --git a/src/blame_git.c b/src/blame_git.c
index bff36c5..02628c4 100644
--- a/src/blame_git.c
+++ b/src/blame_git.c
@@ -456,8 +456,12 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, uint32_t op
 	GIT_UNUSED(opt);
 
 	num_sg = git_commit_parentcount(commit);
-	if (!num_sg)
+	if (!git_oid_cmp(git_commit_id(commit), &sb->blame->options.oldest_commit))
+		num_sg = 0;
+	if (!num_sg) {
+		git_oid_cpy(&sb->blame->options.oldest_commit, git_commit_id(commit));
 		goto finish;
+	}
 	else if (num_sg < (int)ARRAY_SIZE(sg_buf))
 		memset(sg_buf, 0, sizeof(sg_buf));
 	else
@@ -558,9 +562,14 @@ void assign_blame(struct scoreboard *sb, uint32_t opt)
 		pass_blame(sb, suspect, opt);
 
 		/* Take responsibility for the remaining entries */
-		for (ent = sb->ent; ent; ent = ent->next)
-			if (same_suspect(ent->suspect, suspect))
+		for (ent = sb->ent; ent; ent = ent->next) {
+			if (same_suspect(ent->suspect, suspect)) {
 				ent->guilty = 1;
+				ent->is_boundary = !git_oid_cmp(
+						git_commit_id(suspect->commit),
+						&sb->blame->options.oldest_commit);
+			}
+		}
 		origin_decref(suspect);
 	}
 }
diff --git a/src/blame_git.h b/src/blame_git.h
index 89ebc32..6af804d 100644
--- a/src/blame_git.h
+++ b/src/blame_git.h
@@ -55,6 +55,10 @@ struct blame_entry {
 	 * scanning the lines over and over.
 	 */
 	unsigned score;
+
+	/* Whether this entry has been tracked to a boundary commit.
+	 */
+	bool is_boundary;
 };
 
 /*
diff --git a/tests-clar/blame/blame_helpers.c b/tests-clar/blame/blame_helpers.c
index 25c62a1..d64bb5c 100644
--- a/tests-clar/blame/blame_helpers.c
+++ b/tests-clar/blame/blame_helpers.c
@@ -15,7 +15,7 @@ void hunk_message(size_t idx, const git_blame_hunk *hunk, const char *fmt, ...)
 }
 
 void check_blame_hunk_index(git_repository *repo, git_blame *blame, int idx,
-		int start_line, int len, const char *commit_id, const char *orig_path)
+		int start_line, int len, char boundary, const char *commit_id, const char *orig_path)
 {
 	char expected[41] = {0}, actual[41] = {0};
 	const git_blame_hunk *hunk = git_blame_get_hunk_byindex(blame, idx);
@@ -53,6 +53,12 @@ void check_blame_hunk_index(git_repository *repo, git_blame *blame, int idx,
 				hunk->orig_path, orig_path);
 	}
 	cl_assert_equal_s(hunk->orig_path, orig_path);
+
+	if (hunk->boundary != boundary) {
+		hunk_message(idx, hunk, "doesn't match boundary flag (got %d, expected %d)\n",
+				hunk->boundary, boundary);
+	}
+	cl_assert_equal_i(boundary, hunk->boundary);
 }
 
 
diff --git a/tests-clar/blame/blame_helpers.h b/tests-clar/blame/blame_helpers.h
index 15fa1c3..94321a5 100644
--- a/tests-clar/blame/blame_helpers.h
+++ b/tests-clar/blame/blame_helpers.h
@@ -9,6 +9,7 @@ void check_blame_hunk_index(
 		int idx,
 		int start_line,
 		int len,
+		char boundary,
 		const char *commit_id,
 		const char *orig_path);
 
diff --git a/tests-clar/blame/buffer.c b/tests-clar/blame/buffer.c
index 20435eb..69b2d54 100644
--- a/tests-clar/blame/buffer.c
+++ b/tests-clar/blame/buffer.c
@@ -38,7 +38,7 @@ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
 
 	cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer)));
 	cl_assert_equal_i(5, git_blame_get_hunk_count(g_bufferblame));
-	check_blame_hunk_index(g_repo, g_bufferblame, 2, 6, 1, "000000", "b.txt");
+	check_blame_hunk_index(g_repo, g_bufferblame, 2, 6, 1, 0, "000000", "b.txt");
 }
 
 void test_blame_buffer__deleted_line(void)
@@ -59,9 +59,9 @@ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\n";
 
 	cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer)));
-	check_blame_hunk_index(g_repo, g_bufferblame, 2,  6, 3, "63d671eb", "b.txt");
-	check_blame_hunk_index(g_repo, g_bufferblame, 3,  9, 1, "63d671eb", "b.txt");
-	check_blame_hunk_index(g_repo, g_bufferblame, 4, 10, 5, "aa06ecca", "b.txt");
+	check_blame_hunk_index(g_repo, g_bufferblame, 2,  6, 3, 0, "63d671eb", "b.txt");
+	check_blame_hunk_index(g_repo, g_bufferblame, 3,  9, 1, 0, "63d671eb", "b.txt");
+	check_blame_hunk_index(g_repo, g_bufferblame, 4, 10, 5, 0, "aa06ecca", "b.txt");
 }
 
 void test_blame_buffer__add_splits_hunk(void)
@@ -84,9 +84,9 @@ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\n";
 
 	cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer)));
-	check_blame_hunk_index(g_repo, g_bufferblame, 2, 6, 2, "63d671eb", "b.txt");
-	check_blame_hunk_index(g_repo, g_bufferblame, 3, 8, 1, "00000000", "b.txt");
-	check_blame_hunk_index(g_repo, g_bufferblame, 4, 9, 3, "63d671eb", "b.txt");
+	check_blame_hunk_index(g_repo, g_bufferblame, 2, 6, 2, 0, "63d671eb", "b.txt");
+	check_blame_hunk_index(g_repo, g_bufferblame, 3, 8, 1, 0, "00000000", "b.txt");
+	check_blame_hunk_index(g_repo, g_bufferblame, 4, 9, 3, 0, "63d671eb", "b.txt");
 }
 
 void test_blame_buffer__delete_crosses_hunk_boundary(void)
@@ -101,8 +101,8 @@ BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\n";
 
 	cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer)));
-	check_blame_hunk_index(g_repo, g_bufferblame, 2, 6, 1, "63d671eb", "b.txt");
-	check_blame_hunk_index(g_repo, g_bufferblame, 3, 7, 2, "aa06ecca", "b.txt");
+	check_blame_hunk_index(g_repo, g_bufferblame, 2, 6, 1, 0, "63d671eb", "b.txt");
+	check_blame_hunk_index(g_repo, g_bufferblame, 3, 7, 2, 0, "aa06ecca", "b.txt");
 }
 
 void test_blame_buffer__replace_line(void)
@@ -124,7 +124,7 @@ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\n";
 
 	cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer)));
-	check_blame_hunk_index(g_repo, g_bufferblame, 2, 6, 1, "63d671eb", "b.txt");
-	check_blame_hunk_index(g_repo, g_bufferblame, 3, 7, 1, "00000000", "b.txt");
-	check_blame_hunk_index(g_repo, g_bufferblame, 4, 8, 3, "63d671eb", "b.txt");
+	check_blame_hunk_index(g_repo, g_bufferblame, 2, 6, 1, 0, "63d671eb", "b.txt");
+	check_blame_hunk_index(g_repo, g_bufferblame, 3, 7, 1, 0, "00000000", "b.txt");
+	check_blame_hunk_index(g_repo, g_bufferblame, 4, 8, 3, 0, "63d671eb", "b.txt");
 }
diff --git a/tests-clar/blame/simple.c b/tests-clar/blame/simple.c
index ad5cf8f..79bd56b 100644
--- a/tests-clar/blame/simple.c
+++ b/tests-clar/blame/simple.c
@@ -28,8 +28,8 @@ void test_blame_simple__trivial_testrepo(void)
 	cl_git_pass(git_blame_file(&g_blame, g_repo, "branch_file.txt", NULL));
 
 	cl_assert_equal_i(2, git_blame_get_hunk_count(g_blame));
-	check_blame_hunk_index(g_repo, g_blame, 0, 1, 1, "c47800c7", "branch_file.txt");
-	check_blame_hunk_index(g_repo, g_blame, 1, 2, 1, "a65fedf3", "branch_file.txt");
+	check_blame_hunk_index(g_repo, g_blame, 0, 1, 1, 0, "c47800c7", "branch_file.txt");
+	check_blame_hunk_index(g_repo, g_blame, 1, 2, 1, 0, "a65fedf3", "branch_file.txt");
 }
 
 /*
@@ -58,10 +58,10 @@ void test_blame_simple__trivial_blamerepo(void)
 	cl_git_pass(git_blame_file(&g_blame, g_repo, "b.txt", NULL));
 
 	cl_assert_equal_i(4, git_blame_get_hunk_count(g_blame));
-	check_blame_hunk_index(g_repo, g_blame, 0,  1, 4, "da237394", "b.txt");
-	check_blame_hunk_index(g_repo, g_blame, 1,  5, 1, "b99f7ac0", "b.txt");
-	check_blame_hunk_index(g_repo, g_blame, 2,  6, 5, "63d671eb", "b.txt");
-	check_blame_hunk_index(g_repo, g_blame, 3, 11, 5, "aa06ecca", "b.txt");
+	check_blame_hunk_index(g_repo, g_blame, 0,  1, 4, 0, "da237394", "b.txt");
+	check_blame_hunk_index(g_repo, g_blame, 1,  5, 1, 1, "b99f7ac0", "b.txt");
+	check_blame_hunk_index(g_repo, g_blame, 2,  6, 5, 0, "63d671eb", "b.txt");
+	check_blame_hunk_index(g_repo, g_blame, 3, 11, 5, 0, "aa06ecca", "b.txt");
 }
 
 
@@ -147,56 +147,56 @@ void test_blame_simple__trivial_libgit2(void)
 
 	cl_git_pass(git_blame_file(&g_blame, g_repo, "include/git2.h", &opts));
 
-	check_blame_hunk_index(g_repo, g_blame,  0,  1, 1, "d12299fe", "src/git.h");
-	check_blame_hunk_index(g_repo, g_blame,  1,  2, 1, "359fc2d2", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame,  2,  3, 1, "d12299fe", "src/git.h");
-	check_blame_hunk_index(g_repo, g_blame,  3,  4, 2, "bb742ede", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame,  4,  6, 5, "d12299fe", "src/git.h");
-	check_blame_hunk_index(g_repo, g_blame,  5, 11, 1, "96fab093", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame,  6, 12, 1, "9d1dcca2", "src/git2.h");
-	check_blame_hunk_index(g_repo, g_blame,  7, 13, 1, "44908fe7", "src/git2.h");
-	check_blame_hunk_index(g_repo, g_blame,  8, 14, 1, "a15c550d", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame,  9, 15, 1, "44908fe7", "src/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 10, 16, 1, "d12299fe", "src/git.h");
-	check_blame_hunk_index(g_repo, g_blame, 11, 17, 1, "44908fe7", "src/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 12, 18, 1, "d12299fe", "src/git.h");
-	check_blame_hunk_index(g_repo, g_blame, 13, 19, 1, "44908fe7", "src/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 14, 20, 1, "638c2ca4", "src/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 15, 21, 1, "44908fe7", "src/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 16, 22, 1, "d12299fe", "src/git.h");
-	check_blame_hunk_index(g_repo, g_blame, 17, 23, 2, "44908fe7", "src/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 18, 25, 1, "bf787bd8", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 19, 26, 1, "0984c876", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 20, 27, 1, "2f8a8ab2", "src/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 21, 28, 1, "27df4275", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 22, 29, 1, "a346992f", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 23, 30, 1, "d12299fe", "src/git.h");
-	check_blame_hunk_index(g_repo, g_blame, 24, 31, 5, "44908fe7", "src/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 25, 36, 1, "65b09b1d", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 26, 37, 1, "d12299fe", "src/git.h");
-	check_blame_hunk_index(g_repo, g_blame, 27, 38, 1, "44908fe7", "src/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 28, 39, 1, "5d4cd003", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 29, 40, 1, "41fb1ca0", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 30, 41, 1, "2dc31040", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 31, 42, 1, "764df57e", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 32, 43, 1, "5280f4e6", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 33, 44, 1, "613d5eb9", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 34, 45, 1, "d12299fe", "src/git.h");
-	check_blame_hunk_index(g_repo, g_blame, 35, 46, 1, "111ee3fe", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 36, 47, 1, "f004c4a8", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 37, 48, 1, "111ee3fe", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 38, 49, 1, "9c82357b", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 39, 50, 1, "d6258deb", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 40, 51, 1, "b311e313", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 41, 52, 1, "3412391d", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 42, 53, 1, "bfc9ca59", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 43, 54, 1, "bf477ed4", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 44, 55, 1, "edebceff", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 45, 56, 1, "743a4b3b", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 46, 57, 1, "0a32dca5", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 47, 58, 1, "590fb68b", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 48, 59, 1, "bf477ed4", "include/git2.h");
-	check_blame_hunk_index(g_repo, g_blame, 49, 60, 1, "d12299fe", "src/git.h");
+	check_blame_hunk_index(g_repo, g_blame,  0,  1, 1, 0, "d12299fe", "src/git.h");
+	check_blame_hunk_index(g_repo, g_blame,  1,  2, 1, 0, "359fc2d2", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame,  2,  3, 1, 0, "d12299fe", "src/git.h");
+	check_blame_hunk_index(g_repo, g_blame,  3,  4, 2, 0, "bb742ede", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame,  4,  6, 5, 0, "d12299fe", "src/git.h");
+	check_blame_hunk_index(g_repo, g_blame,  5, 11, 1, 0, "96fab093", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame,  6, 12, 1, 0, "9d1dcca2", "src/git2.h");
+	check_blame_hunk_index(g_repo, g_blame,  7, 13, 1, 0, "44908fe7", "src/git2.h");
+	check_blame_hunk_index(g_repo, g_blame,  8, 14, 1, 0, "a15c550d", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame,  9, 15, 1, 0, "44908fe7", "src/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 10, 16, 1, 0, "d12299fe", "src/git.h");
+	check_blame_hunk_index(g_repo, g_blame, 11, 17, 1, 0, "44908fe7", "src/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 12, 18, 1, 0, "d12299fe", "src/git.h");
+	check_blame_hunk_index(g_repo, g_blame, 13, 19, 1, 0, "44908fe7", "src/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 14, 20, 1, 0, "638c2ca4", "src/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 15, 21, 1, 0, "44908fe7", "src/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 16, 22, 1, 0, "d12299fe", "src/git.h");
+	check_blame_hunk_index(g_repo, g_blame, 17, 23, 2, 0, "44908fe7", "src/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 18, 25, 1, 0, "bf787bd8", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 19, 26, 1, 0, "0984c876", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 20, 27, 1, 0, "2f8a8ab2", "src/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 21, 28, 1, 0, "27df4275", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 22, 29, 1, 0, "a346992f", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 23, 30, 1, 0, "d12299fe", "src/git.h");
+	check_blame_hunk_index(g_repo, g_blame, 24, 31, 5, 0, "44908fe7", "src/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 25, 36, 1, 0, "65b09b1d", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 26, 37, 1, 0, "d12299fe", "src/git.h");
+	check_blame_hunk_index(g_repo, g_blame, 27, 38, 1, 0, "44908fe7", "src/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 28, 39, 1, 0, "5d4cd003", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 29, 40, 1, 0, "41fb1ca0", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 30, 41, 1, 0, "2dc31040", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 31, 42, 1, 0, "764df57e", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 32, 43, 1, 0, "5280f4e6", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 33, 44, 1, 0, "613d5eb9", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 34, 45, 1, 0, "d12299fe", "src/git.h");
+	check_blame_hunk_index(g_repo, g_blame, 35, 46, 1, 0, "111ee3fe", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 36, 47, 1, 0, "f004c4a8", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 37, 48, 1, 0, "111ee3fe", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 38, 49, 1, 0, "9c82357b", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 39, 50, 1, 0, "d6258deb", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 40, 51, 1, 0, "b311e313", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 41, 52, 1, 0, "3412391d", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 42, 53, 1, 0, "bfc9ca59", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 43, 54, 1, 0, "bf477ed4", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 44, 55, 1, 0, "edebceff", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 45, 56, 1, 0, "743a4b3b", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 46, 57, 1, 0, "0a32dca5", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 47, 58, 1, 0, "590fb68b", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 48, 59, 1, 0, "bf477ed4", "include/git2.h");
+	check_blame_hunk_index(g_repo, g_blame, 49, 60, 1, 0, "d12299fe", "src/git.h");
 }
 
 
@@ -222,8 +222,8 @@ void test_blame_simple__can_restrict_lines_min(void)
 	opts.min_line = 8;
 	cl_git_pass(git_blame_file(&g_blame, g_repo, "b.txt", &opts));
 	cl_assert_equal_i(2, git_blame_get_hunk_count(g_blame));
-	check_blame_hunk_index(g_repo, g_blame, 0,  8, 3, "63d671eb", "b.txt");
-	check_blame_hunk_index(g_repo, g_blame, 1, 11, 5, "aa06ecca", "b.txt");
+	check_blame_hunk_index(g_repo, g_blame, 0,  8, 3, 0, "63d671eb", "b.txt");
+	check_blame_hunk_index(g_repo, g_blame, 1, 11, 5, 0, "aa06ecca", "b.txt");
 }
 
 /*
@@ -236,16 +236,6 @@ void test_blame_simple__can_restrict_lines_min(void)
  * da237394  4 (Ben Straub 2013-02-12 15:11:30 -0800  4
  * ^b99f7ac  1 (Ben Straub 2013-02-12 15:10:12 -0800  5
  * 63d671eb  6 (Ben Straub 2013-02-12 15:13:04 -0800  6
- *
- * $ git blame -n b.txt -L 2,7
- *    orig line no                          final line no
- * commit   V  author     timestamp                 V
- * da237394 2 (Ben Straub 2013-02-12 15:11:30 -0800 2
- * da237394 3 (Ben Straub 2013-02-12 15:11:30 -0800 3
- * da237394 4 (Ben Straub 2013-02-12 15:11:30 -0800 4
- * ^b99f7ac 1 (Ben Straub 2013-02-12 15:10:12 -0800 5
- * 63d671eb 6 (Ben Straub 2013-02-12 15:13:04 -0800 6
- * 63d671eb 7 (Ben Straub 2013-02-12 15:13:04 -0800 7
  */
 void test_blame_simple__can_restrict_lines_max(void)
 {
@@ -256,9 +246,9 @@ void test_blame_simple__can_restrict_lines_max(void)
 	opts.max_line = 6;
 	cl_git_pass(git_blame_file(&g_blame, g_repo, "b.txt", &opts));
 	cl_assert_equal_i(3, git_blame_get_hunk_count(g_blame));
-	check_blame_hunk_index(g_repo, g_blame, 0,  1, 4, "da237394", "b.txt");
-	check_blame_hunk_index(g_repo, g_blame, 1,  5, 1, "b99f7ac0", "b.txt");
-	check_blame_hunk_index(g_repo, g_blame, 2,  6, 1, "63d671eb", "b.txt");
+	check_blame_hunk_index(g_repo, g_blame, 0,  1, 4, 0, "da237394", "b.txt");
+	check_blame_hunk_index(g_repo, g_blame, 1,  5, 1, 1, "b99f7ac0", "b.txt");
+	check_blame_hunk_index(g_repo, g_blame, 2,  6, 1, 0, "63d671eb", "b.txt");
 }
 
 /*
@@ -282,7 +272,34 @@ void test_blame_simple__can_restrict_lines_both(void)
 	opts.max_line = 7;
 	cl_git_pass(git_blame_file(&g_blame, g_repo, "b.txt", &opts));
 	cl_assert_equal_i(3, git_blame_get_hunk_count(g_blame));
-	check_blame_hunk_index(g_repo, g_blame, 0,  2, 3, "da237394", "b.txt");
-	check_blame_hunk_index(g_repo, g_blame, 1,  5, 1, "b99f7ac0", "b.txt");
-	check_blame_hunk_index(g_repo, g_blame, 2,  6, 2, "63d671eb", "b.txt");
+	check_blame_hunk_index(g_repo, g_blame, 0,  2, 3, 0, "da237394", "b.txt");
+	check_blame_hunk_index(g_repo, g_blame, 1,  5, 1, 1, "b99f7ac0", "b.txt");
+	check_blame_hunk_index(g_repo, g_blame, 2,  6, 2, 0, "63d671eb", "b.txt");
+}
+
+/*
+ * $ git blame -n branch_file.txt be3563a..HEAD
+ *    orig line no                          final line no
+ * commit   V  author       timestamp                 V
+ * ^be3563a 1 (Scott Chacon 2010-05-25 11:58:27 -0700 1) hi
+ * a65fedf3 2 (Scott Chacon 2011-08-09 19:33:46 -0700 2) bye!
+ */
+void test_blame_simple__can_restrict_to_newish_commits(void)
+{
+	git_blame_options opts = GIT_BLAME_OPTIONS_INIT;
+
+	cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git")));
+
+	{
+		git_object *obj;
+		cl_git_pass(git_revparse_single(&obj, g_repo, "be3563a"));
+		git_oid_cpy(&opts.oldest_commit, git_object_id(obj));
+		git_object_free(obj);
+	}
+
+	cl_git_pass(git_blame_file(&g_blame, g_repo, "branch_file.txt", &opts));
+
+	cl_assert_equal_i(2, git_blame_get_hunk_count(g_blame));
+	check_blame_hunk_index(g_repo, g_blame, 0,  1, 1, 1, "be3563a", "branch_file.txt");
+	check_blame_hunk_index(g_repo, g_blame, 1,  2, 1, 0, "a65fedf", "branch_file.txt");
 }