git如何确定谁编辑了一行文件?(How does git blame determine who edited a line of a file?)


git blame file

将显示有关每一行的所有信息,例如谁在哪个提交中添加此行,以及何时,但据我所知,Git将在每次更改文件时添加一个全新的对象。 那么Git在哪里存储关于每一行的信息呢?


git blame file

will show all info about each line, for example who add this line in which commit, and when, but as far as I know, Git will add a completely new object every time you change a file. So where does Git store such info about each line?


正如@mvp所说,“它没有”。 虽然回答你的评论 - 也就是说,“这个过程的流程” - 非常类似于一系列git diff ,从文件的最新版本开始,然后向后工作,直到每一行都有一个指定的原点。

假设你有一个只有四行的短文件,它是最新的(即HEAD的版本)。 进一步假设git diff显示在修订版HEAD~1中只有前三行,我添加了最后一行(第四行)。 然后第4行的“责备”将是我的:它在之前的版本中不存在,并且当前存在,所以我必须添加它。

这就留下了弄清谁应该“责怪”这三条线的问题。 所以现在git必须对HEAD~2区分HEAD~1 。 如果那三条线都完全出现在HEAD~2 - 例如,如果从HEAD~2到HEAD~1的变化只是删除一些线 - 那么我们必须继续在历史中继续前进。

但是,在某些时候, git diff会显示某人添加了第1行,第2行和/或第3行(在某些先前版本中),可能会删除其他一些行; 或者在最坏的情况下,git将达到“root commit”:没有父母的提交。 在任何情况下,任何提交导致这些行出现的提交的人都必须是应该责备的人。

As @mvp said, "it doesn't". To answer your comment though—that is, "the flow of this process"—it works very roughly like a series of git diffs, starting with the most recent version of the file, and working backwards until every line has an assigned origin.

Suppose you have a short file with just four lines, and it is the most recent (i.e., the version in HEAD). Suppose further that git diff shows that in revision HEAD~1 there were only the first three lines, and I added that last (fourth) line. Then the "blame" for line 4 would be mine: it was not there in the previous version, and it was there in the current, so I must have added it.

That leaves the problem of figuring out who to "blame" for those three lines. So now git must diff HEAD~1 against HEAD~2. If those three lines all appear exactly as is in HEAD~2—which might be the case if, for instance, the change from HEAD~2 to HEAD~1 was simply to delete some lines—then we must keep going further back in history.

At some point, though, git diff will show that someone added line 1, line 2, and/or line 3 (in some previous version), possibly while deleting some other line(s); or in the worst case, git will reach a "root commit": a commit with no parents. In any case, whoever committed the commit(s) that caused those lines to appear, must be the one to blame.