From 8156835df17d89bd7ce1525792aa13146fab551e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 20 May 2014 09:29:39 +0200 Subject: smart: store reported symrefs The protocol has a capability which allows the server to tell us which refs are symrefs, so we can e.g. know which is the default branch. This capability is different from the ones we already support, as it's not setting a flag to true, but requires us to store a list of refspec-formatted mappings. This commit does not yet expose the information in the reference listing. --- src/transports/smart.c | 26 +++++++++++++++--- src/transports/smart.h | 5 ++-- src/transports/smart_protocol.c | 58 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 82 insertions(+), 7 deletions(-) diff --git a/src/transports/smart.c b/src/transports/smart.c index 69eaf9b78..2f3e77726 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -7,6 +7,7 @@ #include "git2.h" #include "smart.h" #include "refs.h" +#include "refspec.h" static int git_smart__recv_cb(gitno_buffer *buf) { @@ -63,7 +64,7 @@ static int git_smart__set_callbacks( return 0; } -int git_smart__update_heads(transport_smart *t) +int git_smart__update_heads(transport_smart *t, git_vector *symrefs) { size_t i; git_pkt *pkt; @@ -81,6 +82,19 @@ int git_smart__update_heads(transport_smart *t) return 0; } +static void free_symrefs(git_vector *symrefs) +{ + git_refspec *spec; + size_t i; + + git_vector_foreach(symrefs, i, spec) { + git_refspec__free(spec); + git__free(spec); + } + + git_vector_free(symrefs); +} + static int git_smart__connect( git_transport *transport, const char *url, @@ -94,6 +108,7 @@ static int git_smart__connect( int error; git_pkt *pkt; git_pkt_ref *first; + git_vector symrefs; git_smart_service_t service; if (git_smart__reset_stream(t, true) < 0) @@ -147,8 +162,11 @@ static int git_smart__connect( first = (git_pkt_ref *)git_vector_get(&t->refs, 0); + if ((error = git_vector_init(&symrefs, 1, NULL)) < 0) + return error; + /* Detect capabilities */ - if (git_smart__detect_caps(first, &t->caps) < 0) + if (git_smart__detect_caps(first, &t->caps, &symrefs) < 0) return -1; /* If the only ref in the list is capabilities^{} with OID_ZERO, remove it */ @@ -159,7 +177,9 @@ static int git_smart__connect( } /* Keep a list of heads for _ls */ - git_smart__update_heads(t); + git_smart__update_heads(t, &symrefs); + + free_symrefs(&symrefs); if (t->rpc && git_smart__reset_stream(t, false) < 0) return -1; diff --git a/src/transports/smart.h b/src/transports/smart.h index a2b6b2a71..f1fc29520 100644 --- a/src/transports/smart.h +++ b/src/transports/smart.h @@ -23,6 +23,7 @@ #define GIT_CAP_DELETE_REFS "delete-refs" #define GIT_CAP_REPORT_STATUS "report-status" #define GIT_CAP_THIN_PACK "thin-pack" +#define GIT_CAP_SYMREF "symref" enum git_pkt_type { GIT_PKT_CMD, @@ -154,7 +155,7 @@ typedef struct { /* smart_protocol.c */ int git_smart__store_refs(transport_smart *t, int flushes); -int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps); +int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vector *symrefs); int git_smart__push(git_transport *transport, git_push *push); int git_smart__negotiate_fetch( @@ -174,7 +175,7 @@ int git_smart__download_pack( int git_smart__negotiation_step(git_transport *transport, void *data, size_t len); int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream **out); -int git_smart__update_heads(transport_smart *t); +int git_smart__update_heads(transport_smart *t, git_vector *symrefs); /* smart_pkt.c */ int git_pkt_parse_line(git_pkt **head, const char *line, const char **out, size_t len); diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index 5dd6bab24..bab0cf113 100644 --- a/src/transports/smart_protocol.c +++ b/src/transports/smart_protocol.c @@ -78,7 +78,52 @@ int git_smart__store_refs(transport_smart *t, int flushes) return flush; } -int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps) +static int append_symref(const char **out, git_vector *symrefs, const char *ptr) +{ + int error; + const char *end; + git_buf buf = GIT_BUF_INIT; + git_refspec *mapping; + + ptr += strlen(GIT_CAP_SYMREF); + if (*ptr != '=') + goto on_invalid; + + ptr++; + if (!(end = strchr(ptr, ' ')) && + !(end = strchr(ptr, '\0'))) + goto on_invalid; + + if ((error = git_buf_put(&buf, ptr, end - ptr)) < 0) + return error; + + /* symref mapping has refspec format */ + mapping = git__malloc(sizeof(git_refspec)); + GITERR_CHECK_ALLOC(mapping); + + error = git_refspec__parse(mapping, git_buf_cstr(&buf), true); + git_buf_free(&buf); + + /* if the error isn't OOM, then it's a parse error; let's use a nicer message */ + if (error < 0) { + if (giterr_last()->klass != GITERR_NOMEMORY) + goto on_invalid; + + return error; + } + + if ((error = git_vector_insert(symrefs, mapping)) < 0) + return error; + + *out = end; + return 0; + +on_invalid: + giterr_set(GITERR_NET, "remote sent invalid symref"); + return -1; +} + +int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vector *symrefs) { const char *ptr; @@ -141,6 +186,15 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps) continue; } + if (!git__prefixcmp(ptr, GIT_CAP_SYMREF)) { + int error; + + if ((error = append_symref(&ptr, symrefs, ptr)) < 0) + return error; + + continue; + } + /* We don't know this capability, so skip it */ ptr = strchr(ptr, ' '); } @@ -969,7 +1023,7 @@ int git_smart__push(git_transport *transport, git_push *push) if (error < 0) goto done; - error = git_smart__update_heads(t); + error = git_smart__update_heads(t, NULL); } done: -- cgit v1.2.1 From 306475eb0173d7943a27afee6054af8d0f76bedd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 20 May 2014 09:55:26 +0200 Subject: remote: expose the remote's symref mappings Add a symref_target field to git_remote_head to expose the symref mappings to the user. --- include/git2/net.h | 5 +++++ src/transports/smart.c | 19 +++++++++++++++++++ src/transports/smart_pkt.c | 1 + tests/online/fetch.c | 18 ++++++++++++++++++ 4 files changed, 43 insertions(+) diff --git a/include/git2/net.h b/include/git2/net.h index e70ba1f71..a727696a2 100644 --- a/include/git2/net.h +++ b/include/git2/net.h @@ -41,6 +41,11 @@ struct git_remote_head { git_oid oid; git_oid loid; char *name; + /** + * If the server send a symref mapping for this ref, this will + * point to the target. + */ + char *symref_target; }; /** diff --git a/src/transports/smart.c b/src/transports/smart.c index 2f3e77726..47ef5038c 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -75,6 +75,25 @@ int git_smart__update_heads(transport_smart *t, git_vector *symrefs) if (pkt->type != GIT_PKT_REF) continue; + if (symrefs) { + git_refspec *spec; + git_buf buf = GIT_BUF_INIT; + size_t j; + int error; + + git_vector_foreach(symrefs, j, spec) { + git_buf_clear(&buf); + if (git_refspec_src_matches(spec, ref->head.name) && + !(error = git_refspec_transform(&buf, spec, ref->head.name))) + ref->head.symref_target = git_buf_detach(&buf); + } + + git_buf_free(&buf); + + if (error < 0) + return error; + } + if (git_vector_insert(&t->heads, &ref->head) < 0) return -1; } diff --git a/src/transports/smart_pkt.c b/src/transports/smart_pkt.c index e9376ae6f..b5f9d6dbe 100644 --- a/src/transports/smart_pkt.c +++ b/src/transports/smart_pkt.c @@ -433,6 +433,7 @@ void git_pkt_free(git_pkt *pkt) if (pkt->type == GIT_PKT_REF) { git_pkt_ref *p = (git_pkt_ref *) pkt; git__free(p->head.name); + git__free(p->head.symref_target); } if (pkt->type == GIT_PKT_OK) { diff --git a/tests/online/fetch.c b/tests/online/fetch.c index c54ec5673..f03a6faa6 100644 --- a/tests/online/fetch.c +++ b/tests/online/fetch.c @@ -184,3 +184,21 @@ void test_online_fetch__ls_disconnected(void) git_remote_free(remote); } + +void test_online_fetch__remote_symrefs(void) +{ + const git_remote_head **refs; + size_t refs_len; + git_remote *remote; + + cl_git_pass(git_remote_create(&remote, _repo, "test", + "http://github.com/libgit2/TestGitRepository.git")); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH)); + git_remote_disconnect(remote); + cl_git_pass(git_remote_ls(&refs, &refs_len, remote)); + + cl_assert_equal_s("HEAD", refs[0]->name); + cl_assert_equal_s("refs/heads/master", refs[0]->symref_target); + + git_remote_free(remote); +} -- cgit v1.2.1 From 04865aa05e9d16ad56920103678ee4c34578da78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 21 May 2014 10:01:44 +0200 Subject: local transport: expose the symref data When using the local transport, we always have the symbolic information available, so fill it. --- src/transports/local.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/transports/local.c b/src/transports/local.c index 2c17e6271..8d3619388 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -43,14 +43,19 @@ typedef struct { static int add_ref(transport_local *t, const char *name) { const char peeled[] = "^{}"; - git_oid head_oid; + git_reference *ref, *resolved; git_remote_head *head; + git_oid obj_id; git_object *obj = NULL, *target = NULL; git_buf buf = GIT_BUF_INIT; int error; - error = git_reference_name_to_id(&head_oid, t->repo, name); + if ((error = git_reference_lookup(&ref, t->repo, name)) < 0) + return error; + + error = git_reference_resolve(&resolved, ref); if (error < 0) { + git_reference_free(ref); 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". */ @@ -60,13 +65,22 @@ static int add_ref(transport_local *t, const char *name) return error; } + git_oid_cpy(&obj_id, git_reference_target(resolved)); + git_reference_free(resolved); + head = git__calloc(1, sizeof(git_remote_head)); GITERR_CHECK_ALLOC(head); head->name = git__strdup(name); GITERR_CHECK_ALLOC(head->name); - git_oid_cpy(&head->oid, &head_oid); + git_oid_cpy(&head->oid, &obj_id); + + if (git_reference_type(ref) == GIT_REF_SYMBOLIC) { + head->symref_target = git__strdup(git_reference_symbolic_target(ref)); + GITERR_CHECK_ALLOC(head->symref_target); + } + git_reference_free(ref); if ((error = git_vector_insert(&t->refs, head)) < 0) { git__free(head->name); @@ -176,7 +190,7 @@ static int path_from_url_or_path(git_buf *local_path_out, const char *url_or_pat /* * Try to open the url as a git directory. The direction doesn't - * matter in this case because we're calulating the heads ourselves. + * matter in this case because we're calculating the heads ourselves. */ static int local_connect( git_transport *transport, -- cgit v1.2.1 From d22db24fb75134f30c3a72af0bc47fc7f0a07f33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 21 May 2014 09:32:35 +0200 Subject: remote: add api to guess the remote's default branch If the remote supports the symref protocol extension, then we return that, otherwise we guess with git's rules. --- include/git2/remote.h | 18 +++++++++++++ src/remote.c | 47 +++++++++++++++++++++++++++++++++ tests/network/remote/defaultbranch.c | 50 ++++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 tests/network/remote/defaultbranch.c diff --git a/include/git2/remote.h b/include/git2/remote.h index 07cd2e7c6..28771ac42 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -623,6 +623,24 @@ GIT_EXTERN(int) git_remote_is_valid_name(const char *remote_name); */ GIT_EXTERN(int) git_remote_delete(git_remote *remote); +/** + * Retrieve the name of the remote's default branch + * + * The default branch of a repository is the branch which HEAD points + * to. If the remote does not support reporting this information + * directly, it performs the guess as git does; that is, if there are + * multiple branches which point to the same commit, the first one is + * chosen. If the master branch is a candidate, it wins. + * + * This function must only be called after connecting. + * + * @param out the buffern in which to store the reference name + * @param remote the remote + * @return 0, GIT_ENOTFOUND if the remote does not have any references + * or none of them point to HEAD's commit, or an error message. + */ +GIT_EXTERN(int) git_remote_default_branch(git_buf *out, git_remote *remote); + /** @} */ GIT_END_DECL #endif diff --git a/src/remote.c b/src/remote.c index bdc4791a9..f2e2e2f7a 100644 --- a/src/remote.c +++ b/src/remote.c @@ -1885,3 +1885,50 @@ int git_remote_delete(git_remote *remote) return 0; } + +int git_remote_default_branch(git_buf *out, git_remote *remote) +{ + const git_remote_head **heads; + const git_remote_head *guess = NULL; + const git_oid *head_id; + size_t heads_len, i; + int error; + + if ((error = git_remote_ls(&heads, &heads_len, remote)) < 0) + return error; + + if (heads_len == 0) + return GIT_ENOTFOUND; + + git_buf_sanitize(out); + /* the first one must be HEAD so if that has the symref info, we're done */ + if (heads[0]->symref_target) + return git_buf_puts(out, heads[0]->symref_target); + + /* + * If there's no symref information, we have to look over them + * and guess. We return the first match unless the master + * branch is a candidate. Then we return the master branch. + */ + head_id = &heads[0]->oid; + + for (i = 1; i < heads_len; i++) { + if (git_oid_cmp(head_id, &heads[i]->oid)) + continue; + + if (!guess) { + guess = heads[i]; + continue; + } + + if (!git__strcmp(GIT_REFS_HEADS_MASTER_FILE, heads[i]->name)) { + guess = heads[i]; + break; + } + } + + if (!guess) + return GIT_ENOTFOUND; + + return git_buf_puts(out, guess->name); +} diff --git a/tests/network/remote/defaultbranch.c b/tests/network/remote/defaultbranch.c new file mode 100644 index 000000000..fa3a329db --- /dev/null +++ b/tests/network/remote/defaultbranch.c @@ -0,0 +1,50 @@ +#include "clar_libgit2.h" +#include "buffer.h" +#include "refspec.h" +#include "remote.h" + +static git_remote *g_remote; +static git_repository *g_repo_a, *g_repo_b; + +void test_network_remote_defaultbranch__initialize(void) +{ + g_repo_a = cl_git_sandbox_init("testrepo.git"); + cl_git_pass(git_repository_init(&g_repo_b, "repo-b.git", true)); + cl_git_pass(git_remote_create(&g_remote, g_repo_b, "origin", git_repository_path(g_repo_a))); +} + +void test_network_remote_defaultbranch__cleanup(void) +{ + git_remote_free(g_remote); + git_repository_free(g_repo_b); + + cl_git_sandbox_cleanup(); + cl_fixture_cleanup("repo-b.git"); +} + +static void assert_default_branch(const char *should) +{ + git_buf name = GIT_BUF_INIT; + + cl_git_pass(git_remote_connect(g_remote, GIT_DIRECTION_FETCH)); + cl_git_pass(git_remote_default_branch(&name, g_remote)); + cl_assert_equal_s(should, name.ptr); + git_buf_free(&name); +} + +void test_network_remote_defaultbranch__master(void) +{ + assert_default_branch("refs/heads/master"); +} + +void test_network_remote_defaultbranch__master_does_not_win(void) +{ + cl_git_pass(git_repository_set_head(g_repo_a, "refs/heads/not-good", NULL, NULL)); + assert_default_branch("refs/heads/not-good"); +} + +void test_network_remote_defaultbranch__master_on_detached(void) +{ + cl_git_pass(git_repository_detach_head(g_repo_a, NULL, NULL)); + assert_default_branch("refs/heads/master"); +} -- cgit v1.2.1 From cdb8a608249b3d0b9e8fe1b3ea1e9c1aa731ab8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 21 May 2014 11:51:33 +0200 Subject: clone: make use of the remote's default branch guessing Let's use the remote's default branch guessing instead of reinventing one ourselves with callbacks. --- src/clone.c | 84 +++++++++++++------------------------------------------------ 1 file changed, 17 insertions(+), 67 deletions(-) diff --git a/src/clone.c b/src/clone.c index 9ac9eb2a1..b6a0f03d0 100644 --- a/src/clone.c +++ b/src/clone.c @@ -108,51 +108,10 @@ static int create_tracking_branch( struct head_info { git_repository *repo; git_oid remote_head_oid; - git_buf branchname; const git_refspec *refspec; bool found; }; -static int reference_matches_remote_head( - const char *reference_name, - void *payload) -{ - struct head_info *head_info = (struct head_info *)payload; - git_oid oid; - int error; - - /* TODO: Should we guard against references - * which name doesn't start with refs/heads/ ? - */ - - error = git_reference_name_to_id(&oid, head_info->repo, reference_name); - if (error == GIT_ENOTFOUND) { - /* If the reference doesn't exists, it obviously cannot match the - * expected oid. */ - giterr_clear(); - return 0; - } - - if (!error && !git_oid__cmp(&head_info->remote_head_oid, &oid)) { - /* Determine the local reference name from the remote tracking one */ - error = git_refspec_rtransform( - &head_info->branchname, head_info->refspec, reference_name); - - if (!error && - git_buf_len(&head_info->branchname) > 0 && - !(error = git_buf_sets( - &head_info->branchname, - git_buf_cstr(&head_info->branchname) + - strlen(GIT_REFS_HEADS_DIR)))) - { - head_info->found = true; - error = GIT_ITEROVER; - } - } - - return error; -} - static int update_head_to_new_branch( git_repository *repo, const git_oid *target, @@ -161,6 +120,10 @@ static int update_head_to_new_branch( const char *reflog_message) { git_reference *tracking_branch = NULL; + + if (!git__prefixcmp(name, GIT_REFS_HEADS_DIR)) + name += strlen(GIT_REFS_HEADS_DIR); + int error = create_tracking_branch(&tracking_branch, repo, target, name, signature, reflog_message); @@ -190,6 +153,7 @@ static int update_head_to_remote( const git_remote_head *remote_head, **refs; struct head_info head_info; git_buf remote_master_name = GIT_BUF_INIT; + git_buf branch = GIT_BUF_INIT; if ((error = git_remote_ls(&refs, &refs_len, remote)) < 0) return error; @@ -199,15 +163,22 @@ static int update_head_to_remote( return setup_tracking_config( repo, "master", GIT_REMOTE_ORIGIN, GIT_REFS_HEADS_MASTER_FILE); + memset(&head_info, 0, sizeof(head_info)); + error = git_remote_default_branch(&branch, remote); + if (error == GIT_ENOTFOUND) { + git_buf_puts(&branch, GIT_REFS_HEADS_MASTER_FILE); + } else { + head_info.found = 1; + } + /* Get the remote's HEAD. This is always the first ref in the list. */ remote_head = refs[0]; assert(remote_head); - memset(&head_info, 0, sizeof(head_info)); git_oid_cpy(&head_info.remote_head_oid, &remote_head->oid); head_info.repo = repo; head_info.refspec = - git_remote__matching_refspec(remote, GIT_REFS_HEADS_MASTER_FILE); + git_remote__matching_refspec(remote, git_buf_cstr(&branch)); if (head_info.refspec == NULL) { memset(&dummy_spec, 0, sizeof(git_refspec)); @@ -218,35 +189,14 @@ static int update_head_to_remote( if ((error = git_refspec_transform( &remote_master_name, head_info.refspec, - GIT_REFS_HEADS_MASTER_FILE)) < 0) + git_buf_cstr(&branch))) < 0) return error; - /* Check to see if the remote HEAD points to the remote master */ - error = reference_matches_remote_head( - git_buf_cstr(&remote_master_name), &head_info); - if (error < 0 && error != GIT_ITEROVER) - goto cleanup; - - if (head_info.found) { - error = update_head_to_new_branch( - repo, - &head_info.remote_head_oid, - git_buf_cstr(&head_info.branchname), - signature, reflog_message); - goto cleanup; - } - - /* Not master. Check all the other refs. */ - error = git_reference_foreach_name( - repo, reference_matches_remote_head, &head_info); - if (error < 0 && error != GIT_ITEROVER) - goto cleanup; - if (head_info.found) { error = update_head_to_new_branch( repo, &head_info.remote_head_oid, - git_buf_cstr(&head_info.branchname), + git_buf_cstr(&branch), signature, reflog_message); } else { error = git_repository_set_head_detached( @@ -255,7 +205,7 @@ static int update_head_to_remote( cleanup: git_buf_free(&remote_master_name); - git_buf_free(&head_info.branchname); + git_buf_free(&branch); return error; } -- cgit v1.2.1 From 2a597116583696486141261a8b459319b513facf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 21 May 2014 11:54:10 +0200 Subject: clone: get rid of head_info Since we no longer need to push data to callbacks, there's no need for this truct. --- src/clone.c | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/src/clone.c b/src/clone.c index b6a0f03d0..f19771c1e 100644 --- a/src/clone.c +++ b/src/clone.c @@ -105,13 +105,6 @@ static int create_tracking_branch( git_reference_name(*branch)); } -struct head_info { - git_repository *repo; - git_oid remote_head_oid; - const git_refspec *refspec; - bool found; -}; - static int update_head_to_new_branch( git_repository *repo, const git_oid *target, @@ -147,11 +140,11 @@ static int update_head_to_remote( const git_signature *signature, const char *reflog_message) { - int error = 0; + int error = 0, found_branch = 0; size_t refs_len; - git_refspec dummy_spec; + git_refspec dummy_spec, *refspec; const git_remote_head *remote_head, **refs; - struct head_info head_info; + const git_oid *remote_head_id; git_buf remote_master_name = GIT_BUF_INIT; git_buf branch = GIT_BUF_INIT; @@ -163,47 +156,43 @@ static int update_head_to_remote( return setup_tracking_config( repo, "master", GIT_REMOTE_ORIGIN, GIT_REFS_HEADS_MASTER_FILE); - memset(&head_info, 0, sizeof(head_info)); error = git_remote_default_branch(&branch, remote); if (error == GIT_ENOTFOUND) { git_buf_puts(&branch, GIT_REFS_HEADS_MASTER_FILE); } else { - head_info.found = 1; + found_branch = 1; } /* Get the remote's HEAD. This is always the first ref in the list. */ remote_head = refs[0]; assert(remote_head); - git_oid_cpy(&head_info.remote_head_oid, &remote_head->oid); - head_info.repo = repo; - head_info.refspec = - git_remote__matching_refspec(remote, git_buf_cstr(&branch)); + remote_head_id = &remote_head->oid; + refspec = git_remote__matching_refspec(remote, git_buf_cstr(&branch)); - if (head_info.refspec == NULL) { + if (refspec == NULL) { memset(&dummy_spec, 0, sizeof(git_refspec)); - head_info.refspec = &dummy_spec; + refspec = &dummy_spec; } /* Determine the remote tracking reference name from the local master */ if ((error = git_refspec_transform( &remote_master_name, - head_info.refspec, + refspec, git_buf_cstr(&branch))) < 0) return error; - if (head_info.found) { + if (found_branch) { error = update_head_to_new_branch( repo, - &head_info.remote_head_oid, + remote_head_id, git_buf_cstr(&branch), signature, reflog_message); } else { error = git_repository_set_head_detached( - repo, &head_info.remote_head_oid, signature, reflog_message); + repo, remote_head_id, signature, reflog_message); } -cleanup: git_buf_free(&remote_master_name); git_buf_free(&branch); return error; -- cgit v1.2.1