484

I saw a lot of questions about methods of using git blame, but I don't really understand them.

I see a Blame button on top of files on the GitHub interface. Upon clicking it, it shows some diff with usernames on the left bar. What does that indicate?

Why is git blame actually used, apart from GitHub?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Himanshu Mishra
  • 8,510
  • 12
  • 37
  • 74

6 Answers6

338

From git-blame:

Annotates each line in the given file with information from the revision which last modified the line. Optionally, start annotating from the given revision.

When specified one or more times, -L restricts annotation to the requested lines.

Example:

johndoe@server.com:~# git blame .htaccess
...
^e1fb2d7 (John Doe 2015-07-03 06:30:25 -0300  4) allow from all
^72fgsdl (Arthur King 2015-07-03 06:34:12 -0300  5)
^e1fb2d7 (John Doe 2015-07-03 06:30:25 -0300  6) <IfModule mod_rewrite.c>
^72fgsdl (Arthur King 2015-07-03 06:34:12 -0300  7)     RewriteEngine On
...

Please note that git blame does not show the per-line modifications history in the chronological sense. It only shows who was the last person to have changed a line in a document up to the last commit in HEAD.

That is to say that in order to see the full history/log of a document line, you would need to run a git blame path/to/file for each commit in your git log.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mark
  • 5,437
  • 2
  • 19
  • 29
322

It's to figure out which co-worker wrote the specific line or ruined the project, so you can blame them :)

Prisoner ZERO
  • 13,848
  • 21
  • 92
  • 137
XRay
  • 3,253
  • 1
  • 10
  • 7
  • 163
    The command actually sounds like you will be *blaming* someone by running it. At least that is how it sounded to me before I learned what it did in this post. – Francisco C. Jun 09 '17 at 20:28
  • 19
    @FranciscoC. you're looking for this: https://github.com/jayphelps/git-blame-someone-else – DustWolf Apr 25 '18 at 17:43
  • 3
    @FranciscoC. wait what, doesn't it kinda do exactly that i.e. lets you _blame_ someone else? – IanDess Oct 18 '18 at 16:16
  • 27
    @IanDess Perhaps it's just semantics, but `git blame` sounds as if it would have some persisted effect, similar to `git commit`, where in fact it just informs you to of what changes were made by who. That and the negative connotation the word "blame" carries, make the command sound like something you should stay away from and leads to questions like this one seeking clarification. – Francisco C. Oct 18 '18 at 19:37
  • 44
    Clearly, it should be called `git praise`. – pfnuesel Dec 06 '18 at 19:45
  • 1
    In VS for Mac, they labeled the `git blame` as `Authors`. It makes more sense and removes the awkwardness when someone is viewing the "blame" history. – mr5 Jan 23 '20 at 05:16
  • 4
    Given Linus found the definition of Git so amusing and hence named the system after it given he considered himself one, Blame may be construed as fitting perfectly. https://en.wikipedia.org/wiki/Git_(slang) and https://www.pcworld.idg.com.au/article/129776/after_controversy_torvalds_begins_work_git_/ – volvox Feb 16 '21 at 16:51
  • I think it should be named 'view authors'. – Kristian Heitkamp Mar 11 '22 at 15:50
106

From GitHub:

The blame command is a Git feature, designed to help you determine who made changes to a file.

Despite its negative-sounding name, git blame is actually pretty innocuous; its primary function is to point out who changed which lines in a file, and why. It can be a useful tool to identify changes in your code.

Basically, git-blame is used to show what revision and author last modified each line of a file. It's like checking the history of the development of a file.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Himanshu Mishra
  • 8,510
  • 12
  • 37
  • 74
  • 2
    This seems redundant to me, you can see a diff between commits and ID the user from the commit log. If I'm understanding everything here, it has less persistence than the commit history. Maybe I'm missing something, but it seems like coding standards enforced through public humiliation. – user1431356 Feb 15 '18 at 18:03
  • 10
    I guess the name of the command was the result of the Linus' specific sense of humor :) It wasn't meant to be used to humiliate anyone :) it was just a funny (or not) pick for a name of a useful command :) – Mladen B. Mar 16 '18 at 12:29
  • 3
    @user1431356 - the point is that you want the first log line that affects a *particular line*. Otherwise you'd need to search through the logs for a particular string. (Which is indeed a viable approach - look in the man pages for "git log -S".) – azernik Apr 04 '18 at 22:49
  • 3
    The "blame" title is something that has existed for years before git. Just look at [svn's implementation](http://svnbook.red-bean.com/en/1.8/svn.ref.svn.c.blame.html). It was not a name given by Linus Torvalds. – JackAce Jul 05 '18 at 17:07
  • 3
    "I guess the name of the command was the result of the Linus' specific sense of humor :) It wasn't meant to be used to humiliate anyone :)" lol... More like it was Linus's personality and it WAS meant to humiliate someone. – Sinaesthetic Mar 09 '19 at 23:37
52

The git blame command is used to know who/which commit is responsible for the latest changes made to a file. The author/commit of each line can also been seen.

git blame filename (commits responsible for changes for all lines in code)

git blame filename -L 0,10 (commits responsible for changes from line "0" to line "10")

There are many other options for blame, but generally these could help.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bharath T S
  • 787
  • 6
  • 6
14

The git blame command is used to examine the contents of a file line by line and see when each line was last modified and who the author of the modifications was.

If there was a bug in code,use it to identify who cased it,then you can blame him. Git blame is get blame(d).

If you need to the know history of one line of code, use git log -S"code here". It is simpler than git blame.

git log vs git blame

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JackChouMine
  • 947
  • 8
  • 22
5

The git blame command annotates lines with information from the revision which last modified the line, and... with Git 2.22 (Q2 2019), will do so faster, because of a performance fix around "git blame", especially in a linear history (which is the norm we should optimize for).

See commit f892014 (02 Apr 2019) by David Kastrup (fedelibre). (Merged by Junio C Hamano -- gitster -- in commit 4d8c4da, 25 Apr 2019)

blame.c: don't drop origin blobs as eagerly

When a parent blob already has chunks queued up for blaming, dropping the blob at the end of one blame step will cause it to get reloaded right away, doubling the amount of I/O and unpacking when processing a linear history.

Keeping such parent blobs in memory seems like a reasonable optimization that should incur additional memory pressure mostly when processing the merges from old branches.


Before Git 2.41 (Q2 2023), "git blame --contents=<file> --``"(man) used to be forbidden, but now it finds the origins of lines starting at <file> contents through the history that leads to <rev>.

See commit 1a3119e (24 Mar 2023) by Jacob Keller (jacob-keller).
(Merged by Junio C Hamano -- gitster -- in commit 62df03c, 04 Apr 2023)

blame: allow --contents to work with non-HEAD commit

Signed-off-by: Jacob Keller

The --contents option can be used with git blame(man) to blame the file as if it had the contents from the specified file.
This is akin to copying the contents into the working tree and then running git blame.
This option has been supported since 1cfe773 (git-blame: no rev means start from the working tree file., 2007-01-30, Git v1.5.0-rc4 -- merge) ("git-blame: no rev means start from the working tree file.")

The --contents option always blames the file as if it was based on the current HEAD commit.
If you try to pass a revision while using --contents, you get the following error:

fatal: cannot use --contents with final commit object name

This is because the blame process generates a fake working tree commit which always uses the HEAD object as its sole parent.

Enhance fake_working_tree_commit to take the object ID to use for the parent instead of always using the HEAD object.
Then, always generate a fake commit when we have contents provided, even if we have a final object.
Remove the check to disallow --contents and a final revision.

Note that the behavior of generating a fake working commit is still skipped when a revision is provided but --contents is not provided.
Generating such a commit in that case would combine the currently checked out file contents with the provided revision, which breaks normal blame behavior and produces unexpected results.

This enables use of --contents with an arbitrary revision, rather than forcing the use of the local HEAD commit.
This makes the --contents option significantly more flexible, as it is no longer required to check out the working tree to the desired commit before using --contents.

blame-options now includes in its man page:

Pretend the file being annotated has a commit with the contents from the named file and a parent of <rev>, defaulting to HEAD when no <rev> is specified.
You may specify '-' to make the command read from the standard input for the file contents.

git blame now includes in its man page:

[ --contents <file> ] [<rev> | --reverse <rev>..<rev>] [--] <file>


Still with Git 2.41 (Q2 2023), the output given by "git blame"(man) that attributes a line to contents taken from the file specified by the --contents option shows it differently from a line attributed to the working tree file.

See commit 603d0fd (24 Apr 2023) by Jacob Keller (jacob-keller).
(Merged by Junio C Hamano -- gitster -- in commit cf85f4b, 02 May 2023)

blame: use different author name for fake commit generated by --contents

Suggested-by: Junio C Hamano
Suggested-by: Glen Choo
Signed-off-by: Jacob Keller

When the --contents option is used with git blame(man), and the contents of the file have lines which can't be annotated by the history being blamed, the user will see an author of "Not Committed Yet".
This is similar to the way blame handles working tree contents when blaming without a revision.

This is slightly confusing since this data isn't the working copy and while it is technically "not committed yet", its also coming from an external file.
Replace this author name with "External file (--contents)" to better differentiate such lines from actual working copy lines.

blame-options now includes in its man page:

Annotate using the contents from the named file, starting from <rev> if it is specified, and HEAD otherwise.
You may specify '-' to make the command read from the standard input for the file contents.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Git release notes < Git changelog on the GitHub blog << Git changelog via VonC’s activity feed – Guildenstern May 03 '23 at 19:21
  • 1
    @Guildenstern Thank you for your feedback :) It is my way to keep track of what is going on with Git, feature by feature. – VonC May 03 '23 at 21:36
  • See also [`git blame --contents=file` works in a bare repository](https://stackoverflow.com/a/49090470/6309). – VonC Aug 06 '23 at 12:52