Merge branch 'ps/reflog-migrate-fixes' into ps/remote-rename-fix

* ps/reflog-migrate-fixes:
  refs: fix invalid old object IDs when migrating reflogs
  refs: stop unsetting REF_HAVE_OLD for log-only updates
  refs/files: detect race when generating reflog entry for HEAD
  refs: fix identity for migrated reflogs
  ident: fix type of string length parameter
  builtin/reflog: implement subcommand to write new entries
  refs: export `ref_transaction_update_reflog()`
  builtin/reflog: improve grouping of subcommands
  Documentation/git-reflog: convert to use synopsis type
This commit is contained in:
Junio C Hamano
2025-08-06 07:41:57 -07:00
12 changed files with 446 additions and 150 deletions

60
refs.c
View File

@@ -1362,27 +1362,22 @@ int ref_transaction_update(struct ref_transaction *transaction,
return 0;
}
/*
* Similar to`ref_transaction_update`, but this function is only for adding
* a reflog update. Supports providing custom committer information. The index
* field can be utiltized to order updates as desired. When not used, the
* updates default to being ordered by refname.
*/
static int ref_transaction_update_reflog(struct ref_transaction *transaction,
const char *refname,
const struct object_id *new_oid,
const struct object_id *old_oid,
const char *committer_info,
unsigned int flags,
const char *msg,
uint64_t index,
struct strbuf *err)
int ref_transaction_update_reflog(struct ref_transaction *transaction,
const char *refname,
const struct object_id *new_oid,
const struct object_id *old_oid,
const char *committer_info,
const char *msg,
uint64_t index,
struct strbuf *err)
{
struct ref_update *update;
unsigned int flags;
assert(err);
flags |= REF_LOG_ONLY | REF_FORCE_CREATE_REFLOG | REF_NO_DEREF;
flags = REF_HAVE_OLD | REF_HAVE_NEW | REF_LOG_ONLY | REF_FORCE_CREATE_REFLOG | REF_NO_DEREF |
REF_LOG_USE_PROVIDED_OIDS;
if (!transaction_refname_valid(refname, new_oid, flags, err))
return -1;
@@ -1390,11 +1385,6 @@ static int ref_transaction_update_reflog(struct ref_transaction *transaction,
update = ref_transaction_add_update(transaction, refname, flags,
new_oid, old_oid, NULL, NULL,
committer_info, msg);
/*
* While we do set the old_oid value, we unset the flag to skip
* old_oid verification which only makes sense for refs.
*/
update->flags &= ~REF_HAVE_OLD;
update->index = index;
/*
@@ -2951,7 +2941,7 @@ struct migration_data {
struct ref_store *old_refs;
struct ref_transaction *transaction;
struct strbuf *errbuf;
struct strbuf sb;
struct strbuf sb, name, mail;
};
static int migrate_one_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
@@ -2990,7 +2980,7 @@ struct reflog_migration_data {
struct ref_store *old_refs;
struct ref_transaction *transaction;
struct strbuf *errbuf;
struct strbuf *sb;
struct strbuf *sb, *name, *mail;
};
static int migrate_one_reflog_entry(struct object_id *old_oid,
@@ -3000,18 +2990,25 @@ static int migrate_one_reflog_entry(struct object_id *old_oid,
const char *msg, void *cb_data)
{
struct reflog_migration_data *data = cb_data;
struct ident_split ident;
const char *date;
int ret;
if (split_ident_line(&ident, committer, strlen(committer)) < 0)
return -1;
strbuf_reset(data->name);
strbuf_add(data->name, ident.name_begin, ident.name_end - ident.name_begin);
strbuf_reset(data->mail);
strbuf_add(data->mail, ident.mail_begin, ident.mail_end - ident.mail_begin);
date = show_date(timestamp, tz, DATE_MODE(NORMAL));
strbuf_reset(data->sb);
/* committer contains name and email */
strbuf_addstr(data->sb, fmt_ident("", committer, WANT_BLANK_IDENT, date, 0));
strbuf_addstr(data->sb, fmt_ident(data->name->buf, data->mail->buf, WANT_BLANK_IDENT, date, 0));
ret = ref_transaction_update_reflog(data->transaction, data->refname,
new_oid, old_oid, data->sb->buf,
REF_HAVE_NEW | REF_HAVE_OLD, msg,
data->index++, data->errbuf);
msg, data->index++, data->errbuf);
return ret;
}
@@ -3024,6 +3021,8 @@ static int migrate_one_reflog(const char *refname, void *cb_data)
.transaction = migration_data->transaction,
.errbuf = migration_data->errbuf,
.sb = &migration_data->sb,
.name = &migration_data->name,
.mail = &migration_data->mail,
};
return refs_for_each_reflog_ent(migration_data->old_refs, refname,
@@ -3122,6 +3121,8 @@ int repo_migrate_ref_storage_format(struct repository *repo,
struct strbuf new_gitdir = STRBUF_INIT;
struct migration_data data = {
.sb = STRBUF_INIT,
.name = STRBUF_INIT,
.mail = STRBUF_INIT,
};
int did_migrate_refs = 0;
int ret;
@@ -3297,11 +3298,16 @@ done:
ref_transaction_free(transaction);
strbuf_release(&new_gitdir);
strbuf_release(&data.sb);
strbuf_release(&data.name);
strbuf_release(&data.mail);
return ret;
}
int ref_update_expects_existing_old_ref(struct ref_update *update)
{
if (update->flags & REF_LOG_ONLY)
return 0;
return (update->flags & REF_HAVE_OLD) &&
(!is_null_oid(&update->old_oid) || update->old_target);
}