summaryrefslogtreecommitdiff
path: root/refs.c
diff options
context:
space:
mode:
Diffstat (limited to 'refs.c')
-rw-r--r--refs.c222
1 files changed, 143 insertions, 79 deletions
diff --git a/refs.c b/refs.c
index 118465271d..998d5c3565 100644
--- a/refs.c
+++ b/refs.c
@@ -664,7 +664,8 @@ char *repo_default_branch_name(struct repository *r, int quiet)
if (!ret) {
ret = xstrdup("master");
if (!quiet)
- advise(_(default_branch_name_advice), ret);
+ advise_if_enabled(ADVICE_DEFAULT_BRANCH_NAME,
+ _(default_branch_name_advice), ret);
}
full_ref = xstrfmt("refs/heads/%s", ret);
@@ -1377,7 +1378,7 @@ int ref_transaction_create(struct ref_transaction *transaction,
return 1;
}
return ref_transaction_update(transaction, refname, new_oid,
- null_oid(), new_target, NULL, flags,
+ null_oid(the_hash_algo), new_target, NULL, flags,
msg, err);
}
@@ -1396,7 +1397,7 @@ int ref_transaction_delete(struct ref_transaction *transaction,
if (old_target && !(flags & REF_NO_DEREF))
BUG("delete cannot operate on symrefs with deref mode");
return ref_transaction_update(transaction, refname,
- null_oid(), old_oid,
+ null_oid(the_hash_algo), old_oid,
NULL, old_target, flags,
msg, err);
}
@@ -1699,6 +1700,24 @@ struct ref_iterator *refs_ref_iterator_begin(
enum do_for_each_ref_flags flags)
{
struct ref_iterator *iter;
+ struct strvec normalized_exclude_patterns = STRVEC_INIT;
+
+ if (exclude_patterns) {
+ for (size_t i = 0; exclude_patterns[i]; i++) {
+ const char *pattern = exclude_patterns[i];
+ size_t len = strlen(pattern);
+ if (!len)
+ continue;
+
+ if (pattern[len - 1] == '/')
+ strvec_push(&normalized_exclude_patterns, pattern);
+ else
+ strvec_pushf(&normalized_exclude_patterns, "%s/",
+ pattern);
+ }
+
+ exclude_patterns = normalized_exclude_patterns.v;
+ }
if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN)) {
static int ref_paranoia = -1;
@@ -1719,6 +1738,8 @@ struct ref_iterator *refs_ref_iterator_begin(
if (trim)
iter = prefix_ref_iterator_begin(iter, "", trim);
+ strvec_clear(&normalized_exclude_patterns);
+
return iter;
}
@@ -2160,7 +2181,7 @@ struct ref_store *repo_get_submodule_ref_store(struct repository *repo,
subrepo = xmalloc(sizeof(*subrepo));
if (repo_submodule_init(subrepo, repo, submodule,
- null_oid())) {
+ null_oid(the_hash_algo))) {
free(subrepo);
goto done;
}
@@ -2345,14 +2366,14 @@ static int run_transaction_hook(struct ref_transaction *transaction,
strbuf_reset(&buf);
if (!(update->flags & REF_HAVE_OLD))
- strbuf_addf(&buf, "%s ", oid_to_hex(null_oid()));
+ strbuf_addf(&buf, "%s ", oid_to_hex(null_oid(the_hash_algo)));
else if (update->old_target)
strbuf_addf(&buf, "ref:%s ", update->old_target);
else
strbuf_addf(&buf, "%s ", oid_to_hex(&update->old_oid));
if (!(update->flags & REF_HAVE_NEW))
- strbuf_addf(&buf, "%s ", oid_to_hex(null_oid()));
+ strbuf_addf(&buf, "%s ", oid_to_hex(null_oid(the_hash_algo)));
else if (update->new_target)
strbuf_addf(&buf, "ref:%s ", update->new_target);
else
@@ -2475,19 +2496,18 @@ int ref_transaction_commit(struct ref_transaction *transaction,
return ret;
}
-int refs_verify_refname_available(struct ref_store *refs,
- const char *refname,
- const struct string_list *extras,
- const struct string_list *skip,
- unsigned int initial_transaction,
- struct strbuf *err)
+int refs_verify_refnames_available(struct ref_store *refs,
+ const struct string_list *refnames,
+ const struct string_list *extras,
+ const struct string_list *skip,
+ unsigned int initial_transaction,
+ struct strbuf *err)
{
- const char *slash;
- const char *extra_refname;
struct strbuf dirname = STRBUF_INIT;
struct strbuf referent = STRBUF_INIT;
- struct object_id oid;
- unsigned int type;
+ struct string_list_item *item;
+ struct ref_iterator *iter = NULL;
+ struct strset dirnames;
int ret = -1;
/*
@@ -2497,86 +2517,130 @@ int refs_verify_refname_available(struct ref_store *refs,
assert(err);
- strbuf_grow(&dirname, strlen(refname) + 1);
- for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) {
- /*
- * Just saying "Is a directory" when we e.g. can't
- * lock some multi-level ref isn't very informative,
- * the user won't be told *what* is a directory, so
- * let's not use strerror() below.
- */
- int ignore_errno;
- /* Expand dirname to the new prefix, not including the trailing slash: */
- strbuf_add(&dirname, refname + dirname.len, slash - refname - dirname.len);
+ strset_init(&dirnames);
+
+ for_each_string_list_item(item, refnames) {
+ const char *refname = item->string;
+ const char *extra_refname;
+ struct object_id oid;
+ unsigned int type;
+ const char *slash;
+
+ strbuf_reset(&dirname);
+
+ for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) {
+ /*
+ * Just saying "Is a directory" when we e.g. can't
+ * lock some multi-level ref isn't very informative,
+ * the user won't be told *what* is a directory, so
+ * let's not use strerror() below.
+ */
+ int ignore_errno;
+
+ /* Expand dirname to the new prefix, not including the trailing slash: */
+ strbuf_add(&dirname, refname + dirname.len, slash - refname - dirname.len);
+
+ /*
+ * We are still at a leading dir of the refname (e.g.,
+ * "refs/foo"; if there is a reference with that name,
+ * it is a conflict, *unless* it is in skip.
+ */
+ if (skip && string_list_has_string(skip, dirname.buf))
+ continue;
+
+ /*
+ * If we've already seen the directory we don't need to
+ * process it again. Skip it to avoid checking checking
+ * common prefixes like "refs/heads/" repeatedly.
+ */
+ if (!strset_add(&dirnames, dirname.buf))
+ continue;
+
+ if (!initial_transaction &&
+ !refs_read_raw_ref(refs, dirname.buf, &oid, &referent,
+ &type, &ignore_errno)) {
+ strbuf_addf(err, _("'%s' exists; cannot create '%s'"),
+ dirname.buf, refname);
+ goto cleanup;
+ }
+
+ if (extras && string_list_has_string(extras, dirname.buf)) {
+ strbuf_addf(err, _("cannot process '%s' and '%s' at the same time"),
+ refname, dirname.buf);
+ goto cleanup;
+ }
+ }
/*
- * We are still at a leading dir of the refname (e.g.,
- * "refs/foo"; if there is a reference with that name,
- * it is a conflict, *unless* it is in skip.
+ * We are at the leaf of our refname (e.g., "refs/foo/bar").
+ * There is no point in searching for a reference with that
+ * name, because a refname isn't considered to conflict with
+ * itself. But we still need to check for references whose
+ * names are in the "refs/foo/bar/" namespace, because they
+ * *do* conflict.
*/
- if (skip && string_list_has_string(skip, dirname.buf))
- continue;
+ strbuf_addstr(&dirname, refname + dirname.len);
+ strbuf_addch(&dirname, '/');
- if (!initial_transaction &&
- !refs_read_raw_ref(refs, dirname.buf, &oid, &referent,
- &type, &ignore_errno)) {
- strbuf_addf(err, _("'%s' exists; cannot create '%s'"),
- dirname.buf, refname);
- goto cleanup;
- }
+ if (!initial_transaction) {
+ int ok;
- if (extras && string_list_has_string(extras, dirname.buf)) {
- strbuf_addf(err, _("cannot process '%s' and '%s' at the same time"),
- refname, dirname.buf);
- goto cleanup;
- }
- }
+ if (!iter) {
+ iter = refs_ref_iterator_begin(refs, dirname.buf, NULL, 0,
+ DO_FOR_EACH_INCLUDE_BROKEN);
+ } else if (ref_iterator_seek(iter, dirname.buf) < 0) {
+ goto cleanup;
+ }
- /*
- * We are at the leaf of our refname (e.g., "refs/foo/bar").
- * There is no point in searching for a reference with that
- * name, because a refname isn't considered to conflict with
- * itself. But we still need to check for references whose
- * names are in the "refs/foo/bar/" namespace, because they
- * *do* conflict.
- */
- strbuf_addstr(&dirname, refname + dirname.len);
- strbuf_addch(&dirname, '/');
-
- if (!initial_transaction) {
- struct ref_iterator *iter;
- int ok;
-
- iter = refs_ref_iterator_begin(refs, dirname.buf, NULL, 0,
- DO_FOR_EACH_INCLUDE_BROKEN);
- while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
- if (skip &&
- string_list_has_string(skip, iter->refname))
- continue;
+ while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
+ if (skip &&
+ string_list_has_string(skip, iter->refname))
+ continue;
- strbuf_addf(err, _("'%s' exists; cannot create '%s'"),
- iter->refname, refname);
- ref_iterator_abort(iter);
- goto cleanup;
+ strbuf_addf(err, _("'%s' exists; cannot create '%s'"),
+ iter->refname, refname);
+ goto cleanup;
+ }
+
+ if (ok != ITER_DONE)
+ BUG("error while iterating over references");
}
- if (ok != ITER_DONE)
- BUG("error while iterating over references");
+ extra_refname = find_descendant_ref(dirname.buf, extras, skip);
+ if (extra_refname) {
+ strbuf_addf(err, _("cannot process '%s' and '%s' at the same time"),
+ refname, extra_refname);
+ goto cleanup;
+ }
}
- extra_refname = find_descendant_ref(dirname.buf, extras, skip);
- if (extra_refname)
- strbuf_addf(err, _("cannot process '%s' and '%s' at the same time"),
- refname, extra_refname);
- else
- ret = 0;
+ ret = 0;
cleanup:
strbuf_release(&referent);
strbuf_release(&dirname);
+ strset_clear(&dirnames);
+ ref_iterator_free(iter);
return ret;
}
+int refs_verify_refname_available(struct ref_store *refs,
+ const char *refname,
+ const struct string_list *extras,
+ const struct string_list *skip,
+ unsigned int initial_transaction,
+ struct strbuf *err)
+{
+ struct string_list_item item = { .string = (char *) refname };
+ struct string_list refnames = {
+ .items = &item,
+ .nr = 1,
+ };
+
+ return refs_verify_refnames_available(refs, &refnames, extras, skip,
+ initial_transaction, err);
+}
+
struct do_for_each_reflog_help {
each_reflog_fn *fn;
void *cb_data;
@@ -2794,7 +2858,7 @@ static int migrate_one_ref(const char *refname, const char *referent UNUSED, con
if (ret < 0)
goto done;
- ret = ref_transaction_update(data->transaction, refname, NULL, null_oid(),
+ ret = ref_transaction_update(data->transaction, refname, NULL, null_oid(the_hash_algo),
symref_target.buf, NULL,
REF_SKIP_CREATE_REFLOG | REF_NO_DEREF, NULL, data->errbuf);
if (ret < 0)