libgit2我如何成功提交文件?

时间:2018-07-23 08:40:36

标签: c git libgit2

我如何使用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)

1 个答案:

答案 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.