summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--refs.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/refs.c b/refs.c
index 388ac3e..1e762fb 100644
--- a/refs.c
+++ b/refs.c
@@ -4093,9 +4093,19 @@ cleanup:
return ret;
}
+static int ref_present(const char *refname,
+ const struct object_id *oid, int flags, void *cb_data)
+{
+ struct string_list *affected_refnames = cb_data;
+
+ return string_list_has_string(affected_refnames, refname);
+}
+
int initial_ref_transaction_commit(struct ref_transaction *transaction,
struct strbuf *err)
{
+ struct ref_dir *loose_refs = get_loose_refs(&ref_cache);
+ struct ref_dir *packed_refs = get_packed_refs(&ref_cache);
int ret = 0, i;
int n = transaction->nr;
struct ref_update **updates = transaction->updates;
@@ -4115,12 +4125,36 @@ int initial_ref_transaction_commit(struct ref_transaction *transaction,
goto cleanup;
}
+ /*
+ * It's really undefined to call this function in an active
+ * repository or when there are existing references: we are
+ * only locking and changing packed-refs, so (1) any
+ * simultaneous processes might try to change a reference at
+ * the same time we do, and (2) any existing loose versions of
+ * the references that we are setting would have precedence
+ * over our values. But some remote helpers create the remote
+ * "HEAD" and "master" branches before calling this function,
+ * so here we really only check that none of the references
+ * that we are creating already exists.
+ */
+ if (for_each_rawref(ref_present, &affected_refnames))
+ die("BUG: initial ref transaction called with existing refs");
+
for (i = 0; i < n; i++) {
struct ref_update *update = updates[i];
if ((update->flags & REF_HAVE_OLD) &&
!is_null_sha1(update->old_sha1))
die("BUG: initial ref transaction with old_sha1 set");
+ if (verify_refname_available(update->refname,
+ &affected_refnames, NULL,
+ loose_refs, err) ||
+ verify_refname_available(update->refname,
+ &affected_refnames, NULL,
+ packed_refs, err)) {
+ ret = TRANSACTION_NAME_CONFLICT;
+ goto cleanup;
+ }
}
if (lock_packed_refs(0)) {