diff --git a/src/fetch.c b/src/fetch.c index 1bb896870..3c3dbcb5b 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 1135de475..fcf771b5e 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 979af2ee2..c4b0b0e39 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 9de273071..ed4b5e6b8 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 f581b973f..a557a4930 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;