Get list of tags of remote repository without cloning using libgit2

Using this git command I can get all of the available tags of a remote repository without having to clone it:

git ls-remote --tags https://github.com/blender/blender.git

I want to replicate this using libgit2.

I can use git_tag_list (https://libgit2.org/libgit2/#HEAD/group/tag/git_tag_list) to get a list of tags, but it requires a git_repository object. I can use git_repository_open to create a git_repository object, but that only works if the repository has been cloned and exists locally on the disk. I can’t seem to find any way to create a git_repository object using a remote repository URL.

The libgit2 examples have an implementation for the ls-remote command, so it must be possible somehow:

static int use_remote(git_repository *repo, char *name)
{
    git_remote *remote = NULL;
    int error;
    const git_remote_head **refs;
    size_t refs_len, i;
    git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;

    /* Find the remote by name */
    error = git_remote_lookup(&remote, repo, name);
    if (error < 0) {
        error = git_remote_create_anonymous(&remote, repo, name);
        if (error < 0)
            goto cleanup;
    }

    /**
     * Connect to the remote and call the printing function for
     * each of the remote references.
     */
    callbacks.credentials = cred_acquire_cb;

    error = git_remote_connect(remote, GIT_DIRECTION_FETCH, &callbacks, NULL, NULL);
    if (error < 0)
        goto cleanup;

    /**
     * Get the list of references on the remote and print out
     * their name next to what they point to.
     */
    if (git_remote_ls(&refs, &refs_len, remote) < 0)
        goto cleanup;

    for (i = 0; i < refs_len; i++) {
        char oid[GIT_OID_SHA1_HEXSIZE + 1] = {0};
        git_oid_fmt(oid, &refs[i]->oid);
        printf("%s\t%s\n", oid, refs[i]->name);
    }

cleanup:
    git_remote_free(remote);
    return error;
}

/** Entry point for this command */
int lg2_ls_remote(git_repository *repo, int argc, char **argv)
{
    int error;

    if (argc < 2) {
        fprintf(stderr, "usage: %s ls-remote <remote>\n", argv[-1]);
        return EXIT_FAILURE;
    }

    error = use_remote(repo, argv[1]);

    return error;
}

(https://github.com/libgit2/libgit2/blob/ac0f2245510f6c75db1b1e7af7ca01c15dec26bc/examples/ls-remote.c)

Unfortunately this command also requires a git_repository object, so I’m at a bit of a loss. Is this currently not possible without cloning first?

>Solution :

You can utilize git_remote_create_anonymous() to create a remote object and fetch the tag list without cloning the repository locally.

Here is a sample code:

#include <git2.h>
#include <iostream>
#include <string>

int main() {
    // Initialize the libgit2 library
    git_libgit2_init();

    git_remote *remote = nullptr;
    const char *url = "https://github.com/libgit2/libgit2.git";

    // Create an anonymous remote object with the specified URL
    git_remote_create_anonymous(&remote, nullptr, url);

    // Initialize the remote callbacks structure
    git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;

    // Connect to the remote repository
    git_remote_connect(remote, GIT_DIRECTION_FETCH, &callbacks, nullptr, nullptr);

    const git_remote_head **refs;
    size_t refs_len;

    // Get the list of remote references
    git_remote_ls(&refs, &refs_len, remote);

    // Iterate through the references and print the tags
    for (size_t i = 0; i < refs_len; ++i) {
        std::string ref_name(refs[i]->name);
        if (ref_name.find("refs/tags/") == 0) {
            std::cout << "Tag: " << ref_name.substr(10) << std::endl;
        }
    }

    // Free the resources and shut down the libgit2 library
    git_remote_free(remote);
    git_libgit2_shutdown();

    return 0;
}

This code will help you obtain the tag list of a remote repository without the need to clone it locally. Please note that this code retrieves tags only for publicly accessible repositories, as we’re not providing an authentication function.

Leave a Reply