How can I walk through all the commits of a branch using libgit2?
I have already the following bit of code, but it doesn't compile.
#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 reports:
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
I compiled with the -lgit2
flag. Is there a fast possibility to walk through all the commits, beginning from the root-commit?
Update The new code looks like this:
#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;
}
I get the following error messages:
log.c:11: undefined reference to `git_repository_database'
log.c:14: undefined reference to `git_revparse_single'
Finally, I created a working version using libgit2. Carlos Martín Nieto pointed in the right direction, the following example works great with libgit2 0.16. It took me some time to study the general.c I found in the libgit2-examples repository on github. git revwalk was exactly what I was looking for.
I noted that git adds an newline at the end of my commit messages, probably because I'm always using nano
to write them, so I don't printf out the last character in my example code.
If anyone reads this and has the same problem as I had, here's the working code:
#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;
}
Thanks!
I have already the following bit of code, but it doesn't compile
A git_commit
is an opaque type, which means that your compiler doesn't know what it is, only that it exists. Thus you cannot allocate a git_commit
on the stack. The library will allocate it on the heap for you.
You must use a pointer in your code and pass a pointer to that to the library's functions, as you can see in its documentation and the examples it links to.
Is there a fast possibility to walk through all the commits, beginning from the root-commit?
Those revwalk tests, demonstrating different walking strategies, may provide you with some help.
Adding to Pentax's answer above. If you just want to 'walk' the head, instead of doing all that work to get the old to the head to initialize the walker with:
git_revwalk_push(walker, &oid);
One could simply use:
git_revwalk_push_head(walker);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With