int git_clone( git_repository **out, const char *url, const char *local_path, const git_clone_options *_options) { int retcode = GIT_ERROR; git_repository *repo = NULL; git_remote *origin; git_clone_options options = GIT_CLONE_OPTIONS_INIT; int remove_directory_on_failure = 0; assert(out && url && local_path); if (_options) memcpy(&options, _options, sizeof(git_clone_options)); GITERR_CHECK_VERSION(&options, GIT_CLONE_OPTIONS_VERSION, "git_clone_options"); /* Only clone to a new directory or an empty directory */ if (git_path_exists(local_path) && !git_path_is_empty_dir(local_path)) { giterr_set(GITERR_INVALID, "'%s' exists and is not an empty directory", local_path); return GIT_ERROR; } /* Only remove the directory on failure if we create it */ remove_directory_on_failure = !git_path_exists(local_path); if ((retcode = git_repository_init(&repo, local_path, options.bare)) < 0) return retcode; if ((retcode = create_and_configure_origin(&origin, repo, url, &options)) < 0) goto cleanup; retcode = git_clone_into(repo, origin, &options.checkout_opts, options.checkout_branch); git_remote_free(origin); if (retcode < 0) goto cleanup; *out = repo; return 0; cleanup: git_repository_free(repo); if (remove_directory_on_failure) git_futils_rmdir_r(local_path, NULL, GIT_RMDIR_REMOVE_FILES); else git_futils_cleanupdir_r(local_path); return retcode; }
static int setup_remotes_and_fetch( git_repository *repo, const char *url, const git_clone_options *options) { int retcode = GIT_ERROR; git_remote *origin; /* Construct an origin remote */ if (!create_and_configure_origin(&origin, repo, url, options)) { git_remote_set_update_fetchhead(origin, 0); /* Connect and download everything */ if (!git_remote_connect(origin, GIT_DIRECTION_FETCH)) { if (!(retcode = git_remote_download(origin, options->fetch_progress_cb, options->fetch_progress_payload))) { /* Create "origin/foo" branches for all remote branches */ if (!git_remote_update_tips(origin)) { /* Point HEAD to the requested branch */ if (options->checkout_branch) { if (!update_head_to_branch(repo, options)) retcode = 0; } /* Point HEAD to the same ref as the remote's head */ else if (!update_head_to_remote(repo, origin)) { retcode = 0; } } } git_remote_disconnect(origin); } git_remote_free(origin); } return retcode; }
int git_clone( git_repository **out, const char *url, const char *local_path, const git_clone_options *_options) { int error = 0; git_repository *repo = NULL; git_remote *origin; git_clone_options options = GIT_CLONE_OPTIONS_INIT; uint32_t rmdir_flags = GIT_RMDIR_REMOVE_FILES; git_repository_create_cb repository_cb; assert(out && url && local_path); if (_options) memcpy(&options, _options, sizeof(git_clone_options)); GITERR_CHECK_VERSION(&options, GIT_CLONE_OPTIONS_VERSION, "git_clone_options"); /* Only clone to a new directory or an empty directory */ if (git_path_exists(local_path) && !git_path_is_empty_dir(local_path)) { giterr_set(GITERR_INVALID, "'%s' exists and is not an empty directory", local_path); return GIT_EEXISTS; } /* Only remove the root directory on failure if we create it */ if (git_path_exists(local_path)) rmdir_flags |= GIT_RMDIR_SKIP_ROOT; if (options.repository_cb) repository_cb = options.repository_cb; else repository_cb = default_repository_create; if ((error = repository_cb(&repo, local_path, options.bare, options.repository_cb_payload)) < 0) return error; if (!(error = create_and_configure_origin(&origin, repo, url, &options))) { int clone_local = git_clone__should_clone_local(url, options.local); int link = options.local != GIT_CLONE_LOCAL_NO_LINKS; if (clone_local == 1) error = clone_local_into( repo, origin, &options.checkout_opts, options.checkout_branch, link, options.signature); else if (clone_local == 0) error = clone_into( repo, origin, &options.checkout_opts, options.checkout_branch, options.signature); else error = -1; git_remote_free(origin); } if (error != 0) { git_error_state last_error = {0}; giterr_capture(&last_error, error); git_repository_free(repo); repo = NULL; (void)git_futils_rmdir_r(local_path, NULL, rmdir_flags); giterr_restore(&last_error); } *out = repo; return error; }