initial_ref_transaction_commit(): check for ref D/F conflicts
In initial_ref_transaction_commit(), check for D/F conflicts (i.e., the type of conflict that exists between "refs/foo" and "refs/foo/bar") among the references being created and between the references being created and any hypothetical existing references. Ideally, there shouldn't *be* any existing references when this function is called. But, at least in the case of the "testgit" remote helper, "clone" can be called after the remote-tracking "HEAD" and "master" branches have already been created. So let's just do the full-blown check. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
fb802b3129
commit
e426ff4222
34
refs.c
34
refs.c
@ -4093,9 +4093,19 @@ cleanup:
|
|||||||
return ret;
|
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,
|
int initial_ref_transaction_commit(struct ref_transaction *transaction,
|
||||||
struct strbuf *err)
|
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 ret = 0, i;
|
||||||
int n = transaction->nr;
|
int n = transaction->nr;
|
||||||
struct ref_update **updates = transaction->updates;
|
struct ref_update **updates = transaction->updates;
|
||||||
@ -4115,12 +4125,36 @@ int initial_ref_transaction_commit(struct ref_transaction *transaction,
|
|||||||
goto cleanup;
|
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++) {
|
for (i = 0; i < n; i++) {
|
||||||
struct ref_update *update = updates[i];
|
struct ref_update *update = updates[i];
|
||||||
|
|
||||||
if ((update->flags & REF_HAVE_OLD) &&
|
if ((update->flags & REF_HAVE_OLD) &&
|
||||||
!is_null_sha1(update->old_sha1))
|
!is_null_sha1(update->old_sha1))
|
||||||
die("BUG: initial ref transaction with old_sha1 set");
|
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)) {
|
if (lock_packed_refs(0)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user