Skip to content

Commit 3436340

Browse files
committed
Merge branch 'ps/fetch-atomic' into ps/fetch-mirror-optim
* ps/fetch-atomic: fetch: make `--atomic` flag cover pruning of refs fetch: make `--atomic` flag cover backfilling of tags refs: add interface to iterate over queued transactional updates fetch: report errors when backfilling tags fails fetch: control lifecycle of FETCH_HEAD in a single place fetch: backfill tags before setting upstream fetch: increase test coverage of fetches
2 parents e6ebfd0 + 583bc41 commit 3436340

File tree

5 files changed

+262
-61
lines changed

5 files changed

+262
-61
lines changed

builtin/fetch.c

Lines changed: 129 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,19 @@ static void clear_item(struct refname_hash_entry *item)
349349
item->ignore = 1;
350350
}
351351

352+
353+
static void add_already_queued_tags(const char *refname,
354+
const struct object_id *old_oid,
355+
const struct object_id *new_oid,
356+
void *cb_data)
357+
{
358+
struct hashmap *queued_tags = cb_data;
359+
if (starts_with(refname, "refs/tags/") && new_oid)
360+
(void) refname_hash_add(queued_tags, refname, new_oid);
361+
}
362+
352363
static void find_non_local_tags(const struct ref *refs,
364+
struct ref_transaction *transaction,
353365
struct ref **head,
354366
struct ref ***tail)
355367
{
@@ -367,6 +379,16 @@ static void find_non_local_tags(const struct ref *refs,
367379
create_fetch_oidset(head, &fetch_oids);
368380

369381
for_each_ref(add_one_refname, &existing_refs);
382+
383+
/*
384+
* If we already have a transaction, then we need to filter out all
385+
* tags which have already been queued up.
386+
*/
387+
if (transaction)
388+
ref_transaction_for_each_queued_update(transaction,
389+
add_already_queued_tags,
390+
&existing_refs);
391+
370392
for (ref = refs; ref; ref = ref->next) {
371393
if (!starts_with(ref->name, "refs/tags/"))
372394
continue;
@@ -600,7 +622,7 @@ static struct ref *get_ref_map(struct remote *remote,
600622
/* also fetch all tags */
601623
get_fetch_map(remote_refs, tag_refspec, &tail, 0);
602624
else if (tags == TAGS_DEFAULT && *autotags)
603-
find_non_local_tags(remote_refs, &ref_map, &tail);
625+
find_non_local_tags(remote_refs, NULL, &ref_map, &tail);
604626

605627
/* Now append any refs to be updated opportunistically: */
606628
*tail = orefs;
@@ -1083,23 +1105,18 @@ N_("it took %.2f seconds to check forced updates; you can use\n"
10831105
"to avoid this check\n");
10841106

10851107
static int store_updated_refs(const char *raw_url, const char *remote_name,
1086-
int connectivity_checked, struct ref *ref_map,
1087-
struct worktree **worktrees)
1108+
int connectivity_checked,
1109+
struct ref_transaction *transaction, struct ref *ref_map,
1110+
struct fetch_head *fetch_head, struct worktree **worktrees)
10881111
{
1089-
struct fetch_head fetch_head;
10901112
int url_len, i, rc = 0;
10911113
struct strbuf note = STRBUF_INIT, err = STRBUF_INIT;
1092-
struct ref_transaction *transaction = NULL;
10931114
const char *what, *kind;
10941115
struct ref *rm;
10951116
char *url;
10961117
int want_status;
10971118
int summary_width = transport_summary_width(ref_map);
10981119

1099-
rc = open_fetch_head(&fetch_head);
1100-
if (rc)
1101-
return -1;
1102-
11031120
if (raw_url)
11041121
url = transport_anonymize_url(raw_url);
11051122
else
@@ -1115,14 +1132,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
11151132
}
11161133
}
11171134

1118-
if (atomic_fetch) {
1119-
transaction = ref_transaction_begin(&err);
1120-
if (!transaction) {
1121-
error("%s", err.buf);
1122-
goto abort;
1123-
}
1124-
}
1125-
11261135
prepare_format_display(ref_map);
11271136

11281137
/*
@@ -1206,7 +1215,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
12061215
strbuf_addf(&note, "'%s' of ", what);
12071216
}
12081217

1209-
append_fetch_head(&fetch_head, &rm->old_oid,
1218+
append_fetch_head(fetch_head, &rm->old_oid,
12101219
rm->fetch_head_status,
12111220
note.buf, url, url_len);
12121221

@@ -1238,17 +1247,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
12381247
}
12391248
}
12401249

1241-
if (!rc && transaction) {
1242-
rc = ref_transaction_commit(transaction, &err);
1243-
if (rc) {
1244-
error("%s", err.buf);
1245-
goto abort;
1246-
}
1247-
}
1248-
1249-
if (!rc)
1250-
commit_fetch_head(&fetch_head);
1251-
12521250
if (rc & STORE_REF_ERROR_DF_CONFLICT)
12531251
error(_("some local refs could not be updated; try running\n"
12541252
" 'git remote prune %s' to remove any old, conflicting "
@@ -1266,9 +1264,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
12661264
abort:
12671265
strbuf_release(&note);
12681266
strbuf_release(&err);
1269-
ref_transaction_free(transaction);
12701267
free(url);
1271-
close_fetch_head(&fetch_head);
12721268
return rc;
12731269
}
12741270

@@ -1308,7 +1304,9 @@ static int check_exist_and_connected(struct ref *ref_map)
13081304
}
13091305

13101306
static int fetch_and_consume_refs(struct transport *transport,
1307+
struct ref_transaction *transaction,
13111308
struct ref *ref_map,
1309+
struct fetch_head *fetch_head,
13121310
struct worktree **worktrees)
13131311
{
13141312
int connectivity_checked = 1;
@@ -1331,19 +1329,23 @@ static int fetch_and_consume_refs(struct transport *transport,
13311329

13321330
trace2_region_enter("fetch", "consume_refs", the_repository);
13331331
ret = store_updated_refs(transport->url, transport->remote->name,
1334-
connectivity_checked, ref_map, worktrees);
1332+
connectivity_checked, transaction, ref_map,
1333+
fetch_head, worktrees);
13351334
trace2_region_leave("fetch", "consume_refs", the_repository);
13361335

13371336
out:
13381337
transport_unlock_pack(transport, 0);
13391338
return ret;
13401339
}
13411340

1342-
static int prune_refs(struct refspec *rs, struct ref *ref_map,
1341+
static int prune_refs(struct refspec *rs,
1342+
struct ref_transaction *transaction,
1343+
struct ref *ref_map,
13431344
const char *raw_url)
13441345
{
13451346
int url_len, i, result = 0;
13461347
struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map);
1348+
struct strbuf err = STRBUF_INIT;
13471349
char *url;
13481350
int summary_width = transport_summary_width(stale_refs);
13491351
const char *dangling_msg = dry_run
@@ -1364,13 +1366,22 @@ static int prune_refs(struct refspec *rs, struct ref *ref_map,
13641366
url_len = i - 3;
13651367

13661368
if (!dry_run) {
1367-
struct string_list refnames = STRING_LIST_INIT_NODUP;
1369+
if (transaction) {
1370+
for (ref = stale_refs; ref; ref = ref->next) {
1371+
result = ref_transaction_delete(transaction, ref->name, NULL, 0,
1372+
"fetch: prune", &err);
1373+
if (result)
1374+
goto cleanup;
1375+
}
1376+
} else {
1377+
struct string_list refnames = STRING_LIST_INIT_NODUP;
13681378

1369-
for (ref = stale_refs; ref; ref = ref->next)
1370-
string_list_append(&refnames, ref->name);
1379+
for (ref = stale_refs; ref; ref = ref->next)
1380+
string_list_append(&refnames, ref->name);
13711381

1372-
result = delete_refs("fetch: prune", &refnames, 0);
1373-
string_list_clear(&refnames, 0);
1382+
result = delete_refs("fetch: prune", &refnames, 0);
1383+
string_list_clear(&refnames, 0);
1384+
}
13741385
}
13751386

13761387
if (verbosity >= 0) {
@@ -1389,6 +1400,8 @@ static int prune_refs(struct refspec *rs, struct ref *ref_map,
13891400
}
13901401
}
13911402

1403+
cleanup:
1404+
strbuf_release(&err);
13921405
free(url);
13931406
free_refs(stale_refs);
13941407
return result;
@@ -1503,10 +1516,13 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
15031516
return transport;
15041517
}
15051518

1506-
static void backfill_tags(struct transport *transport, struct ref *ref_map,
1507-
struct worktree **worktrees)
1519+
static int backfill_tags(struct transport *transport,
1520+
struct ref_transaction *transaction,
1521+
struct ref *ref_map,
1522+
struct fetch_head *fetch_head,
1523+
struct worktree **worktrees)
15081524
{
1509-
int cannot_reuse;
1525+
int retcode, cannot_reuse;
15101526

15111527
/*
15121528
* Once we have set TRANS_OPT_DEEPEN_SINCE, we can't unset it
@@ -1525,25 +1541,30 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map,
15251541
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
15261542
transport_set_option(transport, TRANS_OPT_DEPTH, "0");
15271543
transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);
1528-
fetch_and_consume_refs(transport, ref_map, worktrees);
1544+
retcode = fetch_and_consume_refs(transport, transaction, ref_map, fetch_head, worktrees);
15291545

15301546
if (gsecondary) {
15311547
transport_disconnect(gsecondary);
15321548
gsecondary = NULL;
15331549
}
1550+
1551+
return retcode;
15341552
}
15351553

15361554
static int do_fetch(struct transport *transport,
15371555
struct refspec *rs)
15381556
{
1539-
struct ref *ref_map;
1557+
struct ref_transaction *transaction = NULL;
1558+
struct ref *ref_map = NULL;
15401559
int autotags = (transport->remote->fetch_tags == 1);
15411560
int retcode = 0;
15421561
const struct ref *remote_refs;
15431562
struct transport_ls_refs_options transport_ls_refs_options =
15441563
TRANSPORT_LS_REFS_OPTIONS_INIT;
15451564
int must_list_refs = 1;
15461565
struct worktree **worktrees = get_worktrees();
1566+
struct fetch_head fetch_head = { 0 };
1567+
struct strbuf err = STRBUF_INIT;
15471568

15481569
if (tags == TAGS_DEFAULT) {
15491570
if (transport->remote->fetch_tags == 2)
@@ -1601,6 +1622,18 @@ static int do_fetch(struct transport *transport,
16011622
if (!update_head_ok)
16021623
check_not_current_branch(ref_map, worktrees);
16031624

1625+
retcode = open_fetch_head(&fetch_head);
1626+
if (retcode)
1627+
goto cleanup;
1628+
1629+
if (atomic_fetch) {
1630+
transaction = ref_transaction_begin(&err);
1631+
if (!transaction) {
1632+
retcode = error("%s", err.buf);
1633+
goto cleanup;
1634+
}
1635+
}
1636+
16041637
if (tags == TAGS_DEFAULT && autotags)
16051638
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
16061639
if (prune) {
@@ -1610,21 +1643,61 @@ static int do_fetch(struct transport *transport,
16101643
* don't care whether --tags was specified.
16111644
*/
16121645
if (rs->nr) {
1613-
retcode = prune_refs(rs, ref_map, transport->url);
1646+
retcode = prune_refs(rs, transaction, ref_map, transport->url);
16141647
} else {
16151648
retcode = prune_refs(&transport->remote->fetch,
1616-
ref_map,
1649+
transaction, ref_map,
16171650
transport->url);
16181651
}
16191652
if (retcode != 0)
16201653
retcode = 1;
16211654
}
1622-
if (fetch_and_consume_refs(transport, ref_map, worktrees)) {
1623-
free_refs(ref_map);
1655+
1656+
if (fetch_and_consume_refs(transport, transaction, ref_map, &fetch_head, worktrees)) {
16241657
retcode = 1;
16251658
goto cleanup;
16261659
}
16271660

1661+
/*
1662+
* If neither --no-tags nor --tags was specified, do automated tag
1663+
* following.
1664+
*/
1665+
if (tags == TAGS_DEFAULT && autotags) {
1666+
struct ref *tags_ref_map = NULL, **tail = &tags_ref_map;
1667+
1668+
find_non_local_tags(remote_refs, transaction, &tags_ref_map, &tail);
1669+
if (tags_ref_map) {
1670+
/*
1671+
* If backfilling of tags fails then we want to tell
1672+
* the user so, but we have to continue regardless to
1673+
* populate upstream information of the references we
1674+
* have already fetched above. The exception though is
1675+
* when `--atomic` is passed: in that case we'll abort
1676+
* the transaction and don't commit anything.
1677+
*/
1678+
if (backfill_tags(transport, transaction, tags_ref_map,
1679+
&fetch_head, worktrees))
1680+
retcode = 1;
1681+
}
1682+
1683+
free_refs(tags_ref_map);
1684+
}
1685+
1686+
if (transaction) {
1687+
if (retcode)
1688+
goto cleanup;
1689+
1690+
retcode = ref_transaction_commit(transaction, &err);
1691+
if (retcode) {
1692+
error("%s", err.buf);
1693+
ref_transaction_free(transaction);
1694+
transaction = NULL;
1695+
goto cleanup;
1696+
}
1697+
}
1698+
1699+
commit_fetch_head(&fetch_head);
1700+
16281701
if (set_upstream) {
16291702
struct branch *branch = branch_get("HEAD");
16301703
struct ref *rm;
@@ -1644,7 +1717,7 @@ static int do_fetch(struct transport *transport,
16441717
if (!rm->peer_ref) {
16451718
if (source_ref) {
16461719
warning(_("multiple branches detected, incompatible with --set-upstream"));
1647-
goto skip;
1720+
goto cleanup;
16481721
} else {
16491722
source_ref = rm;
16501723
}
@@ -1658,7 +1731,7 @@ static int do_fetch(struct transport *transport,
16581731
warning(_("could not set upstream of HEAD to '%s' from '%s' when "
16591732
"it does not point to any branch."),
16601733
shortname, transport->remote->name);
1661-
goto skip;
1734+
goto cleanup;
16621735
}
16631736

16641737
if (!strcmp(source_ref->name, "HEAD") ||
@@ -1678,21 +1751,16 @@ static int do_fetch(struct transport *transport,
16781751
"you need to specify exactly one branch with the --set-upstream option"));
16791752
}
16801753
}
1681-
skip:
1682-
free_refs(ref_map);
16831754

1684-
/* if neither --no-tags nor --tags was specified, do automated tag
1685-
* following ... */
1686-
if (tags == TAGS_DEFAULT && autotags) {
1687-
struct ref **tail = &ref_map;
1688-
ref_map = NULL;
1689-
find_non_local_tags(remote_refs, &ref_map, &tail);
1690-
if (ref_map)
1691-
backfill_tags(transport, ref_map, worktrees);
1692-
free_refs(ref_map);
1755+
cleanup:
1756+
if (retcode && transaction) {
1757+
ref_transaction_abort(transaction, &err);
1758+
error("%s", err.buf);
16931759
}
16941760

1695-
cleanup:
1761+
close_fetch_head(&fetch_head);
1762+
strbuf_release(&err);
1763+
free_refs(ref_map);
16961764
free_worktrees(worktrees);
16971765
return retcode;
16981766
}

0 commit comments

Comments
 (0)