diff options
Diffstat (limited to 'src/clone.c')
-rw-r--r-- | src/clone.c | 120 |
1 files changed, 55 insertions, 65 deletions
diff --git a/src/clone.c b/src/clone.c index 23aacd478..415efabba 100644 --- a/src/clone.c +++ b/src/clone.c @@ -107,6 +107,7 @@ struct head_info { git_buf branchname; const git_refspec *refspec; bool found; + git_error_state error; }; static int reference_matches_remote_head( @@ -115,43 +116,38 @@ static int reference_matches_remote_head( { 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/ ? */ - /* Stop looking if we've already found a match */ - if (head_info->found) + 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 (git_reference_name_to_id( - &oid, - head_info->repo, - reference_name) < 0) { - /* If the reference doesn't exists, it obviously cannot match the expected oid. */ - giterr_clear(); - return 0; } - if (git_oid__cmp(&head_info->remote_head_oid, &oid) == 0) { + if (!error && !git_oid__cmp(&head_info->remote_head_oid, &oid)) { /* Determine the local reference name from the remote tracking one */ - if (git_refspec_transform_l( - &head_info->branchname, - head_info->refspec, - reference_name) < 0) - return -1; - - if (git_buf_len(&head_info->branchname) > 0) { - if (git_buf_sets( - &head_info->branchname, - git_buf_cstr(&head_info->branchname) + strlen(GIT_REFS_HEADS_DIR)) < 0) - return -1; + error = git_refspec_transform_l( + &head_info->branchname, head_info->refspec, reference_name); - head_info->found = 1; + 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 0; + return giterr_capture(&head_info->error, error); } static int update_head_to_new_branch( @@ -160,16 +156,11 @@ static int update_head_to_new_branch( const char *name) { git_reference *tracking_branch = NULL; - int error; - - if ((error = create_tracking_branch( - &tracking_branch, - repo, - target, - name)) < 0) - return error; + int error = create_tracking_branch(&tracking_branch, repo, target, name); - error = git_repository_set_head(repo, git_reference_name(tracking_branch)); + if (!error) + error = git_repository_set_head( + repo, git_reference_name(tracking_branch)); git_reference_free(tracking_branch); @@ -178,34 +169,30 @@ static int update_head_to_new_branch( static int update_head_to_remote(git_repository *repo, git_remote *remote) { - int retcode = -1; + int error = 0; size_t refs_len; git_refspec dummy_spec; const git_remote_head *remote_head, **refs; struct head_info head_info; git_buf remote_master_name = GIT_BUF_INIT; - if (git_remote_ls(&refs, &refs_len, remote) < 0) - return -1; + if ((error = git_remote_ls(&refs, &refs_len, remote)) < 0) + return error; /* Did we just clone an empty repository? */ - if (refs_len == 0) { + if (refs_len == 0) return setup_tracking_config( - repo, - "master", - GIT_REMOTE_ORIGIN, - GIT_REFS_HEADS_MASTER_FILE); - } + repo, "master", GIT_REMOTE_ORIGIN, GIT_REFS_HEADS_MASTER_FILE); /* 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); - git_buf_init(&head_info.branchname, 16); head_info.repo = repo; - head_info.refspec = git_remote__matching_refspec(remote, GIT_REFS_HEADS_MASTER_FILE); - head_info.found = 0; + head_info.refspec = + git_remote__matching_refspec(remote, GIT_REFS_HEADS_MASTER_FILE); if (head_info.refspec == NULL) { memset(&dummy_spec, 0, sizeof(git_refspec)); @@ -213,50 +200,53 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote) } /* Determine the remote tracking reference name from the local master */ - if (git_refspec_transform_r( + if ((error = git_refspec_transform_r( &remote_master_name, head_info.refspec, - GIT_REFS_HEADS_MASTER_FILE) < 0) - return -1; + GIT_REFS_HEADS_MASTER_FILE)) < 0) + return error; /* Check to see if the remote HEAD points to the remote master */ - if (reference_matches_remote_head(git_buf_cstr(&remote_master_name), &head_info) < 0) - goto cleanup; + error = reference_matches_remote_head( + git_buf_cstr(&remote_master_name), &head_info); + + if (error < 0) { + error = giterr_restore(&head_info.error); + if (error < 0 && error != GIT_ITEROVER) + goto cleanup; + } if (head_info.found) { - retcode = update_head_to_new_branch( + error = update_head_to_new_branch( repo, &head_info.remote_head_oid, git_buf_cstr(&head_info.branchname)); - goto cleanup; } /* Not master. Check all the other refs. */ - if (git_reference_foreach_name( - repo, - reference_matches_remote_head, - &head_info) < 0) - goto cleanup; + error = git_reference_foreach_name( + repo, reference_matches_remote_head, &head_info); + + if (error == GIT_EUSER) + error = giterr_restore(&head_info.error); + if (error < 0 && error != GIT_ITEROVER) + goto cleanup; if (head_info.found) { - retcode = update_head_to_new_branch( + error = update_head_to_new_branch( repo, &head_info.remote_head_oid, git_buf_cstr(&head_info.branchname)); - - goto cleanup; } else { - retcode = git_repository_set_head_detached( - repo, - &head_info.remote_head_oid); - goto cleanup; + error = git_repository_set_head_detached( + repo, &head_info.remote_head_oid); } cleanup: git_buf_free(&remote_master_name); git_buf_free(&head_info.branchname); - return retcode; + return error; } static int update_head_to_branch( |