/** * Derives the remote tracking branch from the remote and refspec. * * FIXME: The current implementation assumes the default mapping of * refs/heads/<branch_name> to refs/remotes/<remote_name>/<branch_name>. */ static const char *get_tracking_branch(const char *remote, const char *refspec) { struct refspec *spec; const char *spec_src; const char *merge_branch; spec = parse_fetch_refspec(1, &refspec); spec_src = spec->src; if (!*spec_src || !strcmp(spec_src, "HEAD")) spec_src = "HEAD"; else if (skip_prefix(spec_src, "heads/", &spec_src)) ; else if (skip_prefix(spec_src, "refs/heads/", &spec_src)) ; else if (starts_with(spec_src, "refs/") || starts_with(spec_src, "tags/") || starts_with(spec_src, "remotes/")) spec_src = ""; if (*spec_src) { if (!strcmp(remote, ".")) merge_branch = mkpath("refs/heads/%s", spec_src); else merge_branch = mkpath("refs/remotes/%s/%s", remote, spec_src); } else merge_branch = NULL; free_refspec(1, spec); return merge_branch; }
static int release_helper(struct transport *transport) { struct helper_data *data = transport->data; free_refspec(data->refspec_nr, data->refspecs); data->refspecs = NULL; disconnect_helper(transport); free(transport->data); return 0; }
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; }
int transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags, unsigned int *reject_reasons) { *reject_reasons = 0; transport_verify_remote_names(refspec_nr, refspec); if (transport_color_config() < 0) return -1; if (transport->vtable->push_refs) { struct ref *remote_refs; struct ref *local_refs = get_local_heads(); int match_flags = MATCH_REFS_NONE; int verbose = (transport->verbose > 0); int quiet = (transport->verbose < 0); int porcelain = flags & TRANSPORT_PUSH_PORCELAIN; int pretend = flags & TRANSPORT_PUSH_DRY_RUN; int push_ret, ret, err; struct refspec *tmp_rs; struct argv_array ref_prefixes = ARGV_ARRAY_INIT; int i; if (check_push_refs(local_refs, refspec_nr, refspec) < 0) return -1; tmp_rs = parse_push_refspec(refspec_nr, refspec); for (i = 0; i < refspec_nr; i++) { const char *prefix = NULL; if (tmp_rs[i].dst) prefix = tmp_rs[i].dst; else if (tmp_rs[i].src && !tmp_rs[i].exact_sha1) prefix = tmp_rs[i].src; if (prefix) { const char *glob = strchr(prefix, '*'); if (glob) argv_array_pushf(&ref_prefixes, "%.*s", (int)(glob - prefix), prefix); else expand_ref_prefix(&ref_prefixes, prefix); } } remote_refs = transport->vtable->get_refs_list(transport, 1, &ref_prefixes); argv_array_clear(&ref_prefixes); free_refspec(refspec_nr, tmp_rs); if (flags & TRANSPORT_PUSH_ALL) match_flags |= MATCH_REFS_ALL; if (flags & TRANSPORT_PUSH_MIRROR) match_flags |= MATCH_REFS_MIRROR; if (flags & TRANSPORT_PUSH_PRUNE) match_flags |= MATCH_REFS_PRUNE; if (flags & TRANSPORT_PUSH_FOLLOW_TAGS) match_flags |= MATCH_REFS_FOLLOW_TAGS; if (match_push_refs(local_refs, &remote_refs, refspec_nr, refspec, match_flags)) { return -1; } if (transport->smart_options && transport->smart_options->cas && !is_empty_cas(transport->smart_options->cas)) apply_push_cas(transport->smart_options->cas, transport->remote, remote_refs); set_ref_status_for_push(remote_refs, flags & TRANSPORT_PUSH_MIRROR, flags & TRANSPORT_PUSH_FORCE); if (!(flags & TRANSPORT_PUSH_NO_HOOK)) if (run_pre_push_hook(transport, remote_refs)) return -1; if ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND | TRANSPORT_RECURSE_SUBMODULES_ONLY)) && !is_bare_repository()) { struct ref *ref = remote_refs; struct oid_array commits = OID_ARRAY_INIT; for (; ref; ref = ref->next) if (!is_null_oid(&ref->new_oid)) oid_array_append(&commits, &ref->new_oid); if (!push_unpushed_submodules(&commits, transport->remote, refspec, refspec_nr, transport->push_options, pretend)) { oid_array_clear(&commits); die("Failed to push all needed submodules!"); } oid_array_clear(&commits); } if (((flags & TRANSPORT_RECURSE_SUBMODULES_CHECK) || ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND | TRANSPORT_RECURSE_SUBMODULES_ONLY)) && !pretend)) && !is_bare_repository()) { struct ref *ref = remote_refs; struct string_list needs_pushing = STRING_LIST_INIT_DUP; struct oid_array commits = OID_ARRAY_INIT; for (; ref; ref = ref->next) if (!is_null_oid(&ref->new_oid)) oid_array_append(&commits, &ref->new_oid); if (find_unpushed_submodules(&commits, transport->remote->name, &needs_pushing)) { oid_array_clear(&commits); die_with_unpushed_submodules(&needs_pushing); } string_list_clear(&needs_pushing, 0); oid_array_clear(&commits); } if (!(flags & TRANSPORT_RECURSE_SUBMODULES_ONLY)) push_ret = transport->vtable->push_refs(transport, remote_refs, flags); else push_ret = 0; err = push_had_errors(remote_refs); ret = push_ret | err; if (!quiet || err) transport_print_push_status(transport->url, remote_refs, verbose | porcelain, porcelain, reject_reasons); if (flags & TRANSPORT_PUSH_SET_UPSTREAM) set_upstreams(transport, remote_refs, pretend); if (!(flags & (TRANSPORT_PUSH_DRY_RUN | TRANSPORT_RECURSE_SUBMODULES_ONLY))) { struct ref *ref; for (ref = remote_refs; ref; ref = ref->next) transport_update_tracking_ref(transport->remote, ref, verbose); } if (porcelain && !push_ret) puts("Done"); else if (!quiet && !ret && !transport_refs_pushed(remote_refs)) fprintf(stderr, "Everything up-to-date\n"); return ret; } return 1; }