diff options
author | Ronnie Sahlberg <sahlberg@google.com> | 2014-05-01 11:16:07 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2014-06-12 13:44:01 -0700 |
commit | 6e7ea2db94b2993405c6f034522131822547ec6a (patch) | |
tree | 1067870bb379cd37a206974e7307aaca22f02b8c | |
parent | 18b9f02f3cd05cb5d15978ff6df23f526574b53f (diff) | |
download | git-6e7ea2db94b2993405c6f034522131822547ec6a.tar.gz |
refs.c: pass a skip list to name_conflict_fn
Allow passing a list of refs to skip checking to name_conflict_fn.
There are some conditions where we want to allow a temporary conflict and skip
checking those refs. For example if we have a transaction that
1, guarantees that m is a packed refs and there is no loose ref for m
2, the transaction will delete m from the packed ref
3, the transaction will create conflicting m/m
For this case we want to be able to lock and create m/m since we know that the
conflict is only transient. I.e. the conflict will be automatically resolved
by the transaction when it deletes m.
Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
-rw-r--r-- | refs.c | 41 |
1 files changed, 26 insertions, 15 deletions
@@ -796,15 +796,18 @@ static int names_conflict(const char *refname1, const char *refname2) struct name_conflict_cb { const char *refname; - const char *oldrefname; const char *conflicting_refname; + const char **skip; + int skipnum; }; static int name_conflict_fn(struct ref_entry *entry, void *cb_data) { struct name_conflict_cb *data = (struct name_conflict_cb *)cb_data; - if (data->oldrefname && !strcmp(data->oldrefname, entry->name)) - return 0; + int i; + for (i = 0; i < data->skipnum; i++) + if (!strcmp(entry->name, data->skip[i])) + return 0; if (names_conflict(data->refname, entry->name)) { data->conflicting_refname = entry->name; return 1; @@ -817,15 +820,18 @@ static int name_conflict_fn(struct ref_entry *entry, void *cb_data) * conflicting with the name of an existing reference in dir. If * oldrefname is non-NULL, ignore potential conflicts with oldrefname * (e.g., because oldrefname is scheduled for deletion in the same - * operation). + * operation). skip contains a list of refs we want to skip checking for + * conflicts with. */ -static int is_refname_available(const char *refname, const char *oldrefname, - struct ref_dir *dir) +static int is_refname_available(const char *refname, + struct ref_dir *dir, + const char **skip, int skipnum) { struct name_conflict_cb data; data.refname = refname; - data.oldrefname = oldrefname; data.conflicting_refname = NULL; + data.skip = skip; + data.skipnum = skipnum; sort_ref_dir(dir); if (do_for_each_entry_in_dir(dir, 0, name_conflict_fn, &data)) { @@ -2073,7 +2079,8 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log) /* This function should make sure errno is meaningful on error */ static struct ref_lock *lock_ref_sha1_basic(const char *refname, const unsigned char *old_sha1, - int flags, int *type_p) + int flags, int *type_p, + const char **skip, int skipnum) { char *ref_file; const char *orig_refname = refname; @@ -2122,7 +2129,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname, * name is a proper prefix of our refname. */ if (missing && - !is_refname_available(refname, NULL, get_packed_refs(&ref_cache))) { + !is_refname_available(refname, get_packed_refs(&ref_cache), + skip, skipnum)) { last_errno = ENOTDIR; goto error_return; } @@ -2180,7 +2188,7 @@ struct ref_lock *lock_any_ref_for_update(const char *refname, const unsigned char *old_sha1, int flags, int *type_p) { - return lock_ref_sha1_basic(refname, old_sha1, flags, type_p); + return lock_ref_sha1_basic(refname, old_sha1, flags, type_p, NULL, 0); } /* @@ -2678,10 +2686,12 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms if (!symref) return error("refname %s not found", oldrefname); - if (!is_refname_available(newrefname, oldrefname, get_packed_refs(&ref_cache))) + if (!is_refname_available(newrefname, get_packed_refs(&ref_cache), + &oldrefname, 1)) return 1; - if (!is_refname_available(newrefname, oldrefname, get_loose_refs(&ref_cache))) + if (!is_refname_available(newrefname, get_loose_refs(&ref_cache), + &oldrefname, 1)) return 1; if (log && rename(git_path("logs/%s", oldrefname), git_path(TMP_RENAMED_LOG))) @@ -2711,7 +2721,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms logmoved = log; - lock = lock_ref_sha1_basic(newrefname, NULL, 0, NULL); + lock = lock_ref_sha1_basic(newrefname, NULL, 0, NULL, NULL, 0); if (!lock) { error("unable to lock %s for update", newrefname); goto rollback; @@ -2726,7 +2736,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms return 0; rollback: - lock = lock_ref_sha1_basic(oldrefname, NULL, 0, NULL); + lock = lock_ref_sha1_basic(oldrefname, NULL, 0, NULL, NULL, 0); if (!lock) { error("unable to lock %s for rollback", oldrefname); goto rollbacklog; @@ -3602,7 +3612,8 @@ int ref_transaction_commit(struct ref_transaction *transaction, update->old_sha1 : NULL), update->flags, - &update->type); + &update->type, + delnames, delnum); if (!update->lock) { if (err) strbuf_addf(err, "Cannot lock the ref '%s'.", |