diff options
| author | Junio C Hamano <gitster@pobox.com> | 2025-08-29 09:44:37 -0700 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2025-08-29 09:44:37 -0700 |
| commit | fea9d18c534a445ef6e488d8ee711fa92fa0e6bd (patch) | |
| tree | 56fd0f9b7dc3c75e9b03bf024d5bff239977f5cc /refs/reftable-backend.c | |
| parent | 040f05e824b9683799148609ff0a77d468e97182 (diff) | |
| parent | 450fc2bace48ce7ba07a2431175923bf2d610635 (diff) | |
| download | git-fea9d18c534a445ef6e488d8ee711fa92fa0e6bd.tar.xz | |
Merge branch 'jk/no-clobber-dangling-symref-with-fetch'
"git fetch" can clobber a symref that is dangling when the
remote-tracking HEAD is set to auto update, which has been
corrected.
* jk/no-clobber-dangling-symref-with-fetch:
refs: do not clobber dangling symrefs
t5510: prefer "git -C" to subshell for followRemoteHEAD tests
t5510: stop changing top-level working directory
t5510: make confusing config cleanup more explicit
Diffstat (limited to 'refs/reftable-backend.c')
| -rw-r--r-- | refs/reftable-backend.c | 30 |
1 files changed, 27 insertions, 3 deletions
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index 5bccd0360a..9e889da2ff 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -1274,9 +1274,33 @@ static enum ref_transaction_error prepare_single_update(struct reftable_ref_stor ret = ref_update_check_old_target(referent->buf, u, err); if (ret) return ret; - } else if ((u->flags & (REF_LOG_ONLY | REF_HAVE_OLD)) == REF_HAVE_OLD && - !oideq(¤t_oid, &u->old_oid)) { - if (is_null_oid(&u->old_oid)) { + } else if ((u->flags & (REF_LOG_ONLY | REF_HAVE_OLD)) == REF_HAVE_OLD) { + if (oideq(¤t_oid, &u->old_oid)) { + /* + * Normally matching the expected old oid is enough. Either we + * found the ref at the expected state, or we are creating and + * expect the null oid (and likewise found nothing). + * + * But there is one exception for the null oid: if we found a + * symref pointing to nothing we'll also get the null oid. In + * regular recursive mode, that's good (we'll write to what the + * symref points to, which doesn't exist). But in no-deref + * mode, it means we'll clobber the symref, even though the + * caller asked for this to be a creation event. So flag + * that case to preserve the dangling symref. + * + * Everything else is OK and we can fall through to the + * end of the conditional chain. + */ + if ((u->flags & REF_NO_DEREF) && + referent->len && + is_null_oid(&u->old_oid)) { + strbuf_addf(err, _("cannot lock ref '%s': " + "dangling symref already exists"), + ref_update_original_update_refname(u)); + return REF_TRANSACTION_ERROR_CREATE_EXISTS; + } + } else if (is_null_oid(&u->old_oid)) { strbuf_addf(err, _("cannot lock ref '%s': " "reference already exists"), ref_update_original_update_refname(u)); |
