gitpathgit-show

using "git show" with an absolute path


When I run git show HEAD^:file.txt git displays the content of this file at revision HEAD^. But when I run this command with the absolute path, i.e.: git show HEAD^:/home/me/repo/file.txt it fails (exit code 128) with the message

fatal: path '/home/me/repo/file.txt' exists on disk, but not in 'HEAD^'

What would be an elegant way to show my file at revision HEAD^ when all my script has is the full path?


More details:


Solution

  • You can use git rev-parse --show-toplevel to find the path to the worktree of any repo, then compute the path of your file relative to this worktree directory.

    filepath=$1
    
    worktree=$(git rev-parse --show-toplevel)
    relpath=$(realpath -s --relative-to="$worktree" "$filepath")
    
    git show -C "$worktree" HEAD^:"$relpath"
    

    If you want to do this with any revision (not just HEAD^), you should either have your script take the revision and the file path as 2 separate arguments, or split the unique argument revision:filepath in 2 parts yourself.


    One element about why <HEAD>:<abspath> doesn't work as you expect:

    <revision>:<path> is a pretty low level notation to point at anything under a tree. If you feed it to git rev-parse or git cat-file for example, you will see the hash/type/content of the blob or subtree that is pointed to:

    $ git rev-parse HEAD:path/to/file
    7bb43a8cc90a1accbb6a167f9ed7c62af3f15b92
    $ git cat-file -t HEAD:path/to/file
    blob
    $ git cat-file -p HEAD:path/to/file
    -- ... content ... --
    

    It is actually not restricted to commits, <revision> can also be any tree :

    $ git rev-parse HEAD:path/to
    eacf32b...
    $ git rev-parse eacf32b:file.txt
    7bb43a8c..
    

    Converting the string <revision>:<path> into the id of a git object is one of the first action that is taken (it is not specific to the git show command for example).

    And this action is implemented by just looking at paths that exist within the git database.