Re: Bug in "git blame -C"
From: Junio C Hamano <hidden>
Date: 2016-08-11 20:06:15
Subsystem:
the rest · Maintainer:
Linus Torvalds
Linus Torvalds [off-list ref] writes:
So this shows two problems: - the line numbers that "git blame -C" shows are the current line numbers only, not the line numbers it came from in the version it shows. That makes them useless. We _know_ the current linenumbers. What we want to know is what they were in the commit that they came from. So right now, the line number information that "git blame -C" shows is just the same thing we could have gotten by doing a "cat -n file".
Please use -f -n, which gives the origin filename and origin linenumber.
f9c03ba7 sha1_file.c 22 (Junio 2006-11-28 21:10:50 -0800 22) #endif
f9c03ba7 sha1_file.c 23 (Junio 2006-11-28 21:10:50 -0800 23) #endif
f9c03ba7 sha1_file.c 24 (Junio 2006-11-28 21:10:50 -0800 24)
f9c03ba7 git.c 21 (Junio 2006-11-28 21:10:50 -0800 25) static v..
f9c03ba7 git.c 22 (Junio 2006-11-28 21:10:50 -0800 26) {
f9c03ba7 git.c 23 (Junio 2006-11-28 21:10:50 -0800 27) co..
f9c03ba7 git.c 24 (Junio 2006-11-28 21:10:50 -0800 28) ch..
f9c03ba7 git.c 25 (Junio 2006-11-28 21:10:50 -0800 29) in..
- "git blame -C" has apparently decided that it doesn't need to show filenames that things came from, because they all came from the same commit, but that's not a logical thing to compare. "same commit" does not mean "same filename", so not showing the filename makes no sense.
This is definitely a bug, and I am sorry to have sent you to a wild goose chase (a root commit corner case that did not exist). I am not sure how often you would want the origin line-number, and I think it is debatable if we should turn show-number on in this case, but we should definitely turn show-name on when two paths are involved; that's what -C is about. For that matter, I do not think the line number in the final revision is interesting at all; they are there for hysterical raisins only (I know pickaxe imitated blame which inherited it from annotate). Something like this?
diff --git a/builtin-blame.c b/builtin-blame.c
index 066dee7..eee0b90 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c@@ -1344,29 +1344,30 @@ static void output(struct scoreboard *sb, int option) { struct blame_entry *ent; - if (option & OUTPUT_PORCELAIN) { - for (ent = sb->ent; ent; ent = ent->next) { - struct blame_entry *oth; - struct origin *suspect = ent->suspect; - struct commit *commit = suspect->commit; - if (commit->object.flags & MORE_THAN_ONE_PATH) + for (ent = sb->ent; ent; ent = ent->next) { + struct blame_entry *oth; + struct origin *suspect = ent->suspect; + struct commit *commit = suspect->commit; + + if (strcmp(suspect->path, sb->path) && + !(option & OUTPUT_PORCELAIN)) + option |= OUTPUT_SHOW_NAME | OUTPUT_SHOW_NUMBER; + if (commit->object.flags & MORE_THAN_ONE_PATH) + continue; + for (oth = ent->next; oth; oth = oth->next) { + if ((oth->suspect->commit != commit) || + !strcmp(oth->suspect->path, suspect->path)) continue; - for (oth = ent->next; oth; oth = oth->next) { - if ((oth->suspect->commit != commit) || - !strcmp(oth->suspect->path, suspect->path)) - continue; - commit->object.flags |= MORE_THAN_ONE_PATH; - break; - } + commit->object.flags |= MORE_THAN_ONE_PATH; + break; } } for (ent = sb->ent; ent; ent = ent->next) { if (option & OUTPUT_PORCELAIN) emit_porcelain(sb, ent); - else { + else emit_other(sb, ent, option); - } } }
@@ -1438,8 +1439,6 @@ static void find_alignment(struct scoreboard *sb, int *option) if (!(suspect->commit->object.flags & METAINFO_SHOWN)) { suspect->commit->object.flags |= METAINFO_SHOWN; get_commit_info(suspect->commit, &ci, 1); - if (strcmp(suspect->path, sb->path)) - *option |= OUTPUT_SHOW_NAME; num = strlen(suspect->path); if (longest_file < num) longest_file = num;