git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 2/2] blame: Fix corner case when a directory becomes a file

From
Junio C Hamano <gitster@pobox.com>
Date
Jun 3, 2009, 07:43 UTC
Message-ID
<7vr5y1bw4l.fsf@alter.siamese.dyndns.org>
In-Reply-To
<4a257d91.0407560a.04d2.ffffe775@mx.google.com>
Ben Willard <benwillard@gmail.com> writes:
> find_origin() assumes that there will be only one listing in
> diff_queued_diff, but this is not the case when a directory becomes a
> file in a single commit.  So, don't fail in this case.
Thanks.
Your problem analysis is almost correct but the solution is wrong.

By the way, I'd rather not see people waste a whole _new_ test script when there are existing test scripts availble for the command.

-- >8 --
Subject: [PATCH] blame: correctly handle a path that used to be a directory

When trying to see if the same path exists in the parent, we ran "diff-tree" with pathspec set to the path we are interested in with the parent, and expect either to have exactly one resulting filepair (either "changed from the parent", "created when there was none") or nothing (when there is no change from the parent).

If the path used to be a directory, however, we will also see unbounded number of entries that talk about the files that used to exist underneath the directory in question. Correctly pick only the entry that describes the path we are interested in in such a case (namely, the creation of the path as a regular file).

Noticed by Ben Willard.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin-blame.c  |   26 ++++++++++++++++++--------
 t/t8003-blame.sh |   15 +++++++++++++++
 2 files changed, 33 insertions(+), 8 deletions(-)
diff --git a/builtin-blame.c b/builtin-blame.c
index cf74a92..0afdb16 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -362,18 +362,28 @@ static struct origin *find_origin(struct scoreboard *sb,
 			       "", &diff_opts);
 	diffcore_std(&diff_opts);
 
-	/* It is either one entry that says "modified", or "created",
-	 * or nothing.
-	 */
 	if (!diff_queued_diff.nr) {
 		/* The path is the same as parent */
 		porigin = get_origin(sb, parent, origin->path);
 		hashcpy(porigin->blob_sha1, origin->blob_sha1);
-	}
-	else if (diff_queued_diff.nr != 1)
-		die("internal error in blame::find_origin");
-	else {
-		struct diff_filepair *p = diff_queued_diff.queue[0];
+	} else {
+		/*
+		 * Since origin->path is a pathspec, if the parent
+		 * commit had it as a directory, we will see a whole
+		 * bunch of deletion of files in the directory that we
+		 * do not care about.
+		 */
+		int i;
+		struct diff_filepair *p = NULL;
+		for (i = 0; i < diff_queued_diff.nr; i++) {
+			const char *name;
+			p = diff_queued_diff.queue[i];
+			name = p->one->path ? p->one->path : p->two->path;
+			if (!strcmp(name, origin->path))
+				break;
+		}
+		if (!p)
+			die("internal error in blame::find_origin");
 		switch (p->status) {
 		default:
 			die("internal error in blame::find_origin (%c)",
diff --git a/t/t8003-blame.sh b/t/t8003-blame.sh
index 966bb0a..13c25f1 100755
--- a/t/t8003-blame.sh
+++ b/t/t8003-blame.sh
@@ -129,4 +129,19 @@ test_expect_success 'blame wholesale copy and more' '
 
 '
 
+test_expect_success 'blame path that used to be a directory' '
+	mkdir path &&
+	echo A A A A A >path/file &&
+	echo B B B B B >path/elif &&
+	git add path &&
+	test_tick &&
+	git commit -m "path was a directory" &&
+	rm -fr path &&
+	echo A A A A A >path &&
+	git add path &&
+	test_tick &&
+	git commit -m "path is a regular file" &&
+	git blame HEAD^.. -- path
+'
+
 test_done
-- 
1.6.3.1.263.g85347
Previous: Ben WillardNext: Ben Willard
Message 4 of 5 in “git-blame bug”
  1. 0/2 git-blame bugBen Willard, Jun 2, 2009
  2. 1/2 t8006: Add test to show blame failureBen Willard, Jun 2, 2009
  3. 2/2 blame: Fix corner case when a directory becomes a fileBen Willard, Jun 2, 2009
  4. Junio C HamanoJun 3, 2009
  5. Ben WillardJun 3, 2009

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.