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@xxxxxxxxxxxx> --- refs.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/refs.c b/refs.c index 8e929c7..fca3ef1 100644 --- a/refs.c +++ b/refs.c @@ -3718,25 +3718,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; @@ -3750,6 +3743,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); @@ -3761,9 +3755,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; } @@ -3879,6 +3875,7 @@ cleanup: if (updates[i]->lock) unlock_ref(updates[i]->lock); string_list_clear(&refs_to_delete, 0); + string_list_clear(&affected_refnames, 0); return ret; } -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html