Merge pull request #444 from carlosmn/fetch-fixes A couple of fetch fixes
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
diff --git a/src/fetch.c b/src/fetch.c
index 1bb8968..3c3dbcb 100644
--- a/src/fetch.c
+++ b/src/fetch.c
@@ -24,7 +24,7 @@ static int filter_wants(git_remote *remote)
git_repository *repo = remote->repo;
const git_refspec *spec;
int error;
- unsigned int i;
+ unsigned int i = 0;
error = git_vector_init(&list, 16, NULL);
if (error < GIT_SUCCESS)
@@ -36,13 +36,32 @@ static int filter_wants(git_remote *remote)
goto cleanup;
}
+ /*
+ * The fetch refspec can be NULL, and what this means is that the
+ * user didn't specify one. This is fine, as it means that we're
+ * not interested in any particular branch but just the remote's
+ * HEAD, which will be stored in FETCH_HEAD after the fetch.
+ */
spec = git_remote_fetchspec(remote);
- if (spec == NULL) {
- error = git__throw(GIT_ERROR, "The remote has no fetchspec");
- goto cleanup;
+
+ /*
+ * We need to handle HEAD separately, as we always want it, but it
+ * probably won't matcht he refspec.
+ */
+ head = refs.heads[0];
+ if (refs.len > 0 && !strcmp(head->name, GIT_HEAD_FILE)) {
+ if (git_odb_exists(repo->db, &head->oid))
+ head->local = 1;
+ else
+ remote->need_pack = 1;
+
+ i = 1;
+ error = git_vector_insert(&list, refs.heads[0]);
+ if (error < GIT_SUCCESS)
+ goto cleanup;
}
- for (i = 0; i < refs.len; ++i) {
+ for (; i < refs.len; ++i) {
git_remote_head *head = refs.heads[i];
/* If it doesn't match the refpec, we don't want it */
diff --git a/src/refs.c b/src/refs.c
index 1135de4..fcf771b 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -1713,7 +1713,8 @@ static int normalize_name(char *buffer_out, size_t out_size, const char *name, i
/* Object id refname have to contain at least one slash, except
* for HEAD in a detached state or MERGE_HEAD if we're in the
* middle of a merge */
- if (is_oid_ref && !contains_a_slash && (strcmp(name, GIT_HEAD_FILE) && strcmp(name, GIT_MERGE_HEAD_FILE)))
+ if (is_oid_ref && !contains_a_slash && (strcmp(name, GIT_HEAD_FILE) && strcmp(name, GIT_MERGE_HEAD_FILE)
+ && strcmp(name, GIT_FETCH_HEAD_FILE)))
return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name contains no slashes");
/* A refname can not end with ".lock" */
diff --git a/src/refs.h b/src/refs.h
index 979af2e..c4b0b0e 100644
--- a/src/refs.h
+++ b/src/refs.h
@@ -24,6 +24,7 @@
#define GIT_PACKEDREFS_HEADER "# pack-refs with: peeled "
#define GIT_HEAD_FILE "HEAD"
+#define GIT_FETCH_HEAD_FILE "FETCH_HEAD"
#define GIT_MERGE_HEAD_FILE "MERGE_HEAD"
#define GIT_REFS_HEADS_MASTER_FILE GIT_REFS_HEADS_DIR "master"
diff --git a/src/refspec.c b/src/refspec.c
index 9de2730..ed4b5e6 100644
--- a/src/refspec.c
+++ b/src/refspec.c
@@ -42,17 +42,17 @@ int git_refspec_parse(git_refspec *refspec, const char *str)
const char *git_refspec_src(const git_refspec *refspec)
{
- return refspec->src;
+ return refspec == NULL ? NULL : refspec->src;
}
const char *git_refspec_dst(const git_refspec *refspec)
{
- return refspec->dst;
+ return refspec == NULL ? NULL : refspec->dst;
}
int git_refspec_src_match(const git_refspec *refspec, const char *refname)
{
- return git__fnmatch(refspec->src, refname, 0);
+ return refspec == NULL ? GIT_ENOMATCH : git__fnmatch(refspec->src, refname, 0);
}
int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, const char *name)
diff --git a/src/remote.c b/src/remote.c
index f581b97..a557a49 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -219,7 +219,7 @@ int git_remote_download(char **filename, git_remote *remote)
int git_remote_update_tips(struct git_remote *remote)
{
int error = GIT_SUCCESS;
- unsigned int i;
+ unsigned int i = 0;
char refname[GIT_PATH_MAX];
git_headarray *refs = &remote->refs;
git_remote_head *head;
@@ -228,8 +228,21 @@ int git_remote_update_tips(struct git_remote *remote)
memset(refname, 0x0, sizeof(refname));
- for (i = 0; i < refs->len; ++i) {
+ if (refs->len == 0)
+ return GIT_SUCCESS;
+
+ /* HEAD is only allowed to be the first in the list */
+ head = refs->heads[0];
+ if (!strcmp(head->name, GIT_HEAD_FILE)) {
+ error = git_reference_create_oid(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1);
+ i = 1;
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to update FETCH_HEAD");
+ }
+
+ for (; i < refs->len; ++i) {
head = refs->heads[i];
+
error = git_refspec_transform(refname, sizeof(refname), spec, head->name);
if (error < GIT_SUCCESS)
return error;