简体   繁体   中英

Create new git repository from a branch of another using libgit2?

In C++ using libgit2, I'd like to create a new local repository where its master branch is based on specific-branch from another local repository, maintaining its history so I can later synch between the two.

Essentially, I'm attempting the following, except using libgit2:

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

So if I had files arranged as follows:

./old.git [branches: master, specific-branch]

./old/* [files and clone of ./old.git at specific-branch]

Where the commands would be something like:

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

And come up with something like (removed error checking to reduce code):

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);

What I'm not really sure is where to go from here and how to invoke git_remote_push() properly where it actually does something. This currently has no side effects, as ./old.git is not referenced. That is, ./new.git is created properly, but it doesn't contain contents of ./old.git / ./old/* .

Help much appreciated.


Based on an answer suggesting a "fetch" approach, I've also attempted the following:

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();
}

This still has no effect.

In straight git the most flexible and direct method (as it doesn't require you to already have the entire repository you only want pieces of) is eg

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

To do this in libgit2, you can create a repository as usual with git_repository_init and an in-memory "anonymous" remote from a url (i'd hope a path would do as well, check that) with git_remote_create_anonymous , then git_remote_download git_remote_fetch the refspec you want from that.

An alternative (IMHO, the way of the API), since what you're after is a "standard" clone step using a custom upstream branch, would be to use git_clone 's provided customization points (instead of using all the smaller parts/steps).

So something like this should work (C pseudocode):

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);
}

It looks like you're creating a new repository, and then adding a remote on it and trying to use it to push to itself... If you want to truly emulate your commands, you'll need two repositories:

  1. git_repository_init the new.git , then
  2. git_repository_open the old , and then set up the remote on it , and push it to the new repository.

Something along the lines of:

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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM