Skip to content

Commit 69571df

Browse files
committed
Merge branch 'jt/clone-unborn-head'
"git clone" tries to locally check out the branch pointed at by HEAD of the remote repository after it is done, but the protocol did not convey the information necessary to do so when copying an empty repository. The protocol v2 learned how to do so. * jt/clone-unborn-head: clone: respect remote unborn HEAD connect, transport: encapsulate arg in struct ls-refs: report unborn targets of symrefs
2 parents 0871fb9 + 4f37d45 commit 69571df

20 files changed

+240
-63
lines changed

Documentation/config.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,8 @@ include::config/interactive.txt[]
398398

399399
include::config/log.txt[]
400400

401+
include::config/lsrefs.txt[]
402+
401403
include::config/mailinfo.txt[]
402404

403405
include::config/mailmap.txt[]

Documentation/config/init.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ init.templateDir::
44

55
init.defaultBranch::
66
Allows overriding the default branch name e.g. when initializing
7-
a new repository or when cloning an empty repository.
7+
a new repository.

Documentation/config/lsrefs.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
lsrefs.unborn::
2+
May be "advertise" (the default), "allow", or "ignore". If "advertise",
3+
the server will respond to the client sending "unborn" (as described in
4+
protocol-v2.txt) and will advertise support for this feature during the
5+
protocol v2 capability advertisement. "allow" is the same as
6+
"advertise" except that the server will not advertise support for this
7+
feature; this is useful for load-balanced servers that cannot be
8+
updated atomically (for example), since the administrator could
9+
configure "allow", then after a delay, configure "advertise".

Documentation/technical/protocol-v2.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,11 +192,20 @@ ls-refs takes in the following arguments:
192192
When specified, only references having a prefix matching one of
193193
the provided prefixes are displayed.
194194

195+
If the 'unborn' feature is advertised the following argument can be
196+
included in the client's request.
197+
198+
unborn
199+
The server will send information about HEAD even if it is a symref
200+
pointing to an unborn branch in the form "unborn HEAD
201+
symref-target:<target>".
202+
195203
The output of ls-refs is as follows:
196204

197205
output = *ref
198206
flush-pkt
199-
ref = PKT-LINE(obj-id SP refname *(SP ref-attribute) LF)
207+
obj-id-or-unborn = (obj-id | "unborn")
208+
ref = PKT-LINE(obj-id-or-unborn SP refname *(SP ref-attribute) LF)
200209
ref-attribute = (symref | peeled)
201210
symref = "symref-target:" symref-target
202211
peeled = "peeled:" obj-id

builtin/clone.c

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -979,7 +979,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
979979
int err = 0, complete_refs_before_fetch = 1;
980980
int submodule_progress;
981981

982-
struct strvec ref_prefixes = STRVEC_INIT;
982+
struct transport_ls_refs_options transport_ls_refs_options =
983+
TRANSPORT_LS_REFS_OPTIONS_INIT;
983984

984985
packet_trace_identity("clone");
985986

@@ -1257,14 +1258,17 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
12571258
transport->smart_options->check_self_contained_and_connected = 1;
12581259

12591260

1260-
strvec_push(&ref_prefixes, "HEAD");
1261-
refspec_ref_prefixes(&remote->fetch, &ref_prefixes);
1261+
strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
1262+
refspec_ref_prefixes(&remote->fetch,
1263+
&transport_ls_refs_options.ref_prefixes);
12621264
if (option_branch)
1263-
expand_ref_prefix(&ref_prefixes, option_branch);
1265+
expand_ref_prefix(&transport_ls_refs_options.ref_prefixes,
1266+
option_branch);
12641267
if (!option_no_tags)
1265-
strvec_push(&ref_prefixes, "refs/tags/");
1268+
strvec_push(&transport_ls_refs_options.ref_prefixes,
1269+
"refs/tags/");
12661270

1267-
refs = transport_get_remote_refs(transport, &ref_prefixes);
1271+
refs = transport_get_remote_refs(transport, &transport_ls_refs_options);
12681272

12691273
if (refs) {
12701274
int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
@@ -1326,8 +1330,19 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
13261330
remote_head = NULL;
13271331
option_no_checkout = 1;
13281332
if (!option_bare) {
1329-
const char *branch = git_default_branch_name(0);
1330-
char *ref = xstrfmt("refs/heads/%s", branch);
1333+
const char *branch;
1334+
char *ref;
1335+
1336+
if (transport_ls_refs_options.unborn_head_target &&
1337+
skip_prefix(transport_ls_refs_options.unborn_head_target,
1338+
"refs/heads/", &branch)) {
1339+
ref = transport_ls_refs_options.unborn_head_target;
1340+
transport_ls_refs_options.unborn_head_target = NULL;
1341+
create_symref("HEAD", ref, reflog_msg.buf);
1342+
} else {
1343+
branch = git_default_branch_name(0);
1344+
ref = xstrfmt("refs/heads/%s", branch);
1345+
}
13311346

13321347
install_branch_config(0, branch, remote_name, ref);
13331348
free(ref);
@@ -1380,6 +1395,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
13801395
strbuf_release(&key);
13811396
junk_mode = JUNK_LEAVE_ALL;
13821397

1383-
strvec_clear(&ref_prefixes);
1398+
strvec_clear(&transport_ls_refs_options.ref_prefixes);
1399+
free(transport_ls_refs_options.unborn_head_target);
13841400
return err;
13851401
}

builtin/fetch-pack.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
220220
version = discover_version(&reader);
221221
switch (version) {
222222
case protocol_v2:
223-
get_remote_refs(fd[1], &reader, &ref, 0, NULL, NULL, args.stateless_rpc);
223+
get_remote_refs(fd[1], &reader, &ref, 0, NULL, NULL,
224+
args.stateless_rpc);
224225
break;
225226
case protocol_v1:
226227
case protocol_v0:

builtin/fetch.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,7 +1455,8 @@ static int do_fetch(struct transport *transport,
14551455
int autotags = (transport->remote->fetch_tags == 1);
14561456
int retcode = 0;
14571457
const struct ref *remote_refs;
1458-
struct strvec ref_prefixes = STRVEC_INIT;
1458+
struct transport_ls_refs_options transport_ls_refs_options =
1459+
TRANSPORT_LS_REFS_OPTIONS_INIT;
14591460
int must_list_refs = 1;
14601461

14611462
if (tags == TAGS_DEFAULT) {
@@ -1475,7 +1476,7 @@ static int do_fetch(struct transport *transport,
14751476
if (rs->nr) {
14761477
int i;
14771478

1478-
refspec_ref_prefixes(rs, &ref_prefixes);
1479+
refspec_ref_prefixes(rs, &transport_ls_refs_options.ref_prefixes);
14791480

14801481
/*
14811482
* We can avoid listing refs if all of them are exact
@@ -1489,22 +1490,25 @@ static int do_fetch(struct transport *transport,
14891490
}
14901491
}
14911492
} else if (transport->remote && transport->remote->fetch.nr)
1492-
refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes);
1493+
refspec_ref_prefixes(&transport->remote->fetch,
1494+
&transport_ls_refs_options.ref_prefixes);
14931495

14941496
if (tags == TAGS_SET || tags == TAGS_DEFAULT) {
14951497
must_list_refs = 1;
1496-
if (ref_prefixes.nr)
1497-
strvec_push(&ref_prefixes, "refs/tags/");
1498+
if (transport_ls_refs_options.ref_prefixes.nr)
1499+
strvec_push(&transport_ls_refs_options.ref_prefixes,
1500+
"refs/tags/");
14981501
}
14991502

15001503
if (must_list_refs) {
15011504
trace2_region_enter("fetch", "remote_refs", the_repository);
1502-
remote_refs = transport_get_remote_refs(transport, &ref_prefixes);
1505+
remote_refs = transport_get_remote_refs(transport,
1506+
&transport_ls_refs_options);
15031507
trace2_region_leave("fetch", "remote_refs", the_repository);
15041508
} else
15051509
remote_refs = NULL;
15061510

1507-
strvec_clear(&ref_prefixes);
1511+
strvec_clear(&transport_ls_refs_options.ref_prefixes);
15081512

15091513
ref_map = get_ref_map(transport->remote, remote_refs, rs,
15101514
tags, &autotags);

builtin/ls-remote.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
4545
int show_symref_target = 0;
4646
const char *uploadpack = NULL;
4747
const char **pattern = NULL;
48-
struct strvec ref_prefixes = STRVEC_INIT;
48+
struct transport_ls_refs_options transport_options =
49+
TRANSPORT_LS_REFS_OPTIONS_INIT;
4950
int i;
5051
struct string_list server_options = STRING_LIST_INIT_DUP;
5152

@@ -94,9 +95,9 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
9495
}
9596

9697
if (flags & REF_TAGS)
97-
strvec_push(&ref_prefixes, "refs/tags/");
98+
strvec_push(&transport_options.ref_prefixes, "refs/tags/");
9899
if (flags & REF_HEADS)
99-
strvec_push(&ref_prefixes, "refs/heads/");
100+
strvec_push(&transport_options.ref_prefixes, "refs/heads/");
100101

101102
remote = remote_get(dest);
102103
if (!remote) {
@@ -118,7 +119,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
118119
if (server_options.nr)
119120
transport->server_options = &server_options;
120121

121-
ref = transport_get_remote_refs(transport, &ref_prefixes);
122+
ref = transport_get_remote_refs(transport, &transport_options);
122123
if (ref) {
123124
int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
124125
repo_set_hash_algo(the_repository, hash_algo);

connect.c

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,8 @@ struct ref **get_remote_heads(struct packet_reader *reader,
376376
}
377377

378378
/* Returns 1 when a valid ref has been added to `list`, 0 otherwise */
379-
static int process_ref_v2(struct packet_reader *reader, struct ref ***list)
379+
static int process_ref_v2(struct packet_reader *reader, struct ref ***list,
380+
char **unborn_head_target)
380381
{
381382
int ret = 1;
382383
int i = 0;
@@ -397,6 +398,25 @@ static int process_ref_v2(struct packet_reader *reader, struct ref ***list)
397398
goto out;
398399
}
399400

401+
if (!strcmp("unborn", line_sections.items[i].string)) {
402+
i++;
403+
if (unborn_head_target &&
404+
!strcmp("HEAD", line_sections.items[i++].string)) {
405+
/*
406+
* Look for the symref target (if any). If found,
407+
* return it to the caller.
408+
*/
409+
for (; i < line_sections.nr; i++) {
410+
const char *arg = line_sections.items[i].string;
411+
412+
if (skip_prefix(arg, "symref-target:", &arg)) {
413+
*unborn_head_target = xstrdup(arg);
414+
break;
415+
}
416+
}
417+
}
418+
goto out;
419+
}
400420
if (parse_oid_hex_algop(line_sections.items[i++].string, &old_oid, &end, reader->hash_algo) ||
401421
*end) {
402422
ret = 0;
@@ -453,12 +473,16 @@ void check_stateless_delimiter(int stateless_rpc,
453473

454474
struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
455475
struct ref **list, int for_push,
456-
const struct strvec *ref_prefixes,
476+
struct transport_ls_refs_options *transport_options,
457477
const struct string_list *server_options,
458478
int stateless_rpc)
459479
{
460480
int i;
461481
const char *hash_name;
482+
struct strvec *ref_prefixes = transport_options ?
483+
&transport_options->ref_prefixes : NULL;
484+
char **unborn_head_target = transport_options ?
485+
&transport_options->unborn_head_target : NULL;
462486
*list = NULL;
463487

464488
if (server_supports_v2("ls-refs", 1))
@@ -488,6 +512,8 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
488512
if (!for_push)
489513
packet_write_fmt(fd_out, "peel\n");
490514
packet_write_fmt(fd_out, "symrefs\n");
515+
if (server_supports_feature("ls-refs", "unborn", 0))
516+
packet_write_fmt(fd_out, "unborn\n");
491517
for (i = 0; ref_prefixes && i < ref_prefixes->nr; i++) {
492518
packet_write_fmt(fd_out, "ref-prefix %s\n",
493519
ref_prefixes->v[i]);
@@ -496,7 +522,7 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
496522

497523
/* Process response from server */
498524
while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
499-
if (!process_ref_v2(reader, &list))
525+
if (!process_ref_v2(reader, &list, unborn_head_target))
500526
die(_("invalid ls-refs response: %s"), reader->line);
501527
}
502528

0 commit comments

Comments
 (0)