【问题标题】:Listing all commits in a branch using libgit2使用 libgit2 列出分支中的所有提交
【发布时间】:2013-07-29 00:18:08
【问题描述】:

如何使用 libgit2 遍历分支的所有提交?

我已经有以下代码,但它无法编译。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <git2.h>

int main(int argc, char *argv[]){
    git_repository *repo;
    git_repository_open(&repo, ".");

    git_odb *obj_db;
    obj_db = git_repository_database(repo);

    git_object commit;
    git_revparse_single(&commit, repo, "HEAD");


    git_repository_free(repo);
    return 0;
}

GCC 报告:

log.c: In function ‘main’:
log.c:11:9: warning: assignment makes pointer from integer without a cast [enabled by default]
log.c:13:13: error: storage size of ‘commit’ isn’t known

我使用-lgit2 标志编译。从根提交开始,是否可以快速遍历所有提交?

更新 新代码如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <git2.h>

int main(int argc, char *argv[]){
    git_repository *repo;
    git_repository_open(&repo, ".");

    git_odb *obj_db;
    obj_db = git_repository_database(repo);

    git_object *commit;
    git_revparse_single(&commit, repo, "HEAD");


    git_repository_free(repo);
    return 0;
}

我收到以下错误消息:

log.c:11: undefined reference to `git_repository_database'
log.c:14: undefined reference to `git_revparse_single'

【问题讨论】:

  • 确保您使用的是最新的库并查看该版本的文档。 git_repository_database 不存在。大概你想要git_repository_odb,虽然你不应该需要它来记录日志。 git_revparse_single 是在 0.18 版本中引入的,这表明您的系统上安装了一个古老的库。
  • 接受的答案似乎并不局限于单个分支,例如master。也许git_revwalk 不是为此而设计的?

标签: c git libgit2


【解决方案1】:

最后,我使用 libgit2 创建了一个工作版本。 Carlos Martín Nieto 指出了正确的方向,以下示例在 libgit2 0.16 上运行良好。我花了一些时间研究我在 github 的 libgit2-examples 存储库中找到的 general.cgit revwalk 正是我想要的。

我注意到 git 在我的提交消息的末尾添加了一个换行符,可能是因为我总是使用nano 来编写它们,所以我没有打印出示例代码中的最后一个字符。

如果有人读到这篇文章并遇到与我相同的问题,这里是工作代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <git2.h>

#define REPO ".git"

int main(void){
    git_repository *repo;
    if(git_repository_open(&repo, REPO) != GIT_SUCCESS){
        fprintf(stderr, "Failed opening repository: '%s'\n", REPO);
        return 1;
    }

    // Read HEAD on master
    char head_filepath[512];
    FILE *head_fileptr;
    char head_rev[41];

    strcpy(head_filepath, REPO);

    if(strrchr(REPO, '/') != (REPO+strlen(REPO)))
        strcat(head_filepath, "/refs/heads/master");
    else
        strcat(head_filepath, "refs/heads/master");


    if((head_fileptr = fopen(head_filepath, "r")) == NULL){
        fprintf(stderr, "Error opening '%s'\n", head_filepath);
        return 1;
    }

    if(fread(head_rev, 40, 1, head_fileptr) != 1){
        fprintf(stderr, "Error reading from '%s'\n", head_filepath);
        fclose(head_fileptr);
        return 1;
    }   

    fclose(head_fileptr);


    git_oid oid;
    git_revwalk *walker;
    git_commit *commit;

    if(git_oid_fromstr(&oid, head_rev) != GIT_SUCCESS){
        fprintf(stderr, "Invalid git object: '%s'\n", head_rev);
        return 1;
    }

    git_revwalk_new(&walker, repo);
    git_revwalk_sorting(walker, GIT_SORT_TOPOLOGICAL);
    git_revwalk_push(walker, &oid);

    const char *commit_message;
    const git_signature *commit_author;

    while(git_revwalk_next(&oid, walker) == GIT_SUCCESS) {
        if(git_commit_lookup(&commit, repo, &oid)){
            fprintf(stderr, "Failed to lookup the next object\n");
            return 1;
        }

        commit_message  = git_commit_message(commit);
        commit_author = git_commit_committer(commit);

        // Don't print the \n in the commit_message 
        printf("'%.*s' by %s <%s>\n", strlen(commit_message)-1, commit_message, commit_author->name, commit_author->email);

        git_commit_free(commit);
    }

    git_revwalk_free(walker);

    return 0;

}

谢谢!

【讨论】:

  • 您好,我刚刚找到了您的此列表,非常感谢您,因为我遇到了完全相同的问题。谢谢分享,好人!
  • 很高兴听到它仍然有效。在解决了这个问题之后,我尝试用另一种语言而不是 C 来实现我的东西。无论如何,libgit2 做了一些 API 更改,你真的必须意识到这些,因为它们改变了一些基本的东西。另外我认为这个库当时对开发人员不太友好......很高兴我能帮助你!
  • 您好,希望您一切顺利。我观察到 walker 将从分支走回假设 A 回到主控,即将在一个循环中列出来自分支 A 和主控的提交。有没有办法只列出来自分支 A 的提交?谢谢。
  • 就像@Thereisnothingwecando 说的那样,这个答案并没有像它所写的那样回答问题。也就是说,它并不局限于只在一个分支中提交。
  • 你不是忘了给git_repository_free打电话吗?
【解决方案2】:

我已经有以下代码,但它没有编译

git_commit 是不透明类型,这意味着您的编译器不知道它是什么,只知道它存在。因此,您不能在堆栈上分配 git_commit。库会为你在堆上分配它。

您必须在代码中使用指针并将指向该指针的指针传递给库的函数,如您在its documentation 和它的示例links to 中所见。

是否可以快速遍历所有提交,从根提交开始?

那些revwalk tests,展示了不同的步行策略,可能会给你一些帮助。

【讨论】:

  • 它仍然无法编译,使用示例中的所有头文件。编译器标志是-lgit2,不是吗?
  • 它仍然无法编译 -> 我很确定提供错误消息可能对读者很有帮助
  • 标题不是问题,而是您没有(或没有)使用指针。如果您想用更新的代码更新您的答案,也许我们可以提供帮助。
【解决方案3】:

补充宾得上面的答案。如果你只是想“走”头部,而不是做所有的工作来让旧的头部初始化步行器:

 git_revwalk_push(walker, &oid);

可以简单地使用:

 git_revwalk_push_head(walker);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-19
    • 2023-03-27
    • 2016-09-10
    • 2021-09-28
    • 2014-02-22
    • 2017-05-30
    • 1970-01-01
    相关资源
    最近更新 更多