How-to: Find Who Wrote A Line in git Repository
30 Oct 2020
I’m building on a previous article
where I categorize all the rubocop issues.
My goal is to find out who committed the infraction. Not to point
fingers, just to see if there are problems I can solve further up in
the development process.
I review two ways to figure out how to get who wrote a line of code in
a git repository using git blame
, one using grep
and another using
additional git blame
syntax: -L
.
Understanding what built-in options to a program are can solve
problems better than working around it with external tools.
This article will take you less than four minutes to read.
source and more information
Introduction
I would just like a command that tells me who wrote a specific line of
a file.
Something like:
who-wrote filename line_number
Is that too much to ask for?? :-)
git blame
If the version control of the code I am investigating uses git
, then
there’s git blame
:
git blame <filename>
For example from my TDD
Callbacks
repository:
$ git blame spec/model/order_spec.rb
4aefedef ( Andrew Leung 2019-01-18 22:58:31 +0000 1) require 'rails_helper'
4aefedef ( Andrew Leung 2019-01-18 22:58:31 +0000 2)
4aefedef ( Andrew Leung 2019-01-18 22:58:31 +0000 3) RSpec.describe Order, type : :model do
68b6a236 ( Andrew Leung 2019-01-18 22:59:51 +0000 4) it 'new orders are created with :open status' do
68b6a236 ( Andrew Leung 2019-01-18 22:59:51 +0000 5) order = Order.new
68b6a236 ( Andrew Leung 2019-01-18 22:59:51 +0000 6)
68b6a236 ( Andrew Leung 2019-01-18 22:59:51 +0000 7) order.save
68b6a236 ( Andrew Leung 2019-01-18 22:59:51 +0000 8)
68b6a236 ( Andrew Leung 2019-01-18 22:59:51 +0000 9) expect( order.status) .to eq( 'open' )
68b6a236 ( Andrew Leung 2019-01-18 22:59:51 +0000 10) end
...
The format of the output of git blame
is:
<Commit SHA> (<Author> <Timestamp> <Line number>) <code>
This is good, it has what I want: for a given filename and line
number, return who wrote the code for a specific line.
It’s great to get details of the whole file. How can I narrow this
down further?
Let’s try both and see how they work.
How: grep
One way to do this is to use grep for the specific line number you want:
git blame <file> | grep <line number>
For example, line 25:
vagrant@ubuntu-xenial:~/tdd_indepth_callbacks$ git blame spec/models/order_spec.rb | grep 25
5bcbbe57 ( Andrew Leung 2019-01-18 23:10:06 +0000 25) order.save
Done, right?
What if I want line 33?
vagrant@ubuntu-xenial:~/tdd_indepth_callbacks$ git blame spec/models/order_spec.rb | grep 33
8c9461cc ( Andrew Leung 2019-01-18 23:15:53 +0000 31) order = Order.create( :amount => 0.33)
8c9461cc ( Andrew Leung 2019-01-18 23:15:53 +0000 32) order.received = 0.33
8c9461cc ( Andrew Leung 2019-01-18 23:15:53 +0000 33)
Oh, it’s easy to just grep for 33)
instead:
vagrant@ubuntu-xenial:~/tdd_indepth_callbacks$ git blame spec/models/order_spec.rb | grep 33)
bash: syntax error near unexpected token ` ) '
What if I escape it:
vagrant@ubuntu-xenial:~/tdd_indepth_callbacks$ git blame spec/models/order_spec.rb | grep 33\)
8c9461cc ( Andrew Leung 2019-01-18 23:15:53 +0000 31) order = Order.create( :amount => 0.33)
8c9461cc ( Andrew Leung 2019-01-18 23:15:53 +0000 33)
Better, not exactly what I want and it would produce false positives
or require additional filtering, definitely possible with awk
.
Is there a better way? Let’s try the next option: git blame -L
How: -L
git blame
has a feature to list a specific range of lines of a file:
git blame <file> -L <start>,<end>
documentation
vagrant@ubuntu-xenial:~/tdd_indepth_callbacks$ git blame spec/models/order_spec.rb -L 25
5bcbbe57 ( Andrew Leung 2019-01-18 23:10:06 +0000 25) order.save
5bcbbe57 ( Andrew Leung 2019-01-18 23:10:06 +0000 26)
5bcbbe57 ( Andrew Leung 2019-01-18 23:10:06 +0000 27) expect( order.status) .to eq( 'received' )
5bcbbe57 ( Andrew Leung 2019-01-18 23:10:06 +0000 28) end
8c9461cc ( Andrew Leung 2019-01-18 23:15:53 +0000 29)
8c9461cc ( Andrew Leung 2019-01-18 23:15:53 +0000 30) it 'also handles potential irrational numbers' do
8c9461cc ( Andrew Leung 2019-01-18 23:15:53 +0000 31) order = Order.create( :amount => 0.33)
...
Hmm, too much output. I wonder if I can just specify the beginning to
be the same as the end.
vagrant@ubuntu-xenial:~/tdd_indepth_callbacks$ git blame spec/models/order_spec.rb -L 25,25
5bcbbe57 ( Andrew Leung 2019-01-18 23:10:06 +0000 25) order.save
Perfect.
What about line 33? That failed miserably using grep
:
vagrant@ubuntu-xenial:~/tdd_indepth_callbacks$ git blame spec/models/order_spec.rb -L 33,33
8c9461cc ( Andrew Leung 2019-01-18 23:15:53 +0000 33)
Nice! Exactly the output expected. No additional processing needed.
Conclusion
Figuring out who wrote a specific line of code is best using the
following syntax:
git blame <filename> -L <line number>,<line number>
Which returns the output in the following format:
<Commit SHA> (<Author> <Timestamp> <Line number>) <code>
I am glad I dug a bit more into git
documentation as using grep
would have been an OK solution, overlapping numbers in the code
section would require additional (surprising) work.