static int reference_matches_remote_head( const char *reference_name, void *payload) { struct head_info *head_info = (struct head_info *)payload; git_oid oid; /* 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) 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) { /* 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; head_info->found = 1; } } return 0; }
static int reference_matches_remote_head( const char *reference_name, void *payload) { struct head_info *head_info = (struct head_info *)payload; git_oid oid; /* TODO: Should we guard against references * which name doesn't start with refs/heads/ ? */ /* Stop looking if we've already found a match */ if (git_buf_len(&head_info->branchname) > 0) return 0; if (git_reference_name_to_oid( &oid, head_info->repo, reference_name) < 0) { /* TODO: How to handle not found references? */ return -1; } if (git_oid_cmp(&head_info->remote_head_oid, &oid) == 0) { /* 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_sets( &head_info->branchname, git_buf_cstr(&head_info->branchname) + strlen(GIT_REFS_HEADS_DIR)) < 0) return -1; } return 0; }
int git_branch_set_upstream(git_reference *branch, const char *upstream_name) { git_buf key = GIT_BUF_INIT, value = GIT_BUF_INIT; git_reference *upstream; git_repository *repo; git_remote *remote = NULL; git_config *config; const char *name, *shortname; int local; const git_refspec *fetchspec; name = git_reference_name(branch); if (!git_reference__is_branch(name)) return not_a_local_branch(name); if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0) return -1; shortname = name + strlen(GIT_REFS_HEADS_DIR); if (upstream_name == NULL) return unset_upstream(config, shortname); repo = git_reference_owner(branch); /* First we need to figure out whether it's a branch or remote-tracking */ if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_LOCAL) == 0) local = 1; else if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_REMOTE) == 0) local = 0; else return GIT_ENOTFOUND; /* * If it's local, the remote is "." and the branch name is * simply the refname. Otherwise we need to figure out what * the remote-tracking branch's name on the remote is and use * that. */ if (local) git_buf_puts(&value, "."); else remote_name(&value, repo, git_reference_name(upstream)); if (git_buf_printf(&key, "branch.%s.remote", shortname) < 0) goto on_error; if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) goto on_error; if (local) { if (git_buf_puts(&value, git_reference_name(branch)) < 0) goto on_error; } else { /* Get the remoe-tracking branch's refname in its repo */ if (git_remote_load(&remote, repo, git_buf_cstr(&value)) < 0) goto on_error; fetchspec = git_remote__matching_dst_refspec(remote, git_reference_name(upstream)); git_buf_clear(&value); if (!fetchspec || git_refspec_transform_l(&value, fetchspec, git_reference_name(upstream)) < 0) goto on_error; git_remote_free(remote); remote = NULL; } git_buf_clear(&key); if (git_buf_printf(&key, "branch.%s.merge", shortname) < 0) goto on_error; if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) goto on_error; git_reference_free(upstream); git_buf_free(&key); git_buf_free(&value); return 0; on_error: git_reference_free(upstream); git_buf_free(&key); git_buf_free(&value); git_remote_free(remote); return -1; }