diff options
author | Junio C Hamano <gitster@pobox.com> | 2015-03-05 12:45:39 -0800 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2015-03-05 12:45:39 -0800 |
commit | fd9de868c359a1bbd214e354aefdb0f1eaa898bd (patch) | |
tree | 1f4f619a49a6f6171e56592bb48d2db3ae927600 /refs.c | |
parent | Post 2.3 cycle (batch #6) (diff) | |
parent | refs.h: remove duplication in function docstrings (diff) | |
download | tgif-fd9de868c359a1bbd214e354aefdb0f1eaa898bd.tar.xz |
Merge branch 'mh/refs-have-new'
Simplify the ref transaction API around how "the ref should be
pointing at this object" is specified.
* mh/refs-have-new:
refs.h: remove duplication in function docstrings
update_ref(): improve documentation
ref_transaction_verify(): new function to check a reference's value
ref_transaction_delete(): check that old_sha1 is not null_sha1
ref_transaction_create(): check that new_sha1 is valid
commit: avoid race when creating orphan commits
commit: add tests of commit races
ref_transaction_delete(): remove "have_old" parameter
ref_transaction_update(): remove "have_old" parameter
struct ref_update: move "have_old" into "flags"
refs.c: change some "flags" to "unsigned int"
refs: remove the gap in the REF_* constant values
refs: move REF_DELETING to refs.c
Diffstat (limited to 'refs.c')
-rw-r--r-- | refs.c | 140 |
1 files changed, 96 insertions, 44 deletions
@@ -35,10 +35,29 @@ static unsigned char refname_disposition[256] = { }; /* - * Used as a flag to ref_transaction_delete when a loose ref is being + * Flag passed to lock_ref_sha1_basic() telling it to tolerate broken + * refs (i.e., because the reference is about to be deleted anyway). + */ +#define REF_DELETING 0x02 + +/* + * Used as a flag in ref_update::flags when a loose ref is being * pruned. */ -#define REF_ISPRUNING 0x0100 +#define REF_ISPRUNING 0x04 + +/* + * Used as a flag in ref_update::flags when the reference should be + * updated to new_sha1. + */ +#define REF_HAVE_NEW 0x08 + +/* + * Used as a flag in ref_update::flags when old_sha1 should be + * checked. + */ +#define REF_HAVE_OLD 0x10 + /* * Try to read one refname component from the front of refname. * Return the length of the component found, or -1 if the component is @@ -2249,7 +2268,7 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log) static struct ref_lock *lock_ref_sha1_basic(const char *refname, const unsigned char *old_sha1, const struct string_list *skip, - int flags, int *type_p) + unsigned int flags, int *type_p) { char *ref_file; const char *orig_refname = refname; @@ -2563,7 +2582,7 @@ static void prune_ref(struct ref_to_prune *r) transaction = ref_transaction_begin(&err); if (!transaction || ref_transaction_delete(transaction, r->name, r->sha1, - REF_ISPRUNING, 1, NULL, &err) || + REF_ISPRUNING, NULL, &err) || ref_transaction_commit(transaction, &err)) { ref_transaction_free(transaction); error("%s", err.buf); @@ -2733,15 +2752,16 @@ static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf *err) return 0; } -int delete_ref(const char *refname, const unsigned char *sha1, int delopt) +int delete_ref(const char *refname, const unsigned char *sha1, unsigned int flags) { struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; transaction = ref_transaction_begin(&err); if (!transaction || - ref_transaction_delete(transaction, refname, sha1, delopt, - sha1 && !is_null_sha1(sha1), NULL, &err) || + ref_transaction_delete(transaction, refname, + (sha1 && !is_null_sha1(sha1)) ? sha1 : NULL, + flags, NULL, &err) || ref_transaction_commit(transaction, &err)) { error("%s", err.buf); ref_transaction_free(transaction); @@ -3556,16 +3576,27 @@ int for_each_reflog(each_ref_fn fn, void *cb_data) } /** - * Information needed for a single ref update. Set new_sha1 to the - * new value or to zero to delete the ref. To check the old value - * while locking the ref, set have_old to 1 and set old_sha1 to the - * value or to zero to ensure the ref does not exist before update. + * Information needed for a single ref update. Set new_sha1 to the new + * value or to null_sha1 to delete the ref. To check the old value + * while the ref is locked, set (flags & REF_HAVE_OLD) and set + * old_sha1 to the old value, or to null_sha1 to ensure the ref does + * not exist before update. */ struct ref_update { + /* + * If (flags & REF_HAVE_NEW), set the reference to this value: + */ unsigned char new_sha1[20]; + /* + * If (flags & REF_HAVE_OLD), check that the reference + * previously had this value: + */ unsigned char old_sha1[20]; - int flags; /* REF_NODEREF? */ - int have_old; /* 1 if old_sha1 is valid, 0 otherwise */ + /* + * One or more of REF_HAVE_NEW, REF_HAVE_OLD, REF_NODEREF, + * REF_DELETING, and REF_ISPRUNING: + */ + unsigned int flags; struct ref_lock *lock; int type; char *msg; @@ -3637,7 +3668,7 @@ int ref_transaction_update(struct ref_transaction *transaction, const char *refname, const unsigned char *new_sha1, const unsigned char *old_sha1, - int flags, int have_old, const char *msg, + unsigned int flags, const char *msg, struct strbuf *err) { struct ref_update *update; @@ -3647,10 +3678,7 @@ int ref_transaction_update(struct ref_transaction *transaction, if (transaction->state != REF_TRANSACTION_OPEN) die("BUG: update called for transaction that is not open"); - if (have_old && !old_sha1) - die("BUG: have_old is true but old_sha1 is NULL"); - - if (!is_null_sha1(new_sha1) && + if (new_sha1 && !is_null_sha1(new_sha1) && check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { strbuf_addf(err, "refusing to update ref with bad name %s", refname); @@ -3658,11 +3686,15 @@ int ref_transaction_update(struct ref_transaction *transaction, } update = add_update(transaction, refname); - hashcpy(update->new_sha1, new_sha1); - update->flags = flags; - update->have_old = have_old; - if (have_old) + if (new_sha1) { + hashcpy(update->new_sha1, new_sha1); + flags |= REF_HAVE_NEW; + } + if (old_sha1) { hashcpy(update->old_sha1, old_sha1); + flags |= REF_HAVE_OLD; + } + update->flags = flags; if (msg) update->msg = xstrdup(msg); return 0; @@ -3671,34 +3703,52 @@ int ref_transaction_update(struct ref_transaction *transaction, int ref_transaction_create(struct ref_transaction *transaction, const char *refname, const unsigned char *new_sha1, - int flags, const char *msg, + unsigned int flags, const char *msg, struct strbuf *err) { + if (!new_sha1 || is_null_sha1(new_sha1)) + die("BUG: create called without valid new_sha1"); return ref_transaction_update(transaction, refname, new_sha1, - null_sha1, flags, 1, msg, err); + null_sha1, flags, msg, err); } int ref_transaction_delete(struct ref_transaction *transaction, const char *refname, const unsigned char *old_sha1, - int flags, int have_old, const char *msg, + unsigned int flags, const char *msg, struct strbuf *err) { - return ref_transaction_update(transaction, refname, null_sha1, - old_sha1, flags, have_old, msg, err); + if (old_sha1 && is_null_sha1(old_sha1)) + die("BUG: delete called with old_sha1 set to zeros"); + return ref_transaction_update(transaction, refname, + null_sha1, old_sha1, + flags, msg, err); } -int update_ref(const char *action, const char *refname, - const unsigned char *sha1, const unsigned char *oldval, - int flags, enum action_on_err onerr) +int ref_transaction_verify(struct ref_transaction *transaction, + const char *refname, + const unsigned char *old_sha1, + unsigned int flags, + struct strbuf *err) +{ + if (!old_sha1) + die("BUG: verify called with old_sha1 set to NULL"); + return ref_transaction_update(transaction, refname, + NULL, old_sha1, + flags, NULL, err); +} + +int update_ref(const char *msg, const char *refname, + const unsigned char *new_sha1, const unsigned char *old_sha1, + unsigned int flags, enum action_on_err onerr) { struct ref_transaction *t; struct strbuf err = STRBUF_INIT; t = ref_transaction_begin(&err); if (!t || - ref_transaction_update(t, refname, sha1, oldval, flags, - !!oldval, action, &err) || + ref_transaction_update(t, refname, new_sha1, old_sha1, + flags, msg, &err) || ref_transaction_commit(t, &err)) { const char *str = "update_ref failed for ref '%s': %s"; @@ -3774,17 +3824,17 @@ int ref_transaction_commit(struct ref_transaction *transaction, /* Acquire all locks while verifying old values */ for (i = 0; i < n; i++) { struct ref_update *update = updates[i]; - int flags = update->flags; + unsigned int flags = update->flags; - if (is_null_sha1(update->new_sha1)) + if ((flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1)) flags |= REF_DELETING; - update->lock = lock_ref_sha1_basic(update->refname, - (update->have_old ? - update->old_sha1 : - NULL), - NULL, - flags, - &update->type); + update->lock = lock_ref_sha1_basic( + update->refname, + ((update->flags & REF_HAVE_OLD) ? + update->old_sha1 : NULL), + NULL, + flags, + &update->type); if (!update->lock) { ret = (errno == ENOTDIR) ? TRANSACTION_NAME_CONFLICT @@ -3798,8 +3848,9 @@ int ref_transaction_commit(struct ref_transaction *transaction, /* Perform updates first so live commits remain referenced */ for (i = 0; i < n; i++) { struct ref_update *update = updates[i]; + int flags = update->flags; - if (!is_null_sha1(update->new_sha1)) { + if ((flags & REF_HAVE_NEW) && !is_null_sha1(update->new_sha1)) { if (write_ref_sha1(update->lock, update->new_sha1, update->msg)) { update->lock = NULL; /* freed by write_ref_sha1 */ @@ -3815,14 +3866,15 @@ int ref_transaction_commit(struct ref_transaction *transaction, /* Perform deletes now that updates are safely completed */ for (i = 0; i < n; i++) { struct ref_update *update = updates[i]; + int flags = update->flags; - if (update->lock) { + if ((flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1)) { if (delete_ref_loose(update->lock, update->type, err)) { ret = TRANSACTION_GENERIC_ERROR; goto cleanup; } - if (!(update->flags & REF_ISPRUNING)) + if (!(flags & REF_ISPRUNING)) string_list_append(&refs_to_delete, update->lock->ref_name); } |