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>
Patrick Steinhardt committed
Jul 1, 2026 at 13:35 UTC
46affdb8c74759697e9afef2a55854d3641953e1
1 file changed
+62
-38
builtin/history.c
+62
-38
@@ -333,21 +333,17 @@ static int handle_ref_update(struct ref_transaction *transaction,
333
NULL, NULL, 0, reflog_msg, err);
334
}
335
336
-static int handle_reference_updates(struct rev_info *revs,
337
- enum ref_action action,
338
- struct commit *original,
339
- struct commit *rewritten,
340
- const char *reflog_msg,
341
- int dry_run,
342
- enum replay_empty_commit_action empty)
336
+static int compute_pending_ref_updates(struct rev_info *revs,
337
+ enum ref_action action,
338
+ struct commit *original,
339
+ struct commit *rewritten,
340
+ enum replay_empty_commit_action empty,
341
+ struct replay_result *result)
342
{
343
const struct name_decoration *decoration;
344
struct replay_revisions_options opts = {
345
.empty = empty,
346
};
348
- struct replay_result result = { 0 };
349
- struct ref_transaction *transaction = NULL;
350
- struct strbuf err = STRBUF_INIT;
347
char hex[GIT_MAX_HEXSZ + 1];
348
bool detached_head;
349
int head_flags = 0;
@@ -359,34 +355,13 @@ static int handle_reference_updates(struct rev_info *revs,
355
356
opts.onto = oid_to_hex_r(hex, &rewritten->object.oid);
357
362
- ret = replay_revisions(revs, &opts, &result);
358
+ ret = replay_revisions(revs, &opts, result);
359
if (ret)
364
- goto out;
360
+ return ret;
361
362
if (action != REF_ACTION_BRANCHES && action != REF_ACTION_HEAD)
363
BUG("unsupported ref action %d", action);
364
369
- if (!dry_run) {
370
- transaction = ref_store_transaction_begin(get_main_ref_store(revs->repo), 0, &err);
371
- if (!transaction) {
372
- ret = error(_("failed to begin ref transaction: %s"), err.buf);
373
- goto out;
374
- }
375
- }
376
-
377
- for (size_t i = 0; i < result.updates_nr; i++) {
378
- ret = handle_ref_update(transaction,
379
- result.updates[i].refname,
380
- &result.updates[i].new_oid,
381
- &result.updates[i].old_oid,
382
- reflog_msg, &err);
383
- if (ret) {
384
- ret = error(_("failed to update ref '%s': %s"),
385
- result.updates[i].refname, err.buf);
386
- goto out;
387
- }
388
- }
389
-
365
/*
366
* `replay_revisions()` only updates references that are
367
* ancestors of `rewritten`, so we need to manually
@@ -414,14 +389,41 @@ static int handle_reference_updates(struct rev_info *revs,
389
!detached_head)
390
continue;
391
392
+ replay_result_queue_update(result, decoration->name,
393
+ &original->object.oid,
394
+ &rewritten->object.oid);
395
+ }
396
+
397
+ return 0;
398
+}
399
+
400
+static int apply_pending_ref_updates(struct repository *repo,
401
+ const struct replay_result *result,
402
+ const char *reflog_msg,
403
+ int dry_run)
404
+{
405
+ struct ref_transaction *transaction = NULL;
406
+ struct strbuf err = STRBUF_INIT;
407
+ int ret;
408
+
409
+ if (!dry_run) {
410
+ transaction = ref_store_transaction_begin(get_main_ref_store(repo),
411
+ 0, &err);
412
+ if (!transaction) {
413
+ ret = error(_("failed to begin ref transaction: %s"), err.buf);
414
+ goto out;
415
+ }
416
+ }
417
+
418
+ for (size_t i = 0; i < result->updates_nr; i++) {
419
ret = handle_ref_update(transaction,
418
- decoration->name,
419
- &rewritten->object.oid,
420
- &original->object.oid,
420
+ result->updates[i].refname,
421
+ &result->updates[i].new_oid,
422
+ &result->updates[i].old_oid,
423
reflog_msg, &err);
424
if (ret) {
425
ret = error(_("failed to update ref '%s': %s"),
424
- decoration->name, err.buf);
426
+ result->updates[i].refname, err.buf);
427
goto out;
428
}
429
}
@@ -435,11 +437,33 @@ static int handle_reference_updates(struct rev_info *revs,
437
438
out:
439
ref_transaction_free(transaction);
438
- replay_result_release(&result);
440
strbuf_release(&err);
441
return ret;
442
}
443
444
+static int handle_reference_updates(struct rev_info *revs,
445
+ enum ref_action action,
446
+ struct commit *original,
447
+ struct commit *rewritten,
448
+ const char *reflog_msg,
449
+ int dry_run,
450
+ enum replay_empty_commit_action empty)
451
+{
452
+ struct replay_result result = { 0 };
453
+ int ret;
454
+
455
+ ret = compute_pending_ref_updates(revs, action, original, rewritten,
456
+ empty, &result);
457
+ if (ret)
458
+ goto out;
459
+
460
+ ret = apply_pending_ref_updates(revs->repo, &result, reflog_msg, dry_run);
461
+
462
+out:
463
+ replay_result_release(&result);
464
+ return ret;
465
+}
466
+
467
static int commit_became_empty(struct repository *repo,
468
struct commit *original,
469
struct tree *result)