static const char *map_refspec(const char *ref, struct remote *remote, struct ref *local_refs) { struct ref *matched = NULL; /* Does "ref" uniquely name our ref? */ if (count_refspec_match(ref, local_refs, &matched) != 1) return ref; if (remote->push.nr) { struct refspec_item query; memset(&query, 0, sizeof(struct refspec_item)); query.src = matched->name; if (!query_refspecs(&remote->push, &query) && query.dst) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "%s%s:%s", query.force ? "+" : "", query.src, query.dst); return strbuf_detach(&buf, NULL); } } if (push_default == PUSH_DEFAULT_UPSTREAM && starts_with(matched->name, "refs/heads/")) { struct branch *branch = branch_get(matched->name + 11); if (branch->merge_nr == 1 && branch->merge[0]->src) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "%s:%s", ref, branch->merge[0]->src); return strbuf_detach(&buf, NULL); } } return ref; }
static int push_check(int argc, const char **argv, const char *prefix) { struct remote *remote; if (argc < 2) die("submodule--helper push-check requires at least 1 argument"); /* * The remote must be configured. * This is to avoid pushing to the exact same URL as the parent. */ remote = pushremote_get(argv[1]); if (!remote || remote->origin == REMOTE_UNCONFIGURED) die("remote '%s' not configured", argv[1]); /* Check the refspec */ if (argc > 2) { int i, refspec_nr = argc - 2; struct ref *local_refs = get_local_heads(); struct refspec *refspec = parse_push_refspec(refspec_nr, argv + 2); for (i = 0; i < refspec_nr; i++) { struct refspec *rs = refspec + i; if (rs->pattern || rs->matching) continue; /* * LHS must match a single ref * NEEDSWORK: add logic to special case 'HEAD' once * working with submodules in a detached head state * ceases to be the norm. */ if (count_refspec_match(rs->src, local_refs, NULL) != 1) die("src refspec '%s' must name a ref", rs->src); } free_refspec(refspec_nr, refspec); } return 0; }
static int match_explicit(struct ref *src, struct ref *dst, struct ref ***dst_tail, struct refspec *rs) { struct ref *matched_src, *matched_dst; const char *dst_value = rs->dst; char *dst_guess; if (rs->pattern || rs->matching) return 0; matched_src = matched_dst = NULL; switch (count_refspec_match(rs->src, src, &matched_src)) { case 1: break; case 0: /* The source could be in the get_sha1() format * not a reference name. :refs/other is a * way to delete 'other' ref at the remote end. */ matched_src = try_explicit_object_name(rs->src); if (!matched_src) return error("src refspec %s does not match any.", rs->src); break; default: return error("src refspec %s matches more than one.", rs->src); } if (!dst_value) { unsigned char sha1[20]; int flag; dst_value = resolve_ref(matched_src->name, sha1, 1, &flag); if (!dst_value || ((flag & REF_ISSYMREF) && prefixcmp(dst_value, "refs/heads/"))) die("%s cannot be resolved to branch.", matched_src->name); } switch (count_refspec_match(dst_value, dst, &matched_dst)) { case 1: break; case 0: if (!memcmp(dst_value, "refs/", 5)) matched_dst = make_linked_ref(dst_value, dst_tail); else if((dst_guess = guess_ref(dst_value, matched_src))) matched_dst = make_linked_ref(dst_guess, dst_tail); else error("unable to push to unqualified destination: %s\n" "The destination refspec neither matches an " "existing ref on the remote nor\n" "begins with refs/, and we are unable to " "guess a prefix based on the source ref.", dst_value); break; default: matched_dst = NULL; error("dst refspec %s matches more than one.", dst_value); break; } if (!matched_dst) return -1; if (matched_dst->peer_ref) return error("dst ref %s receives from more than one src.", matched_dst->name); else { matched_dst->peer_ref = matched_src; matched_dst->force = rs->force; } return 0; }