Search code examples
gitblame

Git: discover which commits ever touched a range of lines


I'm having trouble figuring out how to use git blame for getting the set of commits that ever touched a given range of lines. There are similar questions like this one but the accepted answer doesn't bring me much further.

Let's say I have a definition that starts on line 1000 of foo.rb. It's only only 5 lines long, but the number of commits that ever changed those lines is enormous. If I do

git blame foo.rb -L 1000,+5

I get references to (at most) five distinct commits that changed these lines, but I'm also interested in the commits "behind them".

Similarly,

git rev-list HEAD -- foo.rb | xargs git log --oneline

is almost what I want, but I can't specify line ranges to git rev-list

Can I pass a flag to git blame to get the list of commits that ever touched those five lines, or what's the quickest way to build a script that extracts such information? Let's ignore for the moment the possibility that the definition once had more or less than 5 lines.


Solution

  • Since Git 1.8.4, git log has -L to view the evolution of a range of lines.

    For example, suppose you look at git blame's output:

    ((aa27064...))[mlm@macbook:~/w/mlm/git]
    $ git blame -L150,+11 -- git-web--browse.sh
    a180055a git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:36 +0100 150)            die "The browser $browser is not
    a180055a git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:36 +0100 151)    fi
    5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 152) fi
    5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 153) 
    5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 154) case "$browser" in
    81f42f11 git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:38 +0100 155) firefox|iceweasel|seamonkey|iceape)
    5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 156)    # Check version because firefox < 2.0 do
    5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 157)    vers=$(expr "$($browser_path -version)" 
    5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 158)    NEWTAB='-new-tab'
    5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 159)    test "$vers" -lt 2 && NEWTAB=''
    a0685a4f git-web--browse.sh (Dmitry Potapov   2008-02-09 23:22:22 -0800 160)    "$browser_path" $NEWTAB "$@" &
    

    And you want to know the history of what is now line 155.

    Then:

    ((aa27064...))[mlm@macbook:~/w/mlm/git]
    $ git log --topo-order --graph -u -L 155,155:git-web--browse.sh
    * commit 81f42f11496b9117273939c98d270af273c8a463
    | Author: Giuseppe Bilotta <[email protected]>
    | Date:   Fri Dec 3 17:47:38 2010 +0100
    | 
    |     web--browse: support opera, seamonkey and elinks
    |     
    |     The list of supported browsers is also updated in the documentation.
    |     
    |     Signed-off-by: Giuseppe Bilotta <[email protected]>
    |     Signed-off-by: Junio C Hamano <[email protected]>
    | 
    | diff --git a/git-web--browse.sh b/git-web--browse.sh
    | --- a/git-web--browse.sh
    | +++ b/git-web--browse.sh
    | @@ -143,1 +143,1 @@
    | -firefox|iceweasel)
    | +firefox|iceweasel|seamonkey|iceape)
    |  
    * commit a180055a47c6793eaaba6289f623cff32644215b
    | Author: Giuseppe Bilotta <[email protected]>
    | Date:   Fri Dec 3 17:47:36 2010 +0100
    | 
    |     web--browse: coding style
    |     
    |     Retab and deindent choices in case statements.
    |     
    |     Signed-off-by: Giuseppe Bilotta <[email protected]>
    |     Signed-off-by: Junio C Hamano <[email protected]>
    | 
    | diff --git a/git-web--browse.sh b/git-web--browse.sh
    | --- a/git-web--browse.sh
    | +++ b/git-web--browse.sh
    | @@ -142,1 +142,1 @@
    | -    firefox|iceweasel)
    | +firefox|iceweasel)
    |  
    * commit 5884f1fe96b33d9666a78e660042b1e3e5f9f4d9
      Author: Christian Couder <[email protected]>
      Date:   Sat Feb 2 07:32:53 2008 +0100
    
          Rename 'git-help--browse.sh' to 'git-web--browse.sh'.
    
          Signed-off-by: Christian Couder <[email protected]>
          Signed-off-by: Junio C Hamano <[email protected]>
    
      diff --git a/git-web--browse.sh b/git-web--browse.sh
      --- /dev/null
      +++ b/git-web--browse.sh
      @@ -0,0 +127,1 @@
      +    firefox|iceweasel)
    

    If you use this functionality frequently, you might find a git alias useful. To do that, put in your ~/.gitconfig:

    [alias]
        # Follow evolution of certain lines in a file
        # arg1=file, arg2=first line, arg3=last line or blank for just the first line
        follow = "!sh -c 'git log --topo-order -u -L $2,${3:-$2}:"$1"'" -
    

    And now you can just do git follow git-web--browse.sh 155.