@@ -4,4 +4,4 @@ init.templateDir::
init.defaultBranch::
Allows overriding the default branch name e.g. when initializing
- a new repository or when cloning an empty repository.
+ a new repository.
@@ -1330,8 +1330,19 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
remote_head = NULL;
option_no_checkout = 1;
if (!option_bare) {
- const char *branch = git_default_branch_name();
- char *ref = xstrfmt("refs/heads/%s", branch);
+ const char *branch;
+ char *ref;
+
+ if (transport_ls_refs_options.unborn_head_target &&
+ skip_prefix(transport_ls_refs_options.unborn_head_target,
+ "refs/heads/", &branch)) {
+ ref = transport_ls_refs_options.unborn_head_target;
+ transport_ls_refs_options.unborn_head_target = NULL;
+ create_symref("HEAD", ref, reflog_msg.buf);
+ } else {
+ branch = git_default_branch_name();
+ ref = xstrfmt("refs/heads/%s", branch);
+ }
install_branch_config(0, branch, remote_name, ref);
free(ref);
@@ -1385,5 +1396,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
junk_mode = JUNK_LEAVE_ALL;
strvec_clear(&transport_ls_refs_options.ref_prefixes);
+ free(transport_ls_refs_options.unborn_head_target);
return err;
}
@@ -376,7 +376,8 @@ struct ref **get_remote_heads(struct packet_reader *reader,
}
/* Returns 1 when a valid ref has been added to `list`, 0 otherwise */
-static int process_ref_v2(struct packet_reader *reader, struct ref ***list)
+static int process_ref_v2(struct packet_reader *reader, struct ref ***list,
+ char **unborn_head_target)
{
int ret = 1;
int i = 0;
@@ -397,6 +398,25 @@ static int process_ref_v2(struct packet_reader *reader, struct ref ***list)
goto out;
}
+ if (!strcmp("unborn", line_sections.items[i].string)) {
+ i++;
+ if (unborn_head_target &&
+ !strcmp("HEAD", line_sections.items[i++].string)) {
+ /*
+ * Look for the symref target (if any). If found,
+ * return it to the caller.
+ */
+ for (; i < line_sections.nr; i++) {
+ const char *arg = line_sections.items[i].string;
+
+ if (skip_prefix(arg, "symref-target:", &arg)) {
+ *unborn_head_target = xstrdup(arg);
+ break;
+ }
+ }
+ }
+ goto out;
+ }
if (parse_oid_hex_algop(line_sections.items[i++].string, &old_oid, &end, reader->hash_algo) ||
*end) {
ret = 0;
@@ -461,6 +481,8 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
const char *hash_name;
struct strvec *ref_prefixes = transport_options ?
&transport_options->ref_prefixes : NULL;
+ char **unborn_head_target = transport_options ?
+ &transport_options->unborn_head_target : NULL;
*list = NULL;
if (server_supports_v2("ls-refs", 1))
@@ -490,6 +512,8 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
if (!for_push)
packet_write_fmt(fd_out, "peel\n");
packet_write_fmt(fd_out, "symrefs\n");
+ if (server_supports_feature("ls-refs", "unborn", 0))
+ packet_write_fmt(fd_out, "unborn\n");
for (i = 0; ref_prefixes && i < ref_prefixes->nr; i++) {
packet_write_fmt(fd_out, "ref-prefix %s\n",
ref_prefixes->v[i]);
@@ -498,7 +522,7 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
/* Process response from server */
while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
- if (!process_ref_v2(reader, &list))
+ if (!process_ref_v2(reader, &list, unborn_head_target))
die(_("invalid ls-refs response: %s"), reader->line);
}
@@ -102,11 +102,13 @@ test_expect_success 'redirected clone -v does show progress' '
'
test_expect_success 'chooses correct default initial branch name' '
- git init --bare empty &&
+ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= \
+ git -c init.defaultBranch=foo init --bare empty &&
+ test_config -C empty lsrefs.unborn advertise &&
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= \
git -c init.defaultBranch=up clone empty whats-up &&
- test refs/heads/up = $(git -C whats-up symbolic-ref HEAD) &&
- test refs/heads/up = $(git -C whats-up config branch.up.merge)
+ test refs/heads/foo = $(git -C whats-up symbolic-ref HEAD) &&
+ test refs/heads/foo = $(git -C whats-up config branch.foo.merge)
'
test_expect_success 'guesses initial branch name correctly' '
@@ -209,6 +209,31 @@ test_expect_success 'clone with file:// using protocol v2' '
grep "ref-prefix refs/tags/" log
'
+test_expect_success 'clone of empty repo propagates name of default branch' '
+ test_when_finished "rm -rf file_empty_parent file_empty_child" &&
+
+ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= \
+ git -c init.defaultBranch=mydefaultbranch init file_empty_parent &&
+
+ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= \
+ git -c init.defaultBranch=main -c protocol.version=2 \
+ clone "file://$(pwd)/file_empty_parent" file_empty_child &&
+ grep "refs/heads/mydefaultbranch" file_empty_child/.git/HEAD
+'
+
+test_expect_success '...but not if explicitly forbidden by config' '
+ test_when_finished "rm -rf file_empty_parent file_empty_child" &&
+
+ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= \
+ git -c init.defaultBranch=mydefaultbranch init file_empty_parent &&
+ test_config -C file_empty_parent lsrefs.unborn ignore &&
+
+ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= \
+ git -c init.defaultBranch=main -c protocol.version=2 \
+ clone "file://$(pwd)/file_empty_parent" file_empty_child &&
+ ! grep "refs/heads/mydefaultbranch" file_empty_child/.git/HEAD
+'
+
test_expect_success 'fetch with file:// using protocol v2' '
test_when_finished "rm -f log" &&
@@ -243,6 +243,14 @@ struct transport_ls_refs_options {
* provided ref_prefixes.
*/
struct strvec ref_prefixes;
+
+ /*
+ * If unborn_head_target is not NULL, and the remote reports HEAD as
+ * pointing to an unborn branch, transport_get_remote_refs() stores the
+ * unborn branch in unborn_head_target. It should be freed by the
+ * caller.
+ */
+ char *unborn_head_target;
};
#define TRANSPORT_LS_REFS_OPTIONS_INIT { STRVEC_INIT }