Search code examples
gitawkbranchreflog

What is the most robust way to get the name of the reference last pointed to by HEAD?


After an operation that moves HEAD (such as checkout, reset, etc.), you can always get the commit ID that HEAD pointed to before that operation by running, for instance,

git rev-parse @{1}

What I'm interested in, though, is getting the name of the reference (if any) that HEAD last pointed to. Here's an example that illustrates what I want. Let's say my repo looks as follows:

enter image description here

Then I check out the develop branch by running

git checkout develop

and end up with

enter image description here

How can I retrieve the information, from my repo's entrails, that HEAD was pointing at master, before that last checkout operation?

This answer suggests extracting the name from the reflog with awk as a possibility; for instance, with

git reflog -1 | awk '{ print $6; exit }'

(thanks to Ed and Etan for their suggestions).

As far as I can tell, that works well enough. It even prints the SHA of the previous commit, in case HEAD was detached before the last checkout.

However, the OP raises concerns about robustness and backward compatibility in his comment:

I am marking this answer as correct (which it is, technically), for want of a cleaner approach. However, I am not convinced that the string's format being hard-coded into Git's source code is a good thing, as it means it could break unexpectedly (i.e. in a later version of Git).

Are the OP's concerns legitimate? What is the most robust way to do that?


Solution

  • In some quick tests this seems to work fairly well (though the tests were not at all thorough or stressing of weird scenarios):

    git rev-parse --symbolic-full-name @{-1}
    

    I was in the middle of posting a comment on @EmilDavtyan's answer saying that the multi-ref issue is problematic since I don't think git cares (and so doesn't track) the last location of the HEAD ref but then I remembered @{-1} and how that would be of much less use if it couldn't handle this situation and so after a quick test it seems that it does somehow (it might very well be parsing the message in the reflog for all that I know).

    I should also point out that the linked OP is correct that manually parsing the reflog is not reliable. In fact when I went to test the awk snippet here I didn't get the correct results. Turns out that is because I have --decorate on by default which was padding the line with extra fields and throwing off the count.