Merge pull request #1141 from ben/clone-empty-repo Allow clone to handle empty repos
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
diff --git a/examples/.gitignore b/examples/.gitignore
index 4c34e4a..e40bfc2 100644
--- a/examples/.gitignore
+++ b/examples/.gitignore
@@ -1,2 +1,4 @@
general
showindex
+diff
+*.dSYM
diff --git a/examples/network/Makefile b/examples/network/Makefile
index ef3cec6..60969bd 100644
--- a/examples/network/Makefile
+++ b/examples/network/Makefile
@@ -14,3 +14,7 @@ OBJECTS = \
all: $(OBJECTS)
$(CC) $(CFLAGS) $(LDFLAGS) -o git2 $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) git2
diff --git a/src/transports/local.c b/src/transports/local.c
index 53b2494..c6c95ce 100644
--- a/src/transports/local.c
+++ b/src/transports/local.c
@@ -42,6 +42,7 @@ static int add_ref(transport_local *t, const char *name)
git_remote_head *head;
git_object *obj = NULL, *target = NULL;
git_buf buf = GIT_BUF_INIT;
+ int error;
head = git__calloc(1, sizeof(git_remote_head));
GITERR_CHECK_ALLOC(head);
@@ -49,10 +50,17 @@ static int add_ref(transport_local *t, const char *name)
head->name = git__strdup(name);
GITERR_CHECK_ALLOC(head->name);
- if (git_reference_name_to_id(&head->oid, t->repo, name) < 0) {
+ error = git_reference_name_to_id(&head->oid, t->repo, name);
+ if (error < 0) {
git__free(head->name);
git__free(head);
- return -1;
+ if (!strcmp(name, GIT_HEAD_FILE) && error == GIT_ENOTFOUND) {
+ /* This is actually okay. Empty repos often have a HEAD that points to
+ * a nonexistent "refs/heads/master". */
+ giterr_clear();
+ return 0;
+ }
+ return error;
}
if (git_vector_insert(&t->refs, head) < 0)
diff --git a/tests-clar/clone/empty.c b/tests-clar/clone/empty.c
new file mode 100644
index 0000000..93fe151
--- /dev/null
+++ b/tests-clar/clone/empty.c
@@ -0,0 +1,67 @@
+#include "clar_libgit2.h"
+
+#include "git2/clone.h"
+#include "repository.h"
+
+static git_clone_options g_options;
+static git_remote *g_origin;
+static git_repository *g_repo;
+
+void test_clone_empty__initialize(void)
+{
+ git_repository *sandbox = cl_git_sandbox_init("empty_bare.git");
+ cl_git_remove_placeholders(git_repository_path(sandbox), "dummy-marker.txt");
+
+ g_repo = NULL;
+
+ memset(&g_options, 0, sizeof(git_clone_options));
+ g_options.version = GIT_CLONE_OPTIONS_VERSION;
+ cl_git_pass(git_remote_new(&g_origin, NULL, "origin", cl_git_fixture_url("testrepo.git"), GIT_REMOTE_DEFAULT_FETCH));
+}
+
+void test_clone_empty__cleanup(void)
+{
+ git_remote_free(g_origin);
+ cl_git_sandbox_cleanup();
+}
+
+static void cleanup_repository(void *path)
+{
+ cl_fixture_cleanup((const char *)path);
+}
+
+void test_clone_empty__can_clone_an_empty_local_repo_barely(void)
+{
+ cl_set_cleanup(&cleanup_repository, "./empty");
+
+ git_remote_free(g_origin);
+ cl_git_pass(git_remote_new(&g_origin, NULL, "origin", "./empty_bare.git", GIT_REMOTE_DEFAULT_FETCH));
+
+ g_options.bare = true;
+ cl_git_pass(git_clone(&g_repo, g_origin, "./empty", &g_options));
+}
+
+void test_clone_empty__can_clone_an_empty_local_repo(void)
+{
+ cl_set_cleanup(&cleanup_repository, "./empty");
+
+ git_remote_free(g_origin);
+ cl_git_pass(git_remote_new(&g_origin, NULL, "origin", "./empty_bare.git", GIT_REMOTE_DEFAULT_FETCH));
+
+ cl_git_pass(git_clone(&g_repo, g_origin, "./empty", &g_options));
+}
+
+void test_clone_empty__can_clone_an_empty_standard_repo(void)
+{
+ cl_git_sandbox_cleanup();
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+ cl_git_remove_placeholders(git_repository_path(g_repo), "dummy-marker.txt");
+ git_repository_free(g_repo);
+
+ git_remote_free(g_origin);
+ cl_git_pass(git_remote_new(&g_origin, NULL, "origin", "./empty_standard_repo", GIT_REMOTE_DEFAULT_FETCH));
+
+ cl_set_cleanup(&cleanup_repository, "./empty");
+
+ cl_git_pass(git_clone(&g_repo, g_origin, "./empty", &g_options));
+}
diff --git a/tests-clar/fetchhead/network.c b/tests-clar/fetchhead/network.c
index d10c891..dc223e2 100644
--- a/tests-clar/fetchhead/network.c
+++ b/tests-clar/fetchhead/network.c
@@ -63,8 +63,7 @@ static void fetchhead_test_fetch(const char *fetchspec, const char *expected_fet
git_remote_disconnect(remote);
git_remote_free(remote);
- cl_git_pass(git_futils_readbuffer(&fetchhead_buf,
- "./test1/.git/FETCH_HEAD"));
+ cl_git_pass(git_futils_readbuffer(&fetchhead_buf, "./foo/.git/FETCH_HEAD"));
equals = (strcmp(fetchhead_buf.ptr, expected_fetchhead) == 0);
diff --git a/tests-clar/network/push.c b/tests-clar/network/push.c
index f885609..788af52 100644
--- a/tests-clar/network/push.c
+++ b/tests-clar/network/push.c
@@ -211,6 +211,10 @@ void test_network_push__cleanup(void)
{
if (_remote)
git_remote_free(_remote);
+ _remote = NULL;
+
+ /* Freed by cl_git_sandbox_cleanup */
+ _repo = NULL;
record_callbacks_data_clear(&_record_cbs_data);