From b0f6e45d149c033c9fe41d49af2a87d169d11f40 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 1 Nov 2012 15:47:18 -0500 Subject: [PATCH] create FETCH_HEAD specially instead of as a ref file --- include/git2/remote.h | 17 +++ src/branch.c | 5 + src/clone.c | 6 ++ src/fetchhead.c | 126 +++++++++++++++++++++++ src/fetchhead.h | 27 +++++ src/refspec.c | 7 ++ src/refspec.h | 8 ++ src/remote.c | 142 +++++++++++++++++++++++++- src/remote.h | 3 +- tests-clar/fetchhead/fetchhead_data.h | 21 ++++ tests-clar/fetchhead/network.c | 87 ++++++++++++++++ tests-clar/fetchhead/nonetwork.c | 96 +++++++++++++++++ 12 files changed, 542 insertions(+), 3 deletions(-) create mode 100644 src/fetchhead.c create mode 100644 src/fetchhead.h create mode 100644 tests-clar/fetchhead/fetchhead_data.h create mode 100644 tests-clar/fetchhead/network.c create mode 100644 tests-clar/fetchhead/nonetwork.c diff --git a/include/git2/remote.h b/include/git2/remote.h index d9ccdfda9..44390e7a4 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -401,6 +401,23 @@ GIT_EXTERN(int) git_remote_rename( int (*callback)(const char *problematic_refspec, void *payload), void *payload); +/** + * Retrieve the update FETCH_HEAD setting. + * + * @param remote the remote to query + * @return the update FETCH_HEAD setting + */ +GIT_EXTERN(int) git_remote_update_fetchhead(git_remote *remote); + +/** + * Sets the update FETCH_HEAD setting. By default, FETCH_HEAD will be + * updated on every fetch. Set to 0 to disable. + * + * @param remote the remote to configure + * @param value 0 to disable updating FETCH_HEAD + */ +GIT_EXTERN(void) git_remote_set_update_fetchhead(git_remote *remote, int value); + /** @} */ GIT_END_DECL #endif diff --git a/src/branch.c b/src/branch.c index 43bebd9ef..62c4adbf4 100644 --- a/src/branch.c +++ b/src/branch.c @@ -268,6 +268,11 @@ int git_branch_tracking( if ((error = retrieve_tracking_configuration(&merge_name, branch, "branch.%s.merge")) < 0) goto cleanup; + + if (remote_name == NULL || merge_name == NULL) { + error = GIT_ENOTFOUND; + goto cleanup; + } if (strcmp(".", remote_name) != 0) { if ((error = git_remote_load(&remote, git_reference_owner(branch), remote_name)) < 0) diff --git a/src/clone.c b/src/clone.c index 7352f5fb2..d75fee213 100644 --- a/src/clone.c +++ b/src/clone.c @@ -271,6 +271,12 @@ static int setup_remotes_and_fetch( /* Create the "origin" remote */ if (!git_remote_add(&origin, repo, GIT_REMOTE_ORIGIN, origin_url)) { + /* + * Don't write FETCH_HEAD, we'll check out the remote tracking + * branch ourselves based on the server's default. + */ + git_remote_set_update_fetchhead(origin, 0); + /* Connect and download everything */ if (!git_remote_connect(origin, GIT_DIR_FETCH)) { if (!git_remote_download(origin, progress_cb, progress_payload)) { diff --git a/src/fetchhead.c b/src/fetchhead.c new file mode 100644 index 000000000..ed47bab48 --- /dev/null +++ b/src/fetchhead.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2009-2012 the libgit2 contributors + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "git2/types.h" +#include "git2/oid.h" + +#include "fetchhead.h" +#include "common.h" +#include "fileops.h" +#include "filebuf.h" +#include "refs.h" +#include "repository.h" + + +int git_fetchhead_ref_cmp(const void *a, const void *b) +{ + const git_fetchhead_ref *one = (const git_fetchhead_ref *)a; + const git_fetchhead_ref *two = (const git_fetchhead_ref *)b; + + if (one->is_merge && !two->is_merge) + return -1; + if (two->is_merge && !one->is_merge) + return 1; + + return strcmp(one->ref_name, two->ref_name); +} + +int git_fetchhead_ref_create( + git_fetchhead_ref **fetchhead_ref_out, + git_oid *oid, + int is_merge, + const char *ref_name, + const char *remote_url) +{ + git_fetchhead_ref *fetchhead_ref = NULL; + + assert(fetchhead_ref_out && oid && ref_name && remote_url); + + fetchhead_ref = git__malloc(sizeof(git_fetchhead_ref)); + GITERR_CHECK_ALLOC(fetchhead_ref); + + memset(fetchhead_ref, 0x0, sizeof(git_fetchhead_ref)); + + git_oid_cpy(&fetchhead_ref->oid, oid); + fetchhead_ref->is_merge = is_merge; + fetchhead_ref->ref_name = git__strdup(ref_name); + fetchhead_ref->remote_url = git__strdup(remote_url); + + *fetchhead_ref_out = fetchhead_ref; + + return 0; +} + +static int fetchhead_ref_write( + git_filebuf *file, + git_fetchhead_ref *fetchhead_ref) +{ + char oid[GIT_OID_HEXSZ + 1]; + const char *type, *name; + + assert(file && fetchhead_ref); + + git_oid_fmt(oid, &fetchhead_ref->oid); + oid[GIT_OID_HEXSZ] = '\0'; + + if (git__prefixcmp(fetchhead_ref->ref_name, GIT_REFS_HEADS_DIR) == 0) { + type = "branch "; + name = fetchhead_ref->ref_name + strlen(GIT_REFS_HEADS_DIR); + } else if(git__prefixcmp(fetchhead_ref->ref_name, + GIT_REFS_TAGS_DIR) == 0) { + type = "tag "; + name = fetchhead_ref->ref_name + strlen(GIT_REFS_TAGS_DIR); + } else { + type = ""; + name = fetchhead_ref->ref_name; + } + + return git_filebuf_printf(file, "%s\t%s\t%s'%s' of %s\n", + oid, + (fetchhead_ref->is_merge) ? "" : "not-for-merge", + type, + name, + fetchhead_ref->remote_url); +} + +int git_fetchhead_write(git_repository *repo, git_vector *fetchhead_refs) +{ + git_filebuf file = GIT_FILEBUF_INIT; + git_buf path = GIT_BUF_INIT; + unsigned int i; + git_fetchhead_ref *fetchhead_ref; + + assert(repo && fetchhead_refs); + + if (git_buf_joinpath(&path, repo->path_repository, GIT_FETCH_HEAD_FILE) < 0) + return -1; + + if (git_filebuf_open(&file, path.ptr, GIT_FILEBUF_FORCE) < 0) { + git_buf_free(&path); + return -1; + } + + git_buf_free(&path); + + git_vector_sort(fetchhead_refs); + + git_vector_foreach(fetchhead_refs, i, fetchhead_ref) + fetchhead_ref_write(&file, fetchhead_ref); + + return git_filebuf_commit(&file, GIT_REFS_FILE_MODE); +} + +void git_fetchhead_ref_free(git_fetchhead_ref *fetchhead_ref) +{ + if (fetchhead_ref == NULL) + return; + + git__free(fetchhead_ref->remote_url); + git__free(fetchhead_ref->ref_name); + git__free(fetchhead_ref); +} + diff --git a/src/fetchhead.h b/src/fetchhead.h new file mode 100644 index 000000000..ec7c1985b --- /dev/null +++ b/src/fetchhead.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2009-2012 the libgit2 contributors + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_fetchhead_h__ +#define INCLUDE_fetchhead_h__ + +#include "vector.h" + +typedef struct git_fetchhead_ref { + git_oid oid; + unsigned int is_merge; + char *ref_name; + char *remote_url; +} git_fetchhead_ref; + +int git_fetchhead_ref_create(git_fetchhead_ref **fetchhead_ref_out, git_oid *oid, int is_merge, const char *ref_name, const char *remote_url); + +int git_fetchhead_ref_cmp(const void *a, const void *b); + +int git_fetchhead_write(git_repository *repository, git_vector *fetchhead_refs); + +void git_fetchhead_ref_free(git_fetchhead_ref *fetchhead_ref); + +#endif diff --git a/src/refspec.c b/src/refspec.c index 8b69e9d8e..4d9915b7a 100644 --- a/src/refspec.c +++ b/src/refspec.c @@ -236,3 +236,10 @@ int git_refspec__serialize(git_buf *out, const git_refspec *refspec) return git_buf_oom(out) == false; } + +int git_refspec_is_wildcard(const git_refspec *spec) +{ + assert(spec && spec->src); + + return (spec->src[strlen(spec->src) - 1] == '*'); +} diff --git a/src/refspec.h b/src/refspec.h index 40da16afc..e27314cc3 100644 --- a/src/refspec.h +++ b/src/refspec.h @@ -53,4 +53,12 @@ int git_refspec_transform_l(git_buf *out, const git_refspec *spec, const char *n int git_refspec__serialize(git_buf *out, const git_refspec *refspec); +/** + * Determines if a refspec is a wildcard refspec. + * + * @param spec the refspec + * @return 1 if the refspec is a wildcard, 0 otherwise + */ +int git_refspec_is_wildcard(const git_refspec *spec); + #endif diff --git a/src/remote.c b/src/remote.c index 98660fe3b..8c46ca6a1 100644 --- a/src/remote.c +++ b/src/remote.c @@ -14,6 +14,8 @@ #include "remote.h" #include "fetch.h" #include "refs.h" +#include "refspec.h" +#include "fetchhead.h" #include @@ -68,6 +70,7 @@ int git_remote_new(git_remote **out, git_repository *repo, const char *name, con memset(remote, 0x0, sizeof(git_remote)); remote->repo = repo; remote->check_cert = 1; + remote->update_fetchhead = 1; if (git_vector_init(&remote->refs, 32, NULL) < 0) return -1; @@ -116,6 +119,7 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) memset(remote, 0x0, sizeof(git_remote)); remote->check_cert = 1; + remote->update_fetchhead = 1; remote->name = git__strdup(name); GITERR_CHECK_ALLOC(remote->name); @@ -539,6 +543,120 @@ static int update_tips_callback(git_remote_head *head, void *payload) return 0; } +static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *update_heads, const char *fetchspec_src) +{ + unsigned int i; + git_remote_head *remote_ref; + + assert(update_heads && fetchspec_src); + + *out = NULL; + + git_vector_foreach(update_heads, i, remote_ref) { + if (strcmp(remote_ref->name, fetchspec_src) == 0) { + *out = remote_ref; + break; + } + } + + return 0; +} + +static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_vector *update_heads, git_reference *ref) +{ + git_reference *resolved_ref = NULL; + git_reference *tracking_ref = NULL; + git_buf remote_name = GIT_BUF_INIT; + int error = 0; + + assert(out && remote && ref); + + *out = NULL; + + if ((error = git_reference_resolve(&resolved_ref, ref)) < 0 || + (!git_reference_is_branch(resolved_ref)) || + (error = git_branch_tracking(&tracking_ref, resolved_ref)) < 0 || + (error = git_refspec_transform_l(&remote_name, &remote->fetch, git_reference_name(tracking_ref))) < 0) { + /* Not an error if HEAD is orphaned or no tracking branch */ + if (error == GIT_ENOTFOUND) + error = 0; + + goto cleanup; + } + + error = remote_head_for_fetchspec_src(out, update_heads, git_buf_cstr(&remote_name)); + +cleanup: + git_reference_free(tracking_ref); + git_reference_free(resolved_ref); + git_buf_free(&remote_name); + return error; +} + +static int git_remote_write_fetchhead(git_remote *remote, git_vector *update_heads) +{ + struct git_refspec *spec; + git_reference *head_ref = NULL; + git_fetchhead_ref *fetchhead_ref; + git_remote_head *remote_ref, *merge_remote_ref; + git_vector fetchhead_refs; + bool include_all_fetchheads; + unsigned int i = 0; + int error = 0; + + assert(remote); + + spec = &remote->fetch; + + if (git_vector_init(&fetchhead_refs, update_heads->length, git_fetchhead_ref_cmp) < 0) + return -1; + + /* Iff refspec is * (but not subdir slash star), include tags */ + include_all_fetchheads = (strcmp(GIT_REFS_HEADS_DIR "*", git_refspec_src(spec)) == 0); + + /* Determine what to merge: if refspec was a wildcard, just use HEAD */ + if (git_refspec_is_wildcard(spec)) { + if ((error = git_reference_lookup(&head_ref, remote->repo, GIT_HEAD_FILE)) < 0 || + (error = remote_head_for_ref(&merge_remote_ref, remote, update_heads, head_ref)) < 0) + goto cleanup; + } else { + /* If we're fetching a single refspec, that's the only thing that should be in FETCH_HEAD. */ + if ((error = remote_head_for_fetchspec_src(&merge_remote_ref, update_heads, git_refspec_src(spec))) < 0) + goto cleanup; + } + + /* Create the FETCH_HEAD file */ + git_vector_foreach(update_heads, i, remote_ref) { + int merge_this_fetchhead = (merge_remote_ref == remote_ref); + + if (!include_all_fetchheads && + !git_refspec_src_matches(spec, remote_ref->name) && + !merge_this_fetchhead) + continue; + + if (git_fetchhead_ref_create(&fetchhead_ref, + &remote_ref->oid, + merge_this_fetchhead, + remote_ref->name, + git_remote_url(remote)) < 0) + goto cleanup; + + if (git_vector_insert(&fetchhead_refs, fetchhead_ref) < 0) + goto cleanup; + } + + git_fetchhead_write(remote->repo, &fetchhead_refs); + +cleanup: + for (i = 0; i < fetchhead_refs.length; ++i) + git_fetchhead_ref_free(fetchhead_refs.contents[i]); + + git_vector_free(&fetchhead_refs); + git_reference_free(head_ref); + + return error; +} + int git_remote_update_tips(git_remote *remote) { int error = 0, autotag; @@ -550,7 +668,7 @@ int git_remote_update_tips(git_remote *remote) git_reference *ref; struct git_refspec *spec; git_refspec tagspec; - git_vector refs; + git_vector refs, update_heads; assert(remote); @@ -563,7 +681,8 @@ int git_remote_update_tips(git_remote *remote) return -1; /* Make a copy of the transport's refs */ - if (git_vector_init(&refs, 16, NULL) < 0) + if (git_vector_init(&refs, 16, NULL) < 0 || + git_vector_init(&update_heads, 16, NULL) < 0) return -1; if (remote->transport->ls(remote->transport, update_tips_callback, &refs) < 0) @@ -611,6 +730,9 @@ int git_remote_update_tips(git_remote *remote) if (autotag && !git_odb_exists(odb, &head->oid)) continue; + if (git_vector_insert(&update_heads, head) < 0) + goto on_error; + error = git_reference_name_to_oid(&old, remote->repo, refname.ptr); if (error < 0 && error != GIT_ENOTFOUND) goto on_error; @@ -634,13 +756,19 @@ int git_remote_update_tips(git_remote *remote) } } + if (git_remote_update_fetchhead(remote) && + (error = git_remote_write_fetchhead(remote, &update_heads)) < 0) + goto on_error; + git_vector_free(&refs); + git_vector_free(&update_heads); git_refspec__free(&tagspec); git_buf_free(&refname); return 0; on_error: git_vector_free(&refs); + git_vector_free(&update_heads); git_refspec__free(&tagspec); git_buf_free(&refname); return -1; @@ -1131,3 +1259,13 @@ int git_remote_rename( return 0; } + +int git_remote_update_fetchhead(git_remote *remote) +{ + return remote->update_fetchhead; +} + +void git_remote_set_update_fetchhead(git_remote *remote, int value) +{ + remote->update_fetchhead = value; +} diff --git a/src/remote.h b/src/remote.h index 6a90bfcb4..840c9a905 100644 --- a/src/remote.h +++ b/src/remote.h @@ -29,7 +29,8 @@ struct git_remote { git_transfer_progress stats; unsigned int need_pack:1, download_tags:2, /* There are four possible values */ - check_cert:1; + check_cert:1, + update_fetchhead:1; }; const char* git_remote__urlfordirection(struct git_remote *remote, int direction); diff --git a/tests-clar/fetchhead/fetchhead_data.h b/tests-clar/fetchhead/fetchhead_data.h new file mode 100644 index 000000000..71f67be25 --- /dev/null +++ b/tests-clar/fetchhead/fetchhead_data.h @@ -0,0 +1,21 @@ + +#define FETCH_HEAD_WILDCARD_DATA \ + "49322bb17d3acc9146f98c97d078513228bbf3c0\t\tbranch 'master' of git://github.com/libgit2/TestGitRepository\n" \ + "0966a434eb1a025db6b71485ab63a3bfbea520b6\tnot-for-merge\tbranch 'first-merge' of git://github.com/libgit2/TestGitRepository\n" \ + "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1\tnot-for-merge\tbranch 'no-parent' of git://github.com/libgit2/TestGitRepository\n" \ + "d96c4e80345534eccee5ac7b07fc7603b56124cb\tnot-for-merge\ttag 'annotated_tag' of git://github.com/libgit2/TestGitRepository\n" \ + "55a1a760df4b86a02094a904dfa511deb5655905\tnot-for-merge\ttag 'blob' of git://github.com/libgit2/TestGitRepository\n" \ + "8f50ba15d49353813cc6e20298002c0d17b0a9ee\tnot-for-merge\ttag 'commit_tree' of git://github.com/libgit2/TestGitRepository\n" + +#define FETCH_HEAD_NO_MERGE_DATA \ + "0966a434eb1a025db6b71485ab63a3bfbea520b6\tnot-for-merge\tbranch 'first-merge' of git://github.com/libgit2/TestGitRepository\n" \ + "49322bb17d3acc9146f98c97d078513228bbf3c0\tnot-for-merge\tbranch 'master' of git://github.com/libgit2/TestGitRepository\n" \ + "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1\tnot-for-merge\tbranch 'no-parent' of git://github.com/libgit2/TestGitRepository\n" \ + "d96c4e80345534eccee5ac7b07fc7603b56124cb\tnot-for-merge\ttag 'annotated_tag' of git://github.com/libgit2/TestGitRepository\n" \ + "55a1a760df4b86a02094a904dfa511deb5655905\tnot-for-merge\ttag 'blob' of git://github.com/libgit2/TestGitRepository\n" \ + "8f50ba15d49353813cc6e20298002c0d17b0a9ee\tnot-for-merge\ttag 'commit_tree' of git://github.com/libgit2/TestGitRepository\n" + + +#define FETCH_HEAD_EXPLICIT_DATA \ + "0966a434eb1a025db6b71485ab63a3bfbea520b6\t\tbranch 'first-merge' of git://github.com/libgit2/TestGitRepository\n" + diff --git a/tests-clar/fetchhead/network.c b/tests-clar/fetchhead/network.c new file mode 100644 index 000000000..ef9d01bf9 --- /dev/null +++ b/tests-clar/fetchhead/network.c @@ -0,0 +1,87 @@ +#include "clar_libgit2.h" + +#include "repository.h" +#include "fetchhead.h" +#include "fetchhead_data.h" +#include "git2/clone.h" + +CL_IN_CATEGORY("network") + +#define LIVE_REPO_URL "git://github.com/libgit2/TestGitRepository" + +static git_repository *g_repo; + +void test_fetchhead_network__initialize(void) +{ + g_repo = NULL; +} + +static void cleanup_repository(void *path) +{ + if (g_repo) + git_repository_free(g_repo); + cl_fixture_cleanup((const char *)path); +} + + +static void fetchhead_test_clone(void) +{ + cl_set_cleanup(&cleanup_repository, "./test1"); + + cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./test1", NULL, NULL, NULL)); +} + +static void fetchhead_test_fetch(const char *fetchspec, const char *expected_fetchhead) +{ + git_remote *remote; + git_buf fetchhead_buf = GIT_BUF_INIT; + int equals = 0; + + cl_git_pass(git_remote_load(&remote, g_repo, "origin")); + git_remote_set_autotag(remote, GIT_REMOTE_DOWNLOAD_TAGS_AUTO); + + if(fetchspec != NULL) + git_remote_set_fetchspec(remote, fetchspec); + + cl_git_pass(git_remote_connect(remote, GIT_DIR_FETCH)); + cl_git_pass(git_remote_download(remote, NULL, NULL)); + git_remote_disconnect(remote); + + cl_git_pass(git_remote_update_tips(remote)); + git_remote_free(remote); + + cl_git_pass(git_futils_readbuffer(&fetchhead_buf, + "./test1/.git/FETCH_HEAD")); + + equals = (strcmp(fetchhead_buf.ptr, expected_fetchhead) == 0); + + git_buf_free(&fetchhead_buf); + + cl_assert(equals); +} + +void test_fetchhead_network__wildcard_spec(void) +{ + fetchhead_test_clone(); + fetchhead_test_fetch(NULL, FETCH_HEAD_WILDCARD_DATA); +} + +void test_fetchhead_network__explicit_spec(void) +{ + fetchhead_test_clone(); + fetchhead_test_fetch("refs/heads/first-merge:refs/remotes/origin/first-merge", FETCH_HEAD_EXPLICIT_DATA); +} + +void test_fetchhead_network__no_merges(void) +{ + git_config *config; + + fetchhead_test_clone(); + + cl_git_pass(git_repository_config(&config, g_repo)); + cl_git_pass(git_config_set_string(config, "branch.master.remote", NULL)); + cl_git_pass(git_config_set_string(config, "branch.master.merge", NULL)); + git_config_free(config); + + fetchhead_test_fetch(NULL, FETCH_HEAD_NO_MERGE_DATA); +} diff --git a/tests-clar/fetchhead/nonetwork.c b/tests-clar/fetchhead/nonetwork.c new file mode 100644 index 000000000..1de5280a8 --- /dev/null +++ b/tests-clar/fetchhead/nonetwork.c @@ -0,0 +1,96 @@ +#include "clar_libgit2.h" + +#include "repository.h" +#include "fetchhead.h" +#include "fetchhead_data.h" + +#define DO_LOCAL_TEST 0 + +static git_repository *g_repo; + +void test_fetchhead_nonetwork__initialize(void) +{ + g_repo = NULL; +} + +static void cleanup_repository(void *path) +{ + if (g_repo) + git_repository_free(g_repo); + cl_fixture_cleanup((const char *)path); +} + +void test_fetchhead_nonetwork__write(void) +{ + git_vector fetchhead_vector; + git_fetchhead_ref *fetchhead[6]; + git_oid oid[6]; + git_buf fetchhead_buf = GIT_BUF_INIT; + size_t i; + int equals = 0; + + git_vector_init(&fetchhead_vector, 6, NULL); + + cl_set_cleanup(&cleanup_repository, "./test1"); + + cl_git_pass(git_repository_init(&g_repo, "./test1", 0)); + + cl_git_pass(git_oid_fromstr(&oid[0], + "49322bb17d3acc9146f98c97d078513228bbf3c0")); + cl_git_pass(git_fetchhead_ref_create(&fetchhead[0], &oid[0], 1, + "refs/heads/master", + "git://github.com/libgit2/TestGitRepository")); + cl_git_pass(git_vector_insert(&fetchhead_vector, fetchhead[0])); + + cl_git_pass(git_oid_fromstr(&oid[1], + "0966a434eb1a025db6b71485ab63a3bfbea520b6")); + cl_git_pass(git_fetchhead_ref_create(&fetchhead[1], &oid[1], 0, + "refs/heads/first-merge", + "git://github.com/libgit2/TestGitRepository")); + cl_git_pass(git_vector_insert(&fetchhead_vector, fetchhead[1])); + + cl_git_pass(git_oid_fromstr(&oid[2], + "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1")); + cl_git_pass(git_fetchhead_ref_create(&fetchhead[2], &oid[2], 0, + "refs/heads/no-parent", + "git://github.com/libgit2/TestGitRepository")); + cl_git_pass(git_vector_insert(&fetchhead_vector, fetchhead[2])); + + cl_git_pass(git_oid_fromstr(&oid[3], + "d96c4e80345534eccee5ac7b07fc7603b56124cb")); + cl_git_pass(git_fetchhead_ref_create(&fetchhead[3], &oid[3], 0, + "refs/tags/annotated_tag", + "git://github.com/libgit2/TestGitRepository")); + cl_git_pass(git_vector_insert(&fetchhead_vector, fetchhead[3])); + + cl_git_pass(git_oid_fromstr(&oid[4], + "55a1a760df4b86a02094a904dfa511deb5655905")); + cl_git_pass(git_fetchhead_ref_create(&fetchhead[4], &oid[4], 0, + "refs/tags/blob", + "git://github.com/libgit2/TestGitRepository")); + cl_git_pass(git_vector_insert(&fetchhead_vector, fetchhead[4])); + + cl_git_pass(git_oid_fromstr(&oid[5], + "8f50ba15d49353813cc6e20298002c0d17b0a9ee")); + cl_git_pass(git_fetchhead_ref_create(&fetchhead[5], &oid[5], 0, + "refs/tags/commit_tree", + "git://github.com/libgit2/TestGitRepository")); + cl_git_pass(git_vector_insert(&fetchhead_vector, fetchhead[5])); + + git_fetchhead_write(g_repo, &fetchhead_vector); + + cl_git_pass(git_futils_readbuffer(&fetchhead_buf, + "./test1/.git/FETCH_HEAD")); + + equals = (strcmp(fetchhead_buf.ptr, FETCH_HEAD_WILDCARD_DATA) == 0); + + for (i=0; i < 6; i++) + git_fetchhead_ref_free(fetchhead[i]); + + git_buf_free(&fetchhead_buf); + + git_vector_free(&fetchhead_vector); + + cl_assert(equals); +} +