mirror of
https://github.com/git/git
synced 2024-07-05 00:58:49 +00:00
refs.c: ref_transaction_commit: distinguish name conflicts from other errors
In _commit, ENOTDIR can happen in the call to lock_ref_sha1_basic, either when we lstat the new refname or if the name checking function reports that the same type of conflict happened. In both cases, it means that we can not create the new ref due to a name conflict. Start defining specific return codes for _commit. TRANSACTION_NAME_CONFLICT refers to a failure to create a ref due to a name conflict with another ref. TRANSACTION_GENERIC_ERROR is for all other errors. When "git fetch" is creating refs, name conflicts differ from other errors in that they are likely to be resolved by running "git remote prune <remote>". "git fetch" currently inspects errno to decide whether to give that advice. Once it switches to the transaction API, it can check for TRANSACTION_NAME_CONFLICT instead. Signed-off-by: Ronnie Sahlberg <sahlberg@google.com> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
5fe7d825da
commit
28e6a97e39
26
refs.c
26
refs.c
|
@ -3637,9 +3637,10 @@ int ref_transaction_commit(struct ref_transaction *transaction,
|
||||||
|
|
||||||
/* Copy, sort, and reject duplicate refs */
|
/* Copy, sort, and reject duplicate refs */
|
||||||
qsort(updates, n, sizeof(*updates), ref_update_compare);
|
qsort(updates, n, sizeof(*updates), ref_update_compare);
|
||||||
ret = ref_update_reject_duplicates(updates, n, err);
|
if (ref_update_reject_duplicates(updates, n, err)) {
|
||||||
if (ret)
|
ret = TRANSACTION_GENERIC_ERROR;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
/* Acquire all locks while verifying old values */
|
/* Acquire all locks while verifying old values */
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
|
@ -3653,10 +3654,12 @@ int ref_transaction_commit(struct ref_transaction *transaction,
|
||||||
update->flags,
|
update->flags,
|
||||||
&update->type);
|
&update->type);
|
||||||
if (!update->lock) {
|
if (!update->lock) {
|
||||||
|
ret = (errno == ENOTDIR)
|
||||||
|
? TRANSACTION_NAME_CONFLICT
|
||||||
|
: TRANSACTION_GENERIC_ERROR;
|
||||||
if (err)
|
if (err)
|
||||||
strbuf_addf(err, "Cannot lock the ref '%s'.",
|
strbuf_addf(err, "Cannot lock the ref '%s'.",
|
||||||
update->refname);
|
update->refname);
|
||||||
ret = 1;
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3666,15 +3669,16 @@ int ref_transaction_commit(struct ref_transaction *transaction,
|
||||||
struct ref_update *update = updates[i];
|
struct ref_update *update = updates[i];
|
||||||
|
|
||||||
if (!is_null_sha1(update->new_sha1)) {
|
if (!is_null_sha1(update->new_sha1)) {
|
||||||
ret = write_ref_sha1(update->lock, update->new_sha1,
|
if (write_ref_sha1(update->lock, update->new_sha1,
|
||||||
update->msg);
|
update->msg)) {
|
||||||
update->lock = NULL; /* freed by write_ref_sha1 */
|
update->lock = NULL; /* freed by write_ref_sha1 */
|
||||||
if (ret) {
|
|
||||||
if (err)
|
if (err)
|
||||||
strbuf_addf(err, "Cannot update the ref '%s'.",
|
strbuf_addf(err, "Cannot update the ref '%s'.",
|
||||||
update->refname);
|
update->refname);
|
||||||
|
ret = TRANSACTION_GENERIC_ERROR;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
update->lock = NULL; /* freed by write_ref_sha1 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3683,14 +3687,16 @@ int ref_transaction_commit(struct ref_transaction *transaction,
|
||||||
struct ref_update *update = updates[i];
|
struct ref_update *update = updates[i];
|
||||||
|
|
||||||
if (update->lock) {
|
if (update->lock) {
|
||||||
ret |= delete_ref_loose(update->lock, update->type,
|
if (delete_ref_loose(update->lock, update->type, err))
|
||||||
err);
|
ret = TRANSACTION_GENERIC_ERROR;
|
||||||
|
|
||||||
if (!(update->flags & REF_ISPRUNING))
|
if (!(update->flags & REF_ISPRUNING))
|
||||||
delnames[delnum++] = update->lock->ref_name;
|
delnames[delnum++] = update->lock->ref_name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret |= repack_without_refs(delnames, delnum, err);
|
if (repack_without_refs(delnames, delnum, err))
|
||||||
|
ret = TRANSACTION_GENERIC_ERROR;
|
||||||
for (i = 0; i < delnum; i++)
|
for (i = 0; i < delnum; i++)
|
||||||
unlink_or_warn(git_path("logs/%s", delnames[i]));
|
unlink_or_warn(git_path("logs/%s", delnames[i]));
|
||||||
clear_loose_ref_cache(&ref_cache);
|
clear_loose_ref_cache(&ref_cache);
|
||||||
|
|
9
refs.h
9
refs.h
|
@ -326,9 +326,14 @@ int ref_transaction_delete(struct ref_transaction *transaction,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Commit all of the changes that have been queued in transaction, as
|
* Commit all of the changes that have been queued in transaction, as
|
||||||
* atomically as possible. Return a nonzero value if there is a
|
* atomically as possible.
|
||||||
* problem.
|
*
|
||||||
|
* Returns 0 for success, or one of the below error codes for errors.
|
||||||
*/
|
*/
|
||||||
|
/* Naming conflict (for example, the ref names A and A/B conflict). */
|
||||||
|
#define TRANSACTION_NAME_CONFLICT -1
|
||||||
|
/* All other errors. */
|
||||||
|
#define TRANSACTION_GENERIC_ERROR -2
|
||||||
int ref_transaction_commit(struct ref_transaction *transaction,
|
int ref_transaction_commit(struct ref_transaction *transaction,
|
||||||
struct strbuf *err);
|
struct strbuf *err);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user