clone: leverage refspec transform
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
diff --git a/src/clone.c b/src/clone.c
index dac741f..312a38e 100644
--- a/src/clone.c
+++ b/src/clone.c
@@ -73,21 +73,47 @@ struct head_info {
git_repository *repo;
git_oid remote_head_oid;
git_buf branchname;
+ const git_refspec *refspec;
};
-static int reference_matches_remote_head(const char *head_name, void *payload)
+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_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_reference_name_to_oid(&oid, head_info->repo, head_name) &&
- !git_oid_cmp(&head_info->remote_head_oid, &oid)) {
- git_buf_puts(&head_info->branchname,
- head_name+strlen(GIT_REFS_REMOTES_DIR "origin/"));
+ 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;
}
@@ -108,31 +134,60 @@ static int update_head_to_new_branch(git_repository *repo, const git_oid *target
static int update_head_to_remote(git_repository *repo, git_remote *remote)
{
- int retcode = GIT_ERROR;
+ int retcode = -1;
git_remote_head *remote_head;
- git_oid oid;
struct head_info head_info;
+ git_buf remote_master_name = GIT_BUF_INIT;
/* Get the remote's HEAD. This is always the first ref in remote->refs. */
remote_head = remote->refs.contents[0];
git_oid_cpy(&head_info.remote_head_oid, &remote_head->oid);
git_buf_init(&head_info.branchname, 16);
head_info.repo = repo;
-
- /* Check to see if "master" matches the remote head */
- if (!git_reference_name_to_oid(&oid, repo, GIT_REFS_REMOTES_DIR "origin/master") &&
- !git_oid_cmp(&remote_head->oid, &oid)) {
- retcode = update_head_to_new_branch(repo, &oid, "master");
+ head_info.refspec = git_remote_fetchspec(remote);
+
+ /* Determine the remote tracking reference name from the local master */
+ if (git_refspec_transform_r(
+ &remote_master_name,
+ head_info.refspec,
+ GIT_REFS_HEADS_MASTER_FILE) < 0)
+ return -1;
+
+ /* 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;
+
+ if (git_buf_len(&head_info.branchname) > 0) {
+ retcode = 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. */
- else if (!git_reference_foreach(repo, GIT_REF_LISTALL,
- reference_matches_remote_head,
- &head_info) &&
- git_buf_len(&head_info.branchname) > 0) {
- retcode = update_head_to_new_branch(repo, &head_info.remote_head_oid,
- git_buf_cstr(&head_info.branchname));
+ if (git_reference_foreach(
+ repo,
+ GIT_REF_LISTALL,
+ reference_matches_remote_head,
+ &head_info) < 0)
+ goto cleanup;
+
+ if (git_buf_len(&head_info.branchname) > 0) {
+ retcode = update_head_to_new_branch(
+ repo,
+ &head_info.remote_head_oid,
+ git_buf_cstr(&head_info.branchname));
+
+ goto cleanup;
+ } else {
+ /* TODO: What should we do if nothing has been found?
+ */
}
+cleanup:
+ git_buf_free(&remote_master_name);
git_buf_free(&head_info.branchname);
return retcode;
}