Skip to content

Commit 7d1656f

Browse files
committed
Merge branch 'kn/reflog-migration' into seen
"git refs migrate" learned to also migrate the reflog data across backends. * kn/reflog-migration: SQUASH refs: add support for migrating reflogs refs: allow multiple reflog entries for the same refname refs: introduce the `ref_transaction_update_reflog` function refs: extract out refname verification in transactions refs/files: add count field to ref_lock refs: add `index` field to `struct ref_udpate` refs: include committer info in `ref_update` struct
2 parents f6c57b8 + 4961b86 commit 7d1656f

File tree

7 files changed

+370
-146
lines changed

7 files changed

+370
-146
lines changed

Documentation/git-refs.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ KNOWN LIMITATIONS
5757

5858
The ref format migration has several known limitations in its current form:
5959

60-
* It is not possible to migrate repositories that have reflogs.
61-
6260
* It is not possible to migrate repositories that have worktrees.
6361

6462
* There is no way to block concurrent writes to the repository during an

refs.c

Lines changed: 148 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "date.h"
3232
#include "commit.h"
3333
#include "wildmatch.h"
34+
#include "ident.h"
3435

3536
/*
3637
* List of all available backends
@@ -1199,6 +1200,7 @@ void ref_transaction_free(struct ref_transaction *transaction)
11991200

12001201
for (i = 0; i < transaction->nr; i++) {
12011202
free(transaction->updates[i]->msg);
1203+
free(transaction->updates[i]->committer_info);
12021204
free((char *)transaction->updates[i]->new_target);
12031205
free((char *)transaction->updates[i]->old_target);
12041206
free(transaction->updates[i]);
@@ -1207,13 +1209,15 @@ void ref_transaction_free(struct ref_transaction *transaction)
12071209
free(transaction);
12081210
}
12091211

1210-
struct ref_update *ref_transaction_add_update(
1211-
struct ref_transaction *transaction,
1212-
const char *refname, unsigned int flags,
1213-
const struct object_id *new_oid,
1214-
const struct object_id *old_oid,
1215-
const char *new_target, const char *old_target,
1216-
const char *msg)
1212+
struct ref_update *ref_transaction_add_update(struct ref_transaction *transaction,
1213+
const char *refname,
1214+
unsigned int flags,
1215+
const struct object_id *new_oid,
1216+
const struct object_id *old_oid,
1217+
const char *new_target,
1218+
const char *old_target,
1219+
const char *committer_info,
1220+
const char *msg)
12171221
{
12181222
struct ref_update *update;
12191223

@@ -1237,12 +1241,51 @@ struct ref_update *ref_transaction_add_update(
12371241
oidcpy(&update->new_oid, new_oid);
12381242
if ((flags & REF_HAVE_OLD) && old_oid)
12391243
oidcpy(&update->old_oid, old_oid);
1240-
if (!(flags & REF_SKIP_CREATE_REFLOG))
1244+
if (!(flags & REF_SKIP_CREATE_REFLOG)) {
1245+
if (committer_info) {
1246+
struct strbuf sb = STRBUF_INIT;
1247+
strbuf_addstr(&sb, committer_info);
1248+
update->committer_info = strbuf_detach(&sb, NULL);
1249+
}
1250+
12411251
update->msg = normalize_reflog_message(msg);
1252+
}
12421253

12431254
return update;
12441255
}
12451256

1257+
static int transaction_refname_verification(const char *refname,
1258+
const struct object_id *new_oid,
1259+
unsigned int flags,
1260+
unsigned int reflog,
1261+
struct strbuf *err)
1262+
{
1263+
if (flags & REF_SKIP_REFNAME_VERIFICATION)
1264+
return 0;
1265+
1266+
if (is_pseudo_ref(refname)) {
1267+
if (reflog)
1268+
strbuf_addf(err, _("refusing to update reflog for pseudoref '%s'"),
1269+
refname);
1270+
else
1271+
strbuf_addf(err, _("refusing to update pseudoref '%s'"),
1272+
refname);
1273+
return -1;
1274+
} else if ((new_oid && !is_null_oid(new_oid)) ?
1275+
check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :
1276+
!refname_is_safe(refname)) {
1277+
if (reflog)
1278+
strbuf_addf(err, _("refusing to update reflog with bad name '%s'"),
1279+
refname);
1280+
else
1281+
strbuf_addf(err, _("refusing to update ref with bad name '%s'"),
1282+
refname);
1283+
return -1;
1284+
}
1285+
1286+
return 0;
1287+
}
1288+
12461289
int ref_transaction_update(struct ref_transaction *transaction,
12471290
const char *refname,
12481291
const struct object_id *new_oid,
@@ -1252,6 +1295,8 @@ int ref_transaction_update(struct ref_transaction *transaction,
12521295
unsigned int flags, const char *msg,
12531296
struct strbuf *err)
12541297
{
1298+
int ret;
1299+
12551300
assert(err);
12561301

12571302
if ((flags & REF_FORCE_CREATE_REFLOG) &&
@@ -1260,21 +1305,9 @@ int ref_transaction_update(struct ref_transaction *transaction,
12601305
return -1;
12611306
}
12621307

1263-
if (!(flags & REF_SKIP_REFNAME_VERIFICATION) &&
1264-
((new_oid && !is_null_oid(new_oid)) ?
1265-
check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :
1266-
!refname_is_safe(refname))) {
1267-
strbuf_addf(err, _("refusing to update ref with bad name '%s'"),
1268-
refname);
1269-
return -1;
1270-
}
1271-
1272-
if (!(flags & REF_SKIP_REFNAME_VERIFICATION) &&
1273-
is_pseudo_ref(refname)) {
1274-
strbuf_addf(err, _("refusing to update pseudoref '%s'"),
1275-
refname);
1276-
return -1;
1277-
}
1308+
ret = transaction_refname_verification(refname, new_oid, flags, 0, err);
1309+
if (ret)
1310+
return ret;
12781311

12791312
if (flags & ~REF_TRANSACTION_UPDATE_ALLOWED_FLAGS)
12801313
BUG("illegal flags 0x%x passed to ref_transaction_update()", flags);
@@ -1289,18 +1322,47 @@ int ref_transaction_update(struct ref_transaction *transaction,
12891322
flags |= (new_oid ? REF_HAVE_NEW : 0) | (old_oid ? REF_HAVE_OLD : 0);
12901323
flags |= (new_target ? REF_HAVE_NEW : 0) | (old_target ? REF_HAVE_OLD : 0);
12911324

1292-
ref_transaction_add_update(transaction, refname, flags,
1293-
new_oid, old_oid, new_target,
1294-
old_target, msg);
1325+
ref_transaction_add_update(transaction, refname, flags, new_oid,
1326+
old_oid, new_target, old_target, NULL, msg);
1327+
return 0;
1328+
}
1329+
1330+
int ref_transaction_update_reflog(struct ref_transaction *transaction,
1331+
const char *refname,
1332+
const struct object_id *new_oid,
1333+
const struct object_id *old_oid,
1334+
const char *committer_info, unsigned int flags,
1335+
const char *msg, unsigned int index,
1336+
struct strbuf *err)
1337+
{
1338+
struct ref_update *update;
1339+
int ret;
1340+
1341+
assert(err);
1342+
1343+
ret = transaction_refname_verification(refname, new_oid, flags, 1, err);
1344+
if (ret)
1345+
return ret;
1346+
1347+
flags |= REF_LOG_ONLY | REF_NO_DEREF;
1348+
1349+
update = ref_transaction_add_update(transaction, refname, flags,
1350+
new_oid, old_oid, NULL, NULL,
1351+
committer_info, msg);
1352+
/*
1353+
* While we do set the old_oid value, we unset the flag to skip
1354+
* old_oid verification which only makes sense for refs.
1355+
*/
1356+
update->flags &= ~REF_HAVE_OLD;
1357+
update->index = index;
1358+
12951359
return 0;
12961360
}
12971361

12981362
int ref_transaction_create(struct ref_transaction *transaction,
1299-
const char *refname,
1300-
const struct object_id *new_oid,
1301-
const char *new_target,
1302-
unsigned int flags, const char *msg,
1303-
struct strbuf *err)
1363+
const char *refname, const struct object_id *new_oid,
1364+
const char *new_target, unsigned int flags,
1365+
const char *msg, struct strbuf *err)
13041366
{
13051367
if (new_oid && new_target)
13061368
BUG("create called with both new_oid and new_target set");
@@ -2708,6 +2770,7 @@ int ref_update_check_old_target(const char *referent, struct ref_update *update,
27082770
}
27092771

27102772
struct migration_data {
2773+
unsigned int index;
27112774
struct ref_store *old_refs;
27122775
struct ref_transaction *transaction;
27132776
struct strbuf *errbuf;
@@ -2743,6 +2806,53 @@ static int migrate_one_ref(const char *refname, const char *referent UNUSED, con
27432806
return ret;
27442807
}
27452808

2809+
struct reflog_migration_data {
2810+
unsigned int *index;
2811+
const char *refname;
2812+
struct ref_store *old_refs;
2813+
struct ref_transaction *transaction;
2814+
struct strbuf *errbuf;
2815+
};
2816+
2817+
static int migrate_one_reflog_entry(struct object_id *old_oid,
2818+
struct object_id *new_oid,
2819+
const char *committer,
2820+
timestamp_t timestamp, int tz,
2821+
const char *msg, void *cb_data)
2822+
{
2823+
struct reflog_migration_data *data = cb_data;
2824+
struct strbuf sb = STRBUF_INIT;
2825+
const char *date;
2826+
int ret;
2827+
2828+
date = show_date(timestamp, tz, DATE_MODE(NORMAL));
2829+
/* committer contains name and email */
2830+
strbuf_addstr(&sb, fmt_ident("", committer, WANT_BLANK_IDENT, date, 0));
2831+
2832+
ret = ref_transaction_update_reflog(data->transaction, data->refname,
2833+
new_oid, old_oid, sb.buf,
2834+
REF_HAVE_NEW | REF_HAVE_OLD, msg,
2835+
(*data->index)++, data->errbuf);
2836+
strbuf_release(&sb);
2837+
2838+
return ret;
2839+
}
2840+
2841+
static int migrate_one_reflog(const char *refname, void *cb_data)
2842+
{
2843+
struct migration_data *migration_data = cb_data;
2844+
struct reflog_migration_data data;
2845+
2846+
data.refname = refname;
2847+
data.old_refs = migration_data->old_refs;
2848+
data.transaction = migration_data->transaction;
2849+
data.errbuf = migration_data->errbuf;
2850+
data.index = &migration_data->index;
2851+
2852+
return refs_for_each_reflog_ent(migration_data->old_refs, refname,
2853+
migrate_one_reflog_entry, &data);
2854+
}
2855+
27462856
static int move_files(const char *from_path, const char *to_path, struct strbuf *errbuf)
27472857
{
27482858
struct strbuf from_buf = STRBUF_INIT, to_buf = STRBUF_INIT;
@@ -2809,13 +2919,6 @@ static int move_files(const char *from_path, const char *to_path, struct strbuf
28092919
return ret;
28102920
}
28112921

2812-
static int count_reflogs(const char *reflog UNUSED, void *payload)
2813-
{
2814-
size_t *reflog_count = payload;
2815-
(*reflog_count)++;
2816-
return 0;
2817-
}
2818-
28192922
static int has_worktrees(void)
28202923
{
28212924
struct worktree **worktrees = get_worktrees();
@@ -2841,7 +2944,6 @@ int repo_migrate_ref_storage_format(struct repository *repo,
28412944
struct ref_transaction *transaction = NULL;
28422945
struct strbuf new_gitdir = STRBUF_INIT;
28432946
struct migration_data data;
2844-
size_t reflog_count = 0;
28452947
int did_migrate_refs = 0;
28462948
int ret;
28472949

@@ -2853,21 +2955,6 @@ int repo_migrate_ref_storage_format(struct repository *repo,
28532955

28542956
old_refs = get_main_ref_store(repo);
28552957

2856-
/*
2857-
* We do not have any interfaces that would allow us to write many
2858-
* reflog entries. Once we have them we can remove this restriction.
2859-
*/
2860-
if (refs_for_each_reflog(old_refs, count_reflogs, &reflog_count) < 0) {
2861-
strbuf_addstr(errbuf, "cannot count reflogs");
2862-
ret = -1;
2863-
goto done;
2864-
}
2865-
if (reflog_count) {
2866-
strbuf_addstr(errbuf, "migrating reflogs is not supported yet");
2867-
ret = -1;
2868-
goto done;
2869-
}
2870-
28712958
/*
28722959
* Worktrees complicate the migration because every worktree has a
28732960
* separate ref storage. While it should be feasible to implement, this
@@ -2889,8 +2976,8 @@ int repo_migrate_ref_storage_format(struct repository *repo,
28892976
* 1. Set up a new temporary directory and initialize it with the new
28902977
* format. This is where all refs will be migrated into.
28912978
*
2892-
* 2. Enumerate all refs and write them into the new ref storage.
2893-
* This operation is safe as we do not yet modify the main
2979+
* 2. Enumerate all refs and reflogs and write them into the new ref
2980+
* storage. This operation is safe as we do not yet modify the main
28942981
* repository.
28952982
*
28962983
* 3. If we're in dry-run mode then we are done and can hand over the
@@ -2945,6 +3032,11 @@ int repo_migrate_ref_storage_format(struct repository *repo,
29453032
if (ret < 0)
29463033
goto done;
29473034

3035+
data.index = 1;
3036+
ret = refs_for_each_reflog(old_refs, migrate_one_reflog, &data);
3037+
if (ret < 0)
3038+
goto done;
3039+
29483040
ret = ref_transaction_commit(transaction, errbuf);
29493041
if (ret < 0)
29503042
goto done;

refs.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,18 @@ int ref_transaction_update(struct ref_transaction *transaction,
771771
unsigned int flags, const char *msg,
772772
struct strbuf *err);
773773

774+
/*
775+
* Similar to `ref_transaction_update`, but this function is only for adding
776+
* a reflog updates. Supports providing custom committer information.
777+
*/
778+
int ref_transaction_update_reflog(struct ref_transaction *transaction,
779+
const char *refname,
780+
const struct object_id *new_oid,
781+
const struct object_id *old_oid,
782+
const char *committer_info, unsigned int flags,
783+
const char *msg, unsigned int index,
784+
struct strbuf *err);
785+
774786
/*
775787
* Add a reference creation to transaction. new_oid is the value that
776788
* the reference should have after the update; it must not be

0 commit comments

Comments
 (0)