threads / bug / 27927

[BUG] diff and blame difference

Subject: [BUG] diff and blame difference

## tl;dr

2 messages between Jul 26, 2011 and Jul 26, 2011.

replies: 1people: 2as markdown or json

Semyon Kirnosenko· Jul 26, 2011, 14:10 UTC · lore
Hi.

Again, I have to post about diff and blame difference problem. The initial discussion ends here: http://permalink.gmane.org/gmane.comp.version-control.git/165012

I have the same problem and now it's about non-whitespace lines. The problem is some line is marked in diff as added, but in blame it is marked as added in some older revision. And vice versa line is not marked as added in diff but it is marked in blame. Here are several examples from git repo:

Diff error in revision 198b0fb635ed8a007bac0c16eab112c5e2c7995c in file date.c. Line 184: added in diff, but blame say otherwise. Line 215: added in diff, but blame say otherwise. Line 219: added in diff, but blame say otherwise. Line 259: added in diff, but blame say otherwise. Line 260: added in diff, but blame say otherwise. Line 193: not added in diff, but blame say otherwise. Line 212: not added in diff, but blame say otherwise. Line 222: not added in diff, but blame say otherwise. Line 300: not added in diff, but blame say otherwise. Line 315: not added in diff, but blame say otherwise.

To get diff and blame i've used the following commands: git --git-dir=D:\src\git\.git diff-tree -p 198b0fb635ed8a007bac0c16eab112c5e2c7995c -- date.c > diff-tree git --git-dir=D:\src\git\.git blame -l -s 198b0fb635ed8a007bac0c16eab112c5e2c7995c -- date.c > blame

I have sent this before, but did not receive any response. I just need some type of answer. Something like "we will fix it" or "we don't care about it".

Junio C Hamano· Jul 26, 2011, 19:25 UTC · re: Semyon Kirnosenko · lore

Re: [BUG] diff and blame difference

You need to realize that diff is to express changes as deletion and insertion for humans, while blame is not about expressing changes, but showing the origin of each line.

An example. Imagine you have a file with ten lines (whose contents you will call A, B, C, ..., J). Starting from this initial state, if you make the first three lines to "X B Y", think about what happens.

Most likely, "diff" would give you a single hunk that says "you deleted A B C and then inserted X B Y", making the result look as if B was added by your change.

But that is not the only possible output "diff" could produce. It would also be a valid output if it instead showed two hunks. One hunk would delete A from the first line and add X in its place, and the other hunk would delete C from the third line and add Y in its place. But "git diff" would not do that, in order to make it more readable for humans, these adjacent changes that _could_ be in separate hunks are coalesced into a single hunk.

But "blame" is not constrained by the requirement to show a readable "patch" to humans. It is allowed to, and it does, see this change through, notice and show that B stayed from the older version. Only lines X and Y are new.

Instead of "git --git-dir=D:\src\git\.git diff-tree -p", run it with zero lines of context and you will see lines 184 and 215 indeed stayed from the previous version, which exactly explains why you thought 184 was added by looking at the output of "diff". You can tell that in fact the previous version already had that contents there by looking at "show -U0" output.

And that is what "blame" told you.

Another example that you may not have noticed with just "blame", but would have noticed if you gave it -M or -C option is this.

Starting from the same ten lines, If you move the first three lines and tuck them at the end after J, diff needs to say "remove the first three lines" and then "add these three lines at the end". There is no way for diff to say "these three lines were moved". If you look at "diff" output, you would think "the last three lines A B C were added", while "blame" can see it through and can say "A B C stayed from the beginning".

← back to recent threads