Search code examples
rubygitlibgit2rugged

How to lookup commit by tag/ref using the Rugged (libgit2) Ruby gem?


I'm using Rugged, the libgit2 binding for Ruby. I have seen that you can call the Repository#lookup method to get the object at a given SHA hash in a git repository.

The thing is, I don't know the hash of the commit I'm looking for. I do know the tag id though (e.g. v1.4.2). I'd like something similar to:

# not real API!
my_repo.lookup('v1.4.2')

Or if it's the best I can do, something like this is fine:

# not real API!
sha = my_repo.get_sha_from_tag('v1.4.2')
my_repo.lookup(sha)

The trouble is that although I'm looking through the documentation, I'm unfamiliar with a lot of the low-level Git terminology being used (I had never heard of an oid until 1 hour ago, for example). So it's difficult to find what I need in the docs.

I am new to Ruby and to Rugged and to libgit2, so apologies if it seems like I missed something obvious. Thanks!


Solution

  • Background

    "OID" is not really in Git's parlance: this is rather a contraption of the authors of Rugged. Still, this term colloquially stands for "object ID", where "ID" stands for "identifier". Git presently uses SHA-1 to identify all types of objects it stores (which are: commits, trees and blobs). Hence presumably Repository#lookup expects a SHA-1 of a valid object (presumably formatted as a string containing hex-representation of that SHA-1).

    Contrary to SHA-1 names identifying various objects in the Git database, Git also has "symbolic names" for branches and tags. Those things combined are called "refs", which is short for "references" (since they, well, refer to other stuff — typically commits, but tags can refer to any kind of object at all). Also note that internally Git uses the term "heads" to refer to branches.

    What is more, Git implements a "mini language" which can be used to refer to specific stuff using combinations of ref names, SHA-1 names and operators. This is documented in the gitrevisions(7) manual page, and it should be your go-to documentation to start with. A "revision" is hence anything which may be resolved to some kind of object stored in a Git database — typically commit — using that Git's minilanguage.

    Consider reading it through comptelely, but at the very least read the 3rd paragraph of the "SPECIFYING REVISIONS" block, which starts with <refname> ... — from there, you'll learn that a full name of a tag named, say, "v1.2.3" actually is "refs/tags/v1.2.3", and the fact you may use that short name is due to Git applying its ref resolution rules detailed in that manual page.

    Solution

    So, with that knowledge at hand, a quick skim through the doc you're using brings back at least Repository#rev_parse which looks like what you need — pass it "refs/tags/v1.4.2" and be done with that.

    Note that passing it bare "v1.4.2" will also work but might have surprising result if there is no tag named like that but exists a branch with that name. So think your solution through.

    The way you found yourself will also work OK but it's a bit unnatural IMO.