builtin/history: split handling of ref updates into two phases

The function `handle_reference_updates()` is used by git-history(1) to
update all references that refer to commits that have been rewritten. As
such, it performs two steps:

  - It gathers the references that need to be updated in the first
    place.

  - It prepares and commits the reference transaction.

In a subsequent commit we'll want to handle those two steps separately.
Prepare for this by splitting up the function into two.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Patrick Steinhardt
2026-06-11 15:27:12 +02:00
committed by Junio C Hamano
parent 033db05809
commit fa07f7efbd

View File

@@ -333,21 +333,17 @@ static int handle_ref_update(struct ref_transaction *transaction,
NULL, NULL, 0, reflog_msg, err);
}
static int handle_reference_updates(struct rev_info *revs,
enum ref_action action,
struct commit *original,
struct commit *rewritten,
const char *reflog_msg,
int dry_run,
enum replay_empty_commit_action empty)
static int compute_pending_ref_updates(struct rev_info *revs,
enum ref_action action,
struct commit *original,
struct commit *rewritten,
enum replay_empty_commit_action empty,
struct replay_result *result)
{
const struct name_decoration *decoration;
struct replay_revisions_options opts = {
.empty = empty,
};
struct replay_result result = { 0 };
struct ref_transaction *transaction = NULL;
struct strbuf err = STRBUF_INIT;
char hex[GIT_MAX_HEXSZ + 1];
bool detached_head;
int head_flags = 0;
@@ -359,34 +355,13 @@ static int handle_reference_updates(struct rev_info *revs,
opts.onto = oid_to_hex_r(hex, &rewritten->object.oid);
ret = replay_revisions(revs, &opts, &result);
ret = replay_revisions(revs, &opts, result);
if (ret)
goto out;
return ret;
if (action != REF_ACTION_BRANCHES && action != REF_ACTION_HEAD)
BUG("unsupported ref action %d", action);
if (!dry_run) {
transaction = ref_store_transaction_begin(get_main_ref_store(revs->repo), 0, &err);
if (!transaction) {
ret = error(_("failed to begin ref transaction: %s"), err.buf);
goto out;
}
}
for (size_t i = 0; i < result.updates_nr; i++) {
ret = handle_ref_update(transaction,
result.updates[i].refname,
&result.updates[i].new_oid,
&result.updates[i].old_oid,
reflog_msg, &err);
if (ret) {
ret = error(_("failed to update ref '%s': %s"),
result.updates[i].refname, err.buf);
goto out;
}
}
/*
* `replay_revisions()` only updates references that are
* ancestors of `rewritten`, so we need to manually
@@ -414,14 +389,43 @@ static int handle_reference_updates(struct rev_info *revs,
!detached_head)
continue;
ALLOC_GROW(result->updates, result->updates_nr + 1, result->updates_alloc);
result->updates[result->updates_nr].refname = xstrdup(decoration->name);
result->updates[result->updates_nr].old_oid = original->object.oid;
result->updates[result->updates_nr].new_oid = rewritten->object.oid;
result->updates_nr++;
}
return 0;
}
static int apply_pending_ref_updates(struct repository *repo,
const struct replay_result *result,
const char *reflog_msg,
int dry_run)
{
struct ref_transaction *transaction = NULL;
struct strbuf err = STRBUF_INIT;
int ret;
if (!dry_run) {
transaction = ref_store_transaction_begin(get_main_ref_store(repo),
0, &err);
if (!transaction) {
ret = error(_("failed to begin ref transaction: %s"), err.buf);
goto out;
}
}
for (size_t i = 0; i < result->updates_nr; i++) {
ret = handle_ref_update(transaction,
decoration->name,
&rewritten->object.oid,
&original->object.oid,
result->updates[i].refname,
&result->updates[i].new_oid,
&result->updates[i].old_oid,
reflog_msg, &err);
if (ret) {
ret = error(_("failed to update ref '%s': %s"),
decoration->name, err.buf);
result->updates[i].refname, err.buf);
goto out;
}
}
@@ -435,11 +439,33 @@ static int handle_reference_updates(struct rev_info *revs,
out:
ref_transaction_free(transaction);
replay_result_release(&result);
strbuf_release(&err);
return ret;
}
static int handle_reference_updates(struct rev_info *revs,
enum ref_action action,
struct commit *original,
struct commit *rewritten,
const char *reflog_msg,
int dry_run,
enum replay_empty_commit_action empty)
{
struct replay_result result = { 0 };
int ret;
ret = compute_pending_ref_updates(revs, action, original, rewritten,
empty, &result);
if (ret)
goto out;
ret = apply_pending_ref_updates(revs->repo, &result, reflog_msg, dry_run);
out:
replay_result_release(&result);
return ret;
}
static int commit_became_empty(struct repository *repo,
struct commit *original,
struct tree *result)