summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/git2/clone.h9
-rw-r--r--src/clone.c22
-rw-r--r--tests-clar/clone/network.c42
3 files changed, 67 insertions, 6 deletions
diff --git a/include/git2/clone.h b/include/git2/clone.h
index 40292ed59..c4dfc652b 100644
--- a/include/git2/clone.h
+++ b/include/git2/clone.h
@@ -29,9 +29,12 @@ GIT_BEGIN_DECL
* @param out pointer that will receive the resulting repository object
* @param origin_url repository to clone from
* @param workdir_path local directory to clone to
- * @param fetch_stats pointer to structure that receives fetch progress information (may be NULL)
- * @param checkout_opts options for the checkout step (may be NULL)
- * @return 0 on success, GIT_ERROR otherwise (use giterr_last for information about the error)
+ * @param fetch_stats pointer to structure that receives fetch progress
+ * information (may be NULL)
+ * @param checkout_opts options for the checkout step. If NULL, no checkout
+ * is performed
+ * @return 0 on success, GIT_ERROR otherwise (use giterr_last for information
+ * about the error)
*/
GIT_EXTERN(int) git_clone(git_repository **out,
const char *origin_url,
diff --git a/src/clone.c b/src/clone.c
index 00e39d3b5..82042a46a 100644
--- a/src/clone.c
+++ b/src/clone.c
@@ -18,6 +18,7 @@
#include "common.h"
#include "remote.h"
+#include "pkt.h"
#include "fileops.h"
#include "refs.h"
#include "path.h"
@@ -174,6 +175,7 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote)
{
int retcode = -1;
git_remote_head *remote_head;
+ git_pkt_ref *pkt;
struct head_info head_info;
git_buf remote_master_name = GIT_BUF_INIT;
@@ -187,7 +189,8 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote)
}
/* Get the remote's HEAD. This is always the first ref in remote->refs. */
- remote_head = remote->refs.contents[0];
+ pkt = remote->transport->refs.contents[0];
+ remote_head = &pkt->head;
git_oid_cpy(&head_info.remote_head_oid, &remote_head->oid);
git_buf_init(&head_info.branchname, 16);
head_info.repo = repo;
@@ -290,6 +293,19 @@ static bool path_is_okay(const char *path)
return true;
}
+static bool should_checkout(
+ git_repository *repo,
+ bool is_bare,
+ git_checkout_opts *opts)
+{
+ if (is_bare)
+ return false;
+
+ if (!opts)
+ return false;
+
+ return !git_repository_head_orphan(repo);
+}
static int clone_internal(
git_repository **out,
@@ -298,7 +314,7 @@ static int clone_internal(
git_indexer_stats *fetch_stats,
git_indexer_stats *checkout_stats,
git_checkout_opts *checkout_opts,
- int is_bare)
+ bool is_bare)
{
int retcode = GIT_ERROR;
git_repository *repo = NULL;
@@ -321,7 +337,7 @@ static int clone_internal(
}
}
- if (!retcode && !is_bare && !git_repository_head_orphan(repo))
+ if (!retcode && should_checkout(repo, is_bare, checkout_opts))
retcode = git_checkout_head(*out, checkout_opts, checkout_stats);
return retcode;
diff --git a/tests-clar/clone/network.c b/tests-clar/clone/network.c
index cf3c73bb6..1ebdfb5d1 100644
--- a/tests-clar/clone/network.c
+++ b/tests-clar/clone/network.c
@@ -32,6 +32,8 @@ void test_clone_network__network_full(void)
cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./test2", NULL, NULL, NULL));
cl_assert(!git_repository_is_bare(g_repo));
cl_git_pass(git_remote_load(&origin, g_repo, "origin"));
+
+ git_remote_free(origin);
}
@@ -44,6 +46,8 @@ void test_clone_network__network_bare(void)
cl_git_pass(git_clone_bare(&g_repo, LIVE_REPO_URL, "./test", NULL));
cl_assert(git_repository_is_bare(g_repo));
cl_git_pass(git_remote_load(&origin, g_repo, "origin"));
+
+ git_remote_free(origin);
}
void test_clone_network__cope_with_already_existing_directory(void)
@@ -72,3 +76,41 @@ void test_clone_network__empty_repository(void)
git_reference_free(head);
}
+
+void test_clone_network__can_prevent_the_checkout_of_a_standard_repo(void)
+{
+ git_buf path = GIT_BUF_INIT;
+
+ cl_set_cleanup(&cleanup_repository, "./no-checkout");
+
+ cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./no-checkout", NULL, NULL, NULL));
+
+ cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "master.txt"));
+ cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&path)));
+
+ git_buf_free(&path);
+}
+
+void test_clone_network__can_checkout_a_cloned_repo(void)
+{
+ git_checkout_opts opts;
+ git_buf path = GIT_BUF_INIT;
+ git_reference *head;
+
+ memset(&opts, 0, sizeof(opts));
+ opts.checkout_strategy = GIT_CHECKOUT_CREATE_MISSING;
+
+ cl_set_cleanup(&cleanup_repository, "./default-checkout");
+
+ cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./default-checkout", NULL, NULL, &opts));
+
+ cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "master.txt"));
+ cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&path)));
+
+ cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD"));
+ cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head));
+ cl_assert_equal_s("refs/heads/master", git_reference_target(head));
+
+ git_reference_free(head);
+ git_buf_free(&path);
+}