C++ 使用git init、fetch和checkout克隆git存储库

C++ 使用git init、fetch和checkout克隆git存储库,c++,libgit2,C++,Libgit2,导言 我正在使用流行的用C编写的libgit2进行实验。 我正在尝试做一个克隆,但使用一种不常见的方式。按顺序,git命令: 初始化 git远程添加源https://repository.git git获取源 切换到主分支 通过使用gitbash和以下命令,我可以获得一个包含所有历史记录的现有存储库 问题: 现在,让我们看看我当前的C++实现。下面的代码试图复制以前编写的git命令的行为 #define url "https://repository.git" #define p

导言

我正在使用流行的用C编写的libgit2进行实验。 我正在尝试做一个克隆,但使用一种不常见的方式。按顺序,git命令:

初始化 git远程添加源https://repository.git git获取源 切换到主分支 通过使用gitbash和以下命令,我可以获得一个包含所有历史记录的现有存储库

问题:

现在,让我们看看我当前的C++实现。下面的代码试图复制以前编写的git命令的行为

#define url         "https://repository.git"
#define path        "./"
#define user        "user"
#define pass        "pass"

/** credential callback **/
int credentials(git_cred **cred, const char *, const char *, unsigned int, void *) {
    return git_cred_userpass_plaintext_new(cred, user, pass);
}

class Git {
public:
    Git() {
        git_libgit2_init();
    }

    ~Git() {
        git_repository_free(repository);
        git_libgit2_shutdown();
    }

    void update() {
        init();
        fetch();
        checkout();
    }

private:
    void init() {
        assertSuccess(git_repository_init(&repository, path, GIT_CVAR_FALSE));

        git_remote *remote = nullptr;
        git_remote_callbacks options = GIT_REMOTE_CALLBACKS_INIT;

        assertSuccess(git_remote_create(&remote, repository, "origin", url));

        options.credentials = credentials;
        git_remote_connect(remote, GIT_DIRECTION_FETCH, &options, nullptr, nullptr);
    }

    void fetch() {
        git_remote* remote = nullptr;
        assertSuccess(git_remote_lookup(&remote, repository, "origin"));

        git_fetch_options options = GIT_FETCH_OPTIONS_INIT;
        options.callbacks.credentials = credentials;
        assertSuccess(git_remote_fetch(remote, nullptr, &options, nullptr));
    }

    void checkout() {
        git_checkout_options options = GIT_CHECKOUT_OPTIONS_INIT;
        options.checkout_strategy = GIT_CHECKOUT_FORCE;

        assertSuccess(git_checkout_head(repository, &options));

        assertSuccess(git_checkout_index(repository, nullptr, &options));

        assertSuccess(git_repository_set_head(repository, "refs/heads/master"));
        git_object *treeish = nullptr;
        assertSuccess(git_revparse_single(&treeish, repository, "master"));
        assertSuccess(git_checkout_tree(repository, treeish, &options));
    }

    void assertSuccess(int error) {
        if (!error) return;

        const git_error *e = giterr_last();
        std::cout << "code: " << e->klass << " error: " << e->message << std::endl;
        exit(1);
    }

private:
    git_repository *repository = nullptr;
};

int main() {
    Git git;
    git.update();
    return 0;
}
git存储库已经创建,我可以看到通过git bash成功设置的远程源。我可以从GitBash手动执行git签出主控程序,所以我想我当前的签出实现是失败的

有人能告诉我这个错误吗?我找不到足够的资源,也找不到对所有在互联网上找到的例子的支持

编辑 因为测试代码可能会有所帮助,所以让我给出编译libgit2的CMakeLists.txt。源代码


缺少的链接是,由于您是从头开始构建存储库,所以您的存储库仍然未出生,即,它的头指向一个不存在的refs/heads/master ref。除此之外,在libgit2land中,checkout唯一关心的是从ODB中取出文件,它不会写入或更新引用

因此,您缺少git checkout在git update ref中使用的使master指向origin/master的OID的步骤,您可以通过

类似于以下内容:

静态整数设置\跟踪\分支CHAR*分支\名称,git \参考*上游 { git_参考*跟踪; git_oid up_oid=git_参考_目标_对等流; 字符*用户界面名称; 如果0 /*应该从“上游”建造。IIRC有一些 *git_引用访问器可以帮助 *例如,`refs/remotes/origin/heads/master`是`origin/master`。 */ 其他的 ui_name=原点/主节点; 恩迪夫 如果git\u引用\u创建\u匹配和跟踪, git_reference_ownerStream, 分支\u名称,上限\u oid,0,空,分支:从%s创建,ui\u名称<0|| git\u分支\u集合\u上游跟踪,git\u参考\u名称上游<0{ printfailed创建远程跟踪分支\n; 返回-1; } 清理: git_参考_自由跟踪; 返回0; }
这采用了您希望新分支为-b,远程分支为-t的名称,尽管这显然不是完全的重新实现,甚至不是正确的,所以YMMV。

你能提供一个完整的例子吗?你能稍微谈谈为什么git clone不适合你吗?我需要在一个文件夹中设置一个git存储库,这个文件夹不是空的,基本上不可能使用git cloneThat,这是有意义的,但是你可以通过将文件移到其他地方,然后再返回来让它工作。如果您的FS具有廉价的重命名,那么可能会更容易。
code: 4 error: reference 'refs/heads/master' not found
cmake_minimum_required(VERSION 3.13)
project(test)

include_directories(libgit/include)
LINK_DIRECTORIES(${LIBSSH2_LIBRARY_DIRS})
add_subdirectory(libgit)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_BUILD_TYPE Release)

add_executable(test src/Git.h)
target_link_libraries(test git2)