Search code examples
gittagscommand-line-interfaceblamegit-blame

Git blame command to view the latest tag for each line


I am searching for something like git blame but instead of showing the commit the line was last changed in, I am interested in what version this line was committed.

So instead of the revision ID, I need the most recent tag at the time of the commit.


Solution

  • You can use the command

    $ git blame <file> | awk '{ cmd="git describe --always --tags --abbrev=0 $(echo "$1" | tr -d \"^\") | tr -d \"\n\""; cmd | getline tag; $1=tag; close(cmd); print }'
    

    or in long form

    $ git blame <file> | awk '{ 
        cmd="git describe --always --tags --abbrev=0 \
                $(echo " $1 " | tr -d \"^\") | tr -d \"\n\""
        cmd | getline tag
        $1=tag
        close(cmd)
        print 
    }'
    

    This command replaces the first column in the git-blame output with the output of git describe --always --tags --abbrev=0 <rev>. The first column will contain one of two possible values:

    • If a tag exists in the commit's history, the first column will be the name of the first ancestor tag.
    • If no tag exists in the commit's history, the first column will be the full commit ID.

    If you want to pad/truncate the first column to have a fixed number of characters, you can use

    $ git blame <file> | awk '{ cmd="git describe --always --tags --abbrev=0 $(echo "$1" | tr -d \"^\") | tr -d \"\n\" | xargs -0 printf %10s | head -c10"; cmd | getline tag; $1=tag; close(cmd); print }'
    

    which adds | xargs -0 printf %10s | head -c10" to marshal the first column to have exactly 10 characters. Replace both instances of 10 with your desired width.

    Here's an example of the output using the README file from CPython:

     v3.12.0b1 README.rst (Thomas Wouters 2023-05-22 21:15:32 +0200 1) This is Python version 3.13.0 alpha 0
     v3.11.0b1 README.rst (Pablo Galindo 2022-05-08 03:40:52 +0100 2) =====================================
        v1.6a1 README (Guido van Rossum 2000-04-11 17:11:09 +0000 3)
      v3.9.0a1 README.rst (Steve Dower 2019-12-16 11:15:08 -0800 4) .. image:: https://github.com/python/cpython/workflows/Tests/badge.svg
      v3.9.0a1 README.rst (Steve Dower 2019-12-16 11:15:08 -0800 5) :alt: CPython build status on GitHub Actions
      v3.9.0a1 README.rst (Steve Dower 2019-12-16 11:15:08 -0800 6) :target: https://github.com/python/cpython/actions
      v3.9.0a1 README.rst (Steve Dower 2019-12-16 11:15:08 -0800 7)
     v3.10.0a7 README.rst (Pablo Galindo 2021-05-03 23:36:55 +0100 8) .. image:: https://dev.azure.com/python/cpython/_apis/build/status/Azure%20Pipelines%20CI?branchName=main
      v3.7.0a4 README.rst (Steve Dower 2018-09-24 08:04:33 -0400 9) :alt: CPython build status on Azure DevOps
     v3.10.0a7 README.rst (Pablo Galindo 2021-05-03 23:36:55 +0100 10) :target: https://dev.azure.com/python/cpython/_build/latest?definitionId=4&branchName=main
      v3.7.0a4 README.rst (Steve Dower 2018-08-31 08:11:35 -0700 11)
     v3.10.0a6 README.rst (Erlend Egeberg Aasland 2021-04-02 05:30:40 +0200 12) .. image:: https://img.shields.io/badge/discourse-join_chat-brightgreen.svg
     v3.10.0a6 README.rst (Erlend Egeberg Aasland 2021-04-02 05:30:40 +0200 13) :alt: Python Discourse chat
     v3.10.0a6 README.rst (Erlend Egeberg Aasland 2021-04-02 05:30:40 +0200 14) :target: https://discuss.python.org/
      v3.7.0a4 README.rst (Steve Dower 2018-08-31 08:11:35 -0700 15)
      v3.7.0a4 README.rst (Mariatta 2018-06-29 13:43:45 -0700 16)
     v3.12.0a3 README.rst (Benjamin Peterson 2023-01-08 09:13:25 -0600 17) Copyright © 2001-2023 Python Software Foundation. All rights reserved.
          v2.4 README (Guido van Rossum 2007-08-30 17:16:55 +0000 18)
      v3.6.0b2 README.rst (Zachary Ware 2017-02-13 22:01:03 -0600 19) See the end of this file for further copyright and license information.
    

    Some additional implementation notes

    • --always is needed in the git describe invocation to output the commit ID when no tag can be found.
    • --abbrev=0 is needed in the git describe invocation to only output the closest tag.
    • --tags in the git describe invocation enables both lightweight and annotated tags.
    • The revision from git blame is processed through tr -d "^" to remove the ^ prefix present when the line was last modified in the root commit.