我如何使用libgit2进行首次提交后如何使提交工作,因为我已经签出并尝试了所有其他与使用libgit2实施git commit有关的帖子,但它们似乎都因SIGSEGV在提交或给出时失败“错误:无法创建初始提交(-15)(无法创建提交:当前提示不是第一父级)”
完整的源代码可在http://github.com/mgood7123/Git
获得我的目标是暗示这一点
#!./Files/bash-4.4.0
git config --global user.email "null@gmail.com"
git config --global user.name "null"
git add --all
git commit -m -a
git push --force origin master
最后是这个
git filter-branch --index-filter 'git rm --cached --ignore-unmatch $1' -- --all
使用libgit2作为最小的备份系统,因为无法使用本机二进制文件(因为ios不允许这样做),所以我不能仅从源代码编译git本身
更新:我已经修复了崩溃问题,并且无论文件仍在“要提交的更改:”中,它都成功提交了
push> touch k
push> ggitnadd k
ggitnadd : Command not found.
push> git add k
git_libgit2_features() = 15
git_libgit2_init() = 1
called
add 'k'
push> git commit k
git_libgit2_init() = 1
git_repository_head_unborn(repo) = 0
aquiring reference
git_reference_name_to_id(&parent_id,repo,"HEAD") = 0 (none)
looking up reference
git_commit_lookup(&parent,repo,&parent_id) = 0 (none)
attemting to commit
git_commit_tree(&tree,parent) = 0 (none)
ret = 0 (none)
commit sucessfull
push> git status
# On branch
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: gfd
# new file: k
# new file: te
#
push> git commit -a
git_libgit2_init() = 1
git_repository_head_unborn(repo) = 0
aquiring reference
git_reference_name_to_id(&parent_id,repo,"HEAD") = 0 (none)
looking up reference
git_commit_lookup(&parent,repo,&parent_id) = 0 (none)
attemting to commit
git_commit_tree(&tree,parent) = 0 (none)
ret = 0 (none)
commit sucessfull
push> git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: gfd
# new file: k
# new file: te
#
push>
但是,如果我提交到一个裸仓库,它将成功提交
Git> git init
Initialized empty Git repository in ~/CCR/UserFiles/Mobile C/Git/.git
Git> git add -A
git_libgit2_features() = 15
git_libgit2_init() = 1
called
add 'git.c'
called
add 'git/common.c.h'
called
add 'git/common.h'
called
add 'git/git.h'
called
add 'git/git_add.h'
called
add 'git/git_clone.h'
called
add 'git/git_commit.h'
called
add 'git/git_config.h'
called
add 'git/git_curl.h'
called
add 'git/git_hook_config.h'
called
add 'git/git_init.h'
called
add 'git/git_macros.h'
called
add 'git/git_push.h'
called
add 'git/git_remote.h'
called
add 'git/git_stat.h'
called
add 'git/git_tests.h'
called
add 'git/githeader.h'
called
add 'git/strbuf.h'
called
add 'gitcommit'
called
add 'gitremove'
called
add 'tests/push/'
Git> git status
# On branch Not currently on any branch.
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: git.c
# new file: git/common.c.h
# new file: git/common.h
# new file: git/git.h
# new file: git/git_add.h
# new file: git/git_clone.h
# new file: git/git_commit.h
# new file: git/git_config.h
# new file: git/git_curl.h
# new file: git/git_hook_config.h
# new file: git/git_init.h
# new file: git/git_macros.h
# new file: git/git_push.h
# new file: git/git_remote.h
# new file: git/git_stat.h
# new file: git/git_tests.h
# new file: git/githeader.h
# new file: git/strbuf.h
# new file: gitcommit
# new file: gitremove
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# tests/push/
Git> git commit -a
git_libgit2_init() = 1
git_repository_head_unborn(repo) = 1
looking up tree
attemting to commit
Git> git status
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# tests/push/
Git>
commit.h
int gitprefix(commit) (int argc, char * argv[]) {
git_repository *repo;
git_signature *sig;
git_index *index;
git_oid tree_id, commit_id;
git_tree *tree;
pi(git_libgit2_init());
if (git_repository_open(&repo, ".")) {
git_libgit2_shutdown();
giterror("Could not open repository");
}
/** First use the config to initialize a commit signature for the user. */
if (git_signature_default(&sig, repo) < 0) {
if (git_signature_new(&sig, "null","null@gmail.com",0,0) < 0) {
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Unable to create a commit signature.\n%s",
"Perhaps 'user.name' and 'user.email' are not set");
}
}
/* Now let's create an empty tree for this commit */
if (git_repository_index(&index, repo) < 0) {
git_index_free(index);
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Could not open repository index", NULL);
}
/**
* Outside of this example, you could call git_index_add_bypath()
* here to put actual files into the index. For our purposes, we'll
* leave it empty for now.
*/
if (git_index_write_tree(&tree_id, index) < 0) {
git_index_free(index);
git_tree_free(tree);
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Unable to write initial tree from index", NULL);
}
git_index_free(index);
pi(git_repository_head_unborn(repo))
if(git_repository_head_unborn(repo) == 1) {
puts("looking up tree");
if (git_tree_lookup(&tree, repo, &tree_id) < 0) {
git_tree_free(tree);
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Could not look up initial tree", NULL);
}
/**
* Ready to create the initial commit.
*
* Normally creating a commit would involve looking up the current
* HEAD commit and making that be the parent of the initial commit,
* but here this is the first commit so there will be no parent.
*/
puts("attemting to commit");
int ret = git_commit_create_v(&commit_id, repo, "HEAD", sig, sig, NULL, "Initial commit", tree, 0);
if (ret < 0) {
git_tree_free(tree);
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Could not create the initial commit (%d)", ret);
}
} else if (git_repository_head_unborn(repo) == 0) {
git_oid parent_id;
git_commit *parent;
// Get HEAD as a commit object to use as the parent of the commit
puts("aquiring reference");
giterr(git_reference_name_to_id(&parent_id, repo, "HEAD"));
puts("looking up reference");
giterr(git_commit_lookup(&parent, repo, &parent_id));
puts("attemting to commit");
giterr(git_commit_tree(&tree, parent));
int ret = git_commit_create_v(&commit_id, repo, "HEAD", sig, sig, NULL, "-a", tree, 1, parent, NULL);
giterr(ret);
if (ret < 0) {
git_tree_free(tree);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Could not create the initial commit (%d)", ret);
}
puts("commit sucessfull");
}
/** Clean up so we don't leak memory. */
git_tree_free(tree);
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
return 0;
}
commit2.h(工作)
int gitprefix(commit2) (int argc, char * argv[]) {
git_repository *repo;
git_signature *sig;
git_index *index;
git_oid tree_id, commit_id;
git_tree *tree = NULL;
pi(git_libgit2_init());
if (git_repository_open(&repo, ".")) {
git_libgit2_shutdown();
giterror("Could not open repository");
}
/** First use the config to initialize a commit signature for the user. */
if (git_signature_default(&sig, repo) < 0) {
if (git_signature_new(&sig, "null","null@gmail.com",0,0) < 0) {
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Unable to create a commit signature.\n%s",
"Perhaps 'user.name' and 'user.email' are not set");
}
}
pi(git_repository_head_unborn(repo))
if(git_repository_head_unborn(repo) == 1) {
/* Now let's create an empty tree for this commit */
if (git_repository_index(&index, repo) < 0) {
git_index_free(index);
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Could not open repository index", NULL);
}
/**
* Outside of this example, you could call git_index_add_bypath()
* here to put actual files into the index. For our purposes, we'll
* leave it empty for now.
*/
if (git_index_write_tree(&tree_id, index) < 0) {
git_index_free(index);
git_tree_free(tree);
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Unable to write initial tree from index", NULL);
}
git_index_free(index);
puts("looking up tree");
if (git_tree_lookup(&tree, repo, &tree_id) < 0) {
git_tree_free(tree);
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Could not look up initial tree", NULL);
}
/**
* Ready to create the initial commit.
*
* Normally creating a commit would involve looking up the current
* HEAD commit and making that be the parent of the initial commit,
* but here this is the first commit so there will be no parent.
*/
puts("attemting to commit");
int ret = git_commit_create_v(&commit_id, repo, "HEAD", sig, sig, NULL, "Initial commit", tree, 0);
if (ret < 0) {
git_tree_free(tree);
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Could not create the initial commit (%d)", ret);
}
} else if (git_repository_head_unborn(repo) == 0) {
/* Now let's create an empty tree for this commit */
if (git_repository_index(&index, repo) < 0) {
git_index_free(index);
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Could not open repository index", NULL);
}
/**
* Outside of this example, you could call git_index_add_bypath()
* here to put actual files into the index. For our purposes, we'll
* leave it empty for now.
*/
/* Overwrite the index contents with those of a tree */
giterr(git_revparse_single((git_object**)&tree, repo, "HEAD~^{tree}"));
giterr(git_index_read_tree(index, tree));
/* Write the index contents to the ODB as a tree */
giterr(git_index_write_tree(&tree_id, index));
/* In-memory indexes can write trees to any repo */
giterr(git_index_write_tree_to(&tree_id, index, repo));
git_index_free(index);
git_oid parent_id;
git_commit *parent;
git_commit *parent2;
// Get HEAD as a commit object to use as the parent of the commit
puts("aquiring reference");
giterr(git_reference_name_to_id(&parent_id, repo, "HEAD"));
puts("looking up reference");
giterr(git_commit_lookup(&parent, repo, &parent_id));
puts("attemting to commit");
giterr(git_commit_tree(&tree, parent));
int ret = git_commit_create_v(&commit_id, repo, "HEAD", sig, sig, NULL, "-a", tree, 1, parent, NULL);
//int git_commit_parent(git_commit **out, const git_commit *commit, unsigned int n);
//int ret = git_commit_parent(&parent2, parent, 0);
giterr(ret);
if (ret < 0) {
git_tree_free(tree);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Could not create the commit (%d)", ret);
}
puts("commit sucessfull");
}
/** Clean up so we don't leak memory. */
git_tree_free(tree);
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
return 0;
}
add.h
int gitprefix(add) (int argc, char** argv)
{
git_index_matched_path_cb matched_cb = &pmatched_cb;
git_repository *repo = NULL;
git_index *index;
git_strarray array = {0};
int options = 0, count = 0;
struct print_payload payload = {0};
pi(git_libgit2_features());
pi(git_libgit2_init());
gitret(gitprefix(parse_optsA)(&options, &count, argc, argv));
gitprefix(init_array)(&array, argc-count, argv+count);
if (git_repository_open(&repo, ".")) {
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Could not open repository");
}
if (git_repository_index(&index, repo)) {
git_index_free(index);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Could not open repository index");
}
payload.options = options;
payload.repo = repo;
git_index_add_all(index, &array, GIT_INDEX_ADD_DEFAULT, matched_cb, &payload);
git_index_update_all(index, &array, matched_cb, &payload);
git_index_write(index);
git_index_free(index);
git_repository_free(repo);
git_libgit2_shutdown();
return 0;
}
这是commit函数的代码(因为完整的代码分为几个文件)
#define ps(x) printf("%s = %s\n", #x, x);
#define pi(x) printf("%s = %d\n", #x, x);
#define pp(x) printf("%s = %p\n", #x, x);
#define gitprefix(x) git_libgit_version_2_api_##x
#define giterr(x) { printf("%s = %d (%s)\n", #x, x, giterr_last()?giterr_last()->message:"none"); }
#define giterror(...) { \
printf("error: " __VA_ARGS__); \
printf(" (%s)", giterr_last()?giterr_last()->message:"none"); \
printf("\n"); \
return -2; \
}
#define giterrorn(...) { \
printf("error: " __VA_ARGS__); \
printf(" (%s)", giterr_last()?giterr_last()->message:"none"); \
printf("\n"); \
return NULL; \
}
#define gitret(x) { \
int ret = x ; \
if (ret) return ret; \
}
int gitprefix(commit) (int argc, char * argv[]) {
git_repository *repo;
git_signature *sig;
git_index *index;
git_oid tree_id, commit_id;
git_tree *tree;
pi(git_libgit2_init());
if (git_repository_open(&repo, ".")) {
git_libgit2_shutdown();
giterror("Could not open repository");
}
/** First use the config to initialize a commit signature for the user. */
if (git_signature_default(&sig, repo) < 0) {
if (git_signature_new(&sig, "null","null@gmail.com",0,0) < 0) {
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Unable to create a commit signature.\n%s",
"Perhaps 'user.name' and 'user.email' are not set");
}
}
/* Now let's create an empty tree for this commit */
if (git_repository_index(&index, repo) < 0) {
git_index_free(index);
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Could not open repository index", NULL);
}
/**
* Outside of this example, you could call git_index_add_bypath()
* here to put actual files into the index. For our purposes, we'll
* leave it empty for now.
*/
if (git_index_write_tree(&tree_id, index) < 0) {
git_index_free(index);
git_tree_free(tree);
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Unable to write initial tree from index", NULL);
}
git_index_free(index);
pi(git_repository_head_unborn(repo))
if(git_repository_head_unborn(repo) == 1) {
puts("looking up tree");
if (git_tree_lookup(&tree, repo, &tree_id) < 0) {
git_tree_free(tree);
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Could not look up initial tree", NULL);
}
/**
* Ready to create the initial commit.
*
* Normally creating a commit would involve looking up the current
* HEAD commit and making that be the parent of the initial commit,
* but here this is the first commit so there will be no parent.
*/
puts("attemting to commit");
int ret = git_commit_create_v(&commit_id, repo, "HEAD", sig, sig, NULL, "Initial commit", tree, 0);
if (ret < 0) {
git_tree_free(tree);
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Could not create the initial commit (%d)", ret);
}
} else if (git_repository_head_unborn(repo) == 0) {
git_oid parent_id;
git_commit *parent;
// Get HEAD as a commit object to use as the parent of the commit
puts("aquiring reference");
giterr(git_reference_name_to_id(&parent_id, repo, "HEAD"));
puts("looking up reference");
giterr(git_commit_lookup(&parent, repo, &parent_id));
puts("attemting to commit");
// Do the commit
int ret = git_commit_create_v(&commit_id, repo, "HEAD", sig, sig, NULL, "-a", tree, 1, parent); // seg faults here, does not seg fault if i remove parent but gives -15
if (ret < 0) {
git_tree_free(tree);
git_repository_free(repo);
git_libgit2_shutdown();
giterror("Could not create the initial commit (%d)", ret);
}
}
/** Clean up so we don't leak memory. */
git_tree_free(tree);
git_signature_free(sig);
git_repository_free(repo);
git_libgit2_shutdown();
return 0;
}
和主要的git.c:
#include "git/git.h"
int _main(void);
int rec = 0; // set to 1 to test recursion and stability
int m = 0;
int i = 500;
int main(void)
{
str_new(path);
str_new(num);
str_insert_string(path, path.index, "init ");
str_insert_int(num, num.index, m);
str_insert_string(path, path.index, num.string);
str_insert_string(path, path.index, " --initial-commit");
_main(num.string, path.string);
str_free(path)
str_free(num)
if (rec == 1) {
if(m < i) {
m++;
main();
}
if (m <= i) printf("%d <= %d\n", m, i);
m--;
}
chdir("../");
return 0;
}
int _main(char * dir, char * init)
{
git("init a");
chdir("a");
git("commit");
puts("testing");
git(init);
chdir(dir);
git("commit");
puts("");
puts("");
puts("");
puts("");
touch("test");
mkdir("b",0777);
touch("b/l");
git("add -A");
git("stat a/0");
git("commit");
git("status");
chdir("../../");
puts("testing done");
return 0;
}
这是完整命令的输出:
self> git
Initialized empty Git repository in ~/CCR/UserFiles/Mobile C/Git/self/a/.git
git_libgit2_init() = 3
git_repository_head_unborn(repo) = 1
looking up tree
attemting to commit
testing
Initialized empty Git repository in ~/CCR/UserFiles/Mobile C/Git/self/a/0/.git
git_libgit2_init() = 3
git_repository_head_unborn(repo) = 1
looking up tree
attemting to commit
git_libgit2_features() = 15
git_libgit2_init() = 3
File Path: b/l
Stage: 0
Blob SHA: e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
File Mode: 0100644
File Size: 0 bytes
Dev/Inode: 0/1962460
UID/GID: 501/501
ctime: 1532334385
mtime: 1532334385
File Path: test
Stage: 0
Blob SHA: e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
File Mode: 0100644
File Size: 0 bytes
Dev/Inode: 0/1962458
UID/GID: 501/501
ctime: 1532334385
mtime: 1532334385
git_libgit2_init() = 3
git_repository_head_unborn(repo) = 0
aquiring reference
git_reference_name_to_id(&parent_id,repo,"HEAD") = 0 (none)
looking up reference
git_commit_lookup(&parent,repo,&parent_id) = 0 (none)
attemting to commit
SIGSEGV on thread : 1090547712
0>
最小可编译示例:
#include <git2.h>
#include <unistd.h>
#include <stdio.h>
#define giterr(x) { printf("%s = %d (%s)\n", #x, x, giterr_last()?giterr_last()->message:"none"); }
#define giterror(...) { \
printf("error: " __VA_ARGS__); \
printf(" (%s)", giterr_last()?giterr_last()->message:"none"); \
printf("\n"); \
return -2; \
}
int main(void)
{
int ret = 0, retg = 0;
git_repository *repo;
git_signature *sig;
git_index *index;
git_oid tree_id, commit_id;
git_tree *tree;
git_oid parent_id;
git_commit *parent;
ret = git_libgit2_init();
giterr(ret)
ret = chdir("a/0");
giterr(ret)
ret = git_repository_open(&repo, ".");
giterr(ret)
if (ret < 0) {
git_libgit2_shutdown();
giterror("Could not open repository");
}
ret = git_signature_default(&sig, repo);
giterr(ret)
if (ret < 0) {
puts("Failed to obtain default signature, attempting to create new signature");
ret = git_signature_new(&sig, "null","null@gmail.com",0,0);
giterr(ret)
if (ret < 0) {
git_signature_free(sig); // returns void
git_repository_free(repo); // returns void
git_libgit2_shutdown();
giterror("Unable to create a commit signature.\n%s",
"Perhaps 'user.name' and 'user.email' are not set");
}
}
ret = git_repository_index(&index, repo);
giterr(ret)
if (ret < 0) {
git_index_free(index); // returns void
git_signature_free(sig); // returns void
git_repository_free(repo); // returns void
git_libgit2_shutdown();
giterror("Could not open repository index", NULL);
}
ret = git_index_write_tree(&tree_id, index);
giterr(ret)
if (ret < 0) {
git_index_free(index); // returns void
git_tree_free(tree); // returns void
git_signature_free(sig); // returns void
git_repository_free(repo); // returns void
git_libgit2_shutdown();
giterror("Unable to write initial tree from index", NULL);
}
git_index_free(index); // returns void
retg = git_repository_head_unborn(repo);
giterr(retg)
if (retg == 1) {
ret = git_tree_lookup(&tree, repo, &tree_id);
giterr(ret)
if (ret < 0) {
git_tree_free(tree); // returns void
git_signature_free(sig); // returns void
git_repository_free(repo); // returns void
git_libgit2_shutdown();
giterror("Could not look up initial tree", NULL);
}
ret = git_commit_create_v(&commit_id, repo, "HEAD", sig, sig, NULL, "Initial commit", tree, 0);
giterr(ret)
if (ret < 0) {
git_tree_free(tree); // returns void
git_signature_free(sig); // returns void
git_repository_free(repo); // returns void
git_libgit2_shutdown(); // returns void
giterror("Could not create the initial commit (%d)", ret);
}
}
else if (retg == 0) {
ret = git_reference_name_to_id(&parent_id, repo, "HEAD");
giterr(ret)
if (ret < 0) {
git_tree_free(tree); // returns void
git_signature_free(sig); // returns void
git_repository_free(repo); // returns void
git_libgit2_shutdown(); // returns void
giterror("Cannot convert reference to id (%d)", ret);
}
ret = git_commit_lookup(&parent, repo, &parent_id);
giterr(ret)
if (ret < 0) {
git_commit_free(parent); // returns void
git_tree_free(tree); // returns void
git_signature_free(sig); // returns void
git_repository_free(repo); // returns void
git_libgit2_shutdown();
giterror("Cannot look up commit (%d)", ret);
}
puts("committing");
giterr(git_commit_tree(&tree, parent));
ret = git_commit_create_v(&commit_id, repo, "HEAD", sig, sig, NULL, "-a", tree, 1, parent, NULL);
puts("committed");
giterr(ret)
if (ret < 0) {
git_commit_free(parent); // returns void
git_tree_free(tree); // returns void
git_signature_free(sig); // returns void
git_repository_free(repo); // returns void
git_libgit2_shutdown();
giterror("Could not create the initial commit (%d)", ret);
}
// seg fault
}
ret = chdir("../../");
giterr(ret)
git_tree_free(tree);
git_signature_free(sig);
git_repository_free(repo);
ret = git_libgit2_shutdown();
giterr(ret)
return 0;
}
其输出
ret = 3 (none)
ret = 0 (none)
ret = 0 (none)
ret = -3 (config value 'user.name' was not found)
Failed to obtain default signature, attempting to create new signature
ret = 0 (config value 'user.name' was not found)
ret = 0 (config value 'user.name' was not found)
ret = 0 (none)
retg = 0 (none)
ret = 0 (none)
ret = 0 (none)
committing
ret = 0 (none)
committed
ret = 0 (none)
ret = 0 (none)
答案 0 :(得分:1)
至少从您的示例来看,您似乎没有将任何父级传递给第二次提交。根据{{3}},您应该传递一个git_commit
对象的变量参数列表。
因此正确的呼叫是:
int ret = git_commit_create_v(&commit_id, repo, "HEAD", sig, sig, NULL, "-a", tree, 1, parent, NULL);
否则,您可能会将堆栈垃圾传递给该函数,从而传递SIGSEGV和错误。
编辑:抱歉,可变参数很难。我忘记添加NULL
标记值。
编辑2:,这是结果。您的代码有2个问题(至少是最小可编译的示例):
在未初始化库时,您不能使用giterr_last()
,这将导致严重崩溃。由于您通常在致电git_libgit2_shutdown()
之前先giterror
,所以您将无法长期生存。
您将第二次传递未初始化的git_tree
,因为您仅在“未出生”的情况下执行查找。那是另一场崩溃。在您提交的查询中使用git_commit_tree
。
我不是您所使用的IDE,但是至少Xcode谈到了您的崩溃:
Assertion failed: (tree && git_tree_owner(tree) == repo), function git_commit_create_v, file /Users/tiennou/Projects/libgit2/src/commit.c, line 231.