I've been trying to push a commit created with libgit2 to github for a while, I've managed to overcome quite a lot of the issues I was facing, but the "final" on is to actually push the commit, as currently it doesnt error, but also doesnt actually seem to work. So my code is something like (ive omitted all error checking for brevity):
...
git_commit_create(...); // create the commit
...
git_remote_lookup(&remote, _repo, "origin");
git_remote_init_callbacks(&cbs, GIT_REMOTE_CALLBACKS_VERSION);
cbs.credentials = my_git_cred_cb;
git_remote_connect(remote, GIT_DIRECTION_PUSH, &cbs, NULL, NULL);
git_remote_add_push(_repo, "origin", "refs/heads/master:refs/heads/master");
git_push_options_init(&options, GIT_PUSH_OPTIONS_VERSION);
options.callbacks = cbs;
git_remote_upload(remote, null, &options);
git_remote_disconnect(remote);
git_remote_free(remote);
All these functions pass, and no error is returned, however, the commit hasnt been pushed. My guess is that my refspec (refs/heads/master:refs/heads/master
) is off - ive tried loads and loads of others but am just going in circles. Am i doing something totally wrong here, has anyone else used libgit2 to fully push a commit to a github repository? Any help / pointers would be greatly appreciated!
So, thanks to Jason Haslam in the comments, Ive managed to figure it out, since libgit2 full examples seem a little thin on ground Im posting my own solution as an answer, it might help someone else. Ive omitted errors and obvious variable creation for brevity.
// open reop
git_repository_open_(&repo, "path/to/repo");
// add commit
git_signature_now(&sig, "Name", "Email");
git_repository_index(&index, repo);
git_index_add_bypath(index, "some_test_file.txt");
git_index_write_tree(&tree_oid, index);
git_tree_lookup(&tree, repo, &tree_oid);
git_reference_name_to_id(&parent_oid, repo, "HEAD");
git_commit_lookup(&parent, repo, &parent_oid);
git_commit_create(&oid_commit, repo, "HEAD", sig, sig, null, "commit message", tree, 1, &parent);
// ... free all created objects
// push to github
git_remote_lookup(&remote, repo, "origin");
git_remote_init_callbacks(&cbs, GIT_REMOTE_CALLBACKS_VERSION);
cbs.credentials = &my_git_cred_cb;
git_push_options_init(&options, GIT_PUSH_OPTIONS_VERSION);
options.callbacks = cbs;
char *refspec_strings[] = {
"HEAD:refs/heads/master",
};
git_strarray refspec_array = {
refspec_strings,
1,
};
git_remote_push(remote, &refspec_array, &options);
git_remote_upload(remote, null, &options);
git_repository_state_cleanup(repo); // not sure this is needed
char *pathspec_strings[] = {
"HEAD",
};
git_strarray pathspec_array = {
pathspec_strings,
1,
};
git_reset_default(repo, null, &pathspec_array); // needed to reset to stop "git status" showing anything - not sure why it does
git_remote_disconnect(remote);
// ... free all created objects
The creditials callback is nice and simple:
int my_git_cred_cb(git_cred **cred, const char *url, const char *username_from_url, unsigned int allowed_types, void *payload) {
if ((allowed_types & GIT_CREDTYPE_USERPASS_PLAINTEXT) != 0) {
return git_cred_userpass_plaintext_new(cred, "gh_user", "gh_pass");
} else {
/* Some other kind of authentication was requested */
return -1;
}
return 1; /* unable to provide authentication data */
}