Search code examples
gitgit-show

Git show: Show blob in revision selected by text


I know that you can select a revision using the :/<text>-syntax documented in gitrevisions(1), e.g.

git show :/"new change"

would show the (youngest reachable) commit with "new change" in the commit message.

I also often use the feature to git show a blob in a specific revision, e.g.

git show myBranch:./coolFile.csv

to view the whole content of coolFile.csv (in a relative path to me) in the state of revision myBranch.

Now my question: Can I select a revision using the :/<text> syntax and then show a blob in that revision? I have tried

git show (:/"new change"):./coolFile.csv
git show :/"new change":./coolFile.csv

That threw the error

fatal: ambiguous argument ':/new change:./coolFile.csv': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git [<revision>...] -- [<file>...]'

so I tried

git show :/"new change" -- ./coolFile.csv

which printed nothing because that syntax only prints the changes of that revision in that file.


Solution

  • Command substitution (as in Romain Valeri's answer) or some other two-step process is usually the way to go. Note, however, that the problem here is syntactic: :/regex has no way to terminate the regular expression and resume a revision specifier. If we look at the gitrevisions documentation, we find that this :/regex or :/<text> syntax:

    ... names a commit whose commit message matches the specified regular expression. This name returns the youngest matching commit which is reachable from any ref, including HEAD

    (boldface mine).

    Shortly above this description for :/<text> we find:

    ^{/<text>}, e.g. HEAD^{/fix nasty bug}

    described this way:

    ... is the same as the :/fix nasty bug syntax below except that it returns the youngest matching commit which is reachable from the <rev> before ^.

    This syntax does have the equivalent of a "close parenthesis", namely the closing brace. So if you're willing to search from HEAD or some other single ref exclusively, rather than from every ref, you can replace :/foo with HEAD^{/foo}, and this can be followed by :./coolFile.csv:

    git show HEAD^{/new\ change}:./coolFile.csv
    

    The fact that some revspec arguments cannot be appended-to was missed in some shell-script Git commands for some time, where people did things like:

    set -e     # if/as appropriate
    cmt=$(git rev-parse "$1"^{commit})
    tree=$(git rev-parse "$1"^{tree})
    ... go on to use $cmt as the commit and $tree as the tree ...
    

    when in fact we must do:

    t=$(git rev-parse "$1")
    cmt=$(git rev-parse $t^{commit})
    tree=$(git rev-parse $t^{tree})
    

    in case $1 reads :/fix nasty bug for instance.