【问题标题】:Create new git repository from a branch of another using libgit2?使用 libgit2 从另一个分支创建新的 git 存储库?
【发布时间】:2018-05-22 00:41:01
【问题描述】:

在使用 libgit2 的 C++ 中,我想创建一个新的本地存储库,其中其 master 分支基于来自另一个本地存储库的 specific-branch,维护其历史记录,以便稍后在两者之间进行同步。

基本上,我正在尝试以下操作,除了使用 libgit2:

https://stackoverflow.com/a/9529847/1019385

所以如果我有如下排列的文件:

./old.git [分支:master,特定分支]

./old/* [./old.git 在特定分支的文件和克隆]

命令应该是这样的:

git init --bare ./new.git
cd ./old
git push ./new.git +specific-branch:master

并想出类似的东西(删除错误检查以减少代码):

git_libgit2_init();
git_repository* repo = nullptr;
git_repository_init(&repo, "./new.git", true);
git_remote_create(&remote, repo, "origin", "./new.git");
git_remote_add_push(repo, "origin", "+specific-branch:master");
git_push_options optionsPush = GIT_PUSH_OPTIONS_INIT;
git_remote_push(remote, nullptr, &optionsPush);

我不太确定从这里去哪里以及如何正确调用git_remote_push() 在它实际做某事的地方。这目前没有副作用,因为没有引用 ./old.git。即./new.git创建正确,但不包含./old.git/./old/*的内容。

非常感谢您的帮助。


根据建议“获取”方法的答案,我还尝试了以下方法:

git_repository* repo = nullptr;
if (git_repository_init(&repo, "./new.git", true)) {
    FATAL();
}
git_remote* remote;
git_remote_create_anonymous(&remote, repo, "./old");
char* specs[] = { _strdup("specific-branch:master"), nullptr };
git_strarray refspecs;
refspecs.count = 1;
refspecs.strings = specs;
if (git_remote_download(remote, &refspecs, NULL)) {
    FATAL();
}

这仍然没有效果。

【问题讨论】:

  • 请显示您正在查看的实际调试结果。 mcve 加上您期望结果(返回/效果)的特定点以及原因,以及您得到了什么以及为什么..
  • @jthill 显示预期结果。这是一个相当普遍的问题,可以使用任何存储库来完成。我还链接到一个问题,其中包含与我的问题有关的几个答案,而没有使用 libgit2。唯一的区别是我希望使用 libgit2 来避免 cli。
  • 您正在做出没有任何证据支持的断言(“这仍然没有效果”),没有费心提供可编译的测试用例或显示您的诊断步骤,通常除了把它扔到墙上,看看它是否粘住了编码。难怪您的代码不起作用。我花了两个小时从全新的 libgit2 到工作代码,来帮助你,但我没有办法奖励这样一个不合作、不费力的需求。如果您费心去做这项工作,那么您已经解决了这个问题,或者至少说明了您在这里所做的任何错误假设。
  • 这些函数的组合方式并不多。我只是不认为这些电话等于答案。我已经包含了一个示例源代码,它可以很容易地放入测试项目中,在您有权访问的任何存储库中。

标签: c++ git libgit2


【解决方案1】:

在直接 git 中,最灵活和最直接的方法(因为它不需要您已经拥有您只想要部分的整个存储库)例如

git init --bare new.git; cd $_

git fetch --no-tags ~/src/git next:master    # to fetch and rename a branch
# or
git fetch ~/src/git v2.17.0; git branch master FETCH_HEAD   # full handroll

要在 libgit2 中执行此操作,您可以像往常一样使用git_repository_init 创建一个存储库,并使用@987654323 从一个 url 远程创建一个内存中的“匿名”(我希望路径也可以,检查一下) @,然后是 git_remote_downloadgit_remote_fetch 你想要的 refspec。

【讨论】:

  • 这不会失去它的历史吗?这似乎只会获取文件,并且不允许在存储库之间进行任何合并。
  • 否,fetch 检索完整的历史记录。试试看。
  • 您似乎是对的,使用git fetch 似乎可以维护历史记录。然而,git_remote_download() 没有效果,尽管git_remote_create_anonymous()(都使用路径和 url)和git_remote_download() 都没有失败。您能否举一个使用示例,因为我可能做错了。
  • 为了清晰起见,我已根据您的建议使用代码更新了我的答案。
  • 嗯,所以我随机猜测并尝试git_remote_fetch() 而不是git_remote_download(),一切都突然按预期工作。我对 Git 很不熟悉 - 关于两者之间有什么区别的任何想法?
【解决方案2】:

另一种选择(恕我直言,API 的方式),因为您所追求的是使用自定义上游分支的“标准”克隆步骤,将使用 git_clone 提供的自定义点(而不是使用所有较小的部分/步骤)。

所以这样的东西应该可以工作(C 伪代码):

int main() {
    git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
    git_repository *repo;

    opts.bare = 1;
    opts.remote_create_cb = (git_remote_create_cb)git_remote_create_with_fetchspec;
    opts.remote_create_payload = "specific-branch:master";

    return git_clone(&repo, "./old", "./new", &opts);
}

【讨论】:

    【解决方案3】:

    看起来您正在创建一个新的存储库,然后在其上添加一个远程并尝试使用它来推送到自身...如果您想真正模拟您的命令,您将需要两个存储库:

    1. git_repository_initnew.git,然后
    2. git_repository_openold,然后在it上设置远程,并将it推送到新的仓库。

    类似的东西:

    git_repository *old = NULL, *new = NULL;
    
    git_libgit2_init();
    git_repository_init(&new, "./new.git", true);
    git_repository_free(new);
    
    git_repository_open(&old, "./old");
    git_remote_create(&remote, old, "origin", "./new.git");
    git_remote_add_push(old, "origin", "+specific-branch:master");
    git_remote_push(remote, NULL, NULL);
    git_repository_free(old);
    

    【讨论】:

    • 您能提供一些指导吗?我理解需要两个实例,对此没有任何问题。
    • 我添加了一些代码来说明我的想法,但到目前为止它完全未经测试。
    • git_remote_create()GIT_EEXISTS 失败。当我只是编了一个不同的名字而不是“起源”,并在git_remote_add_push()的第二个参数中使用它时,它似乎仍然没有最终效果(虽然没有错误代码)。
    猜你喜欢
    • 2012-03-20
    • 1970-01-01
    • 2018-12-24
    • 2022-10-25
    • 2013-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-15
    • 2011-05-27
    相关资源
    最近更新 更多