1
0
mirror of https://github.com/git/git synced 2024-07-04 16:48:40 +00:00

ref_transaction_commit(): use a string_list for detecting duplicates

Detect duplicates by storing the reference names in a string_list and
sorting that, instead of sorting the ref_updates directly.

* In a moment the string_list will be used for another purpose, too.

* This removes the need for the custom comparison function
  ref_update_compare().

* This means that we can carry out the updates in the order that the
  user specified them instead of reordering them. This might be handy
  someday if, we want to permit multiple updates to a single reference
  as long as they are compatible with each other.

Note: we can't use string_list_remove_duplicates() to check for
duplicates, because we need to know the name of the reference that
appeared multiple times, to be used in the error message.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
This commit is contained in:
Michael Haggerty 2015-05-11 17:25:11 +02:00 committed by Junio C Hamano
parent 61da596992
commit 07f9c881d6

25
refs.c
View File

@ -3720,25 +3720,18 @@ int update_ref(const char *msg, const char *refname,
return 0;
}
static int ref_update_compare(const void *r1, const void *r2)
{
const struct ref_update * const *u1 = r1;
const struct ref_update * const *u2 = r2;
return strcmp((*u1)->refname, (*u2)->refname);
}
static int ref_update_reject_duplicates(struct ref_update **updates, int n,
static int ref_update_reject_duplicates(struct string_list *refnames,
struct strbuf *err)
{
int i;
int i, n = refnames->nr;
assert(err);
for (i = 1; i < n; i++)
if (!strcmp(updates[i - 1]->refname, updates[i]->refname)) {
if (!strcmp(refnames->items[i - 1].string, refnames->items[i].string)) {
strbuf_addf(err,
"Multiple updates for ref '%s' not allowed.",
updates[i]->refname);
refnames->items[i].string);
return 1;
}
return 0;
@ -3752,6 +3745,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,
struct ref_update **updates = transaction->updates;
struct string_list refs_to_delete = STRING_LIST_INIT_NODUP;
struct string_list_item *ref_to_delete;
struct string_list affected_refnames = STRING_LIST_INIT_NODUP;
assert(err);
@ -3763,9 +3757,11 @@ int ref_transaction_commit(struct ref_transaction *transaction,
return 0;
}
/* Copy, sort, and reject duplicate refs */
qsort(updates, n, sizeof(*updates), ref_update_compare);
if (ref_update_reject_duplicates(updates, n, err)) {
/* Fail if a refname appears more than once in the transaction: */
for (i = 0; i < n; i++)
string_list_append(&affected_refnames, updates[i]->refname);
string_list_sort(&affected_refnames);
if (ref_update_reject_duplicates(&affected_refnames, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
@ -3857,6 +3853,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,
if (updates[i]->lock)
unlock_ref(updates[i]->lock);
string_list_clear(&refs_to_delete, 0);
string_list_clear(&affected_refnames, 0);
return ret;
}