Skip to content

Commit 6b58df5

Browse files
peffgitster
authored andcommitted
clone: handle unborn branch in bare repos
When cloning a repository with an unborn HEAD, we'll set the local HEAD to match it only if the local repository is non-bare. This is inconsistent with all other combinations: remote HEAD | local repo | local HEAD ----------------------------------------------- points to commit | non-bare | same as remote points to commit | bare | same as remote unborn | non-bare | same as remote unborn | bare | local default So I don't think this is some clever or subtle behavior, but just a bug in 4f37d45 (clone: respect remote unborn HEAD, 2021-02-05). And it's easy to see how we ended up there. Before that commit, the code to set up the HEAD for an empty repo was guarded by "if (!option_bare)". That's because the only thing it did was call install_branch_config(), and we don't want to do so for a bare repository (unborn HEAD or not). That commit put the handling of unborn HEADs into the same block, since those also need to call install_branch_config(). But the unborn case has an additional side effect of calling create_symref(), and we want that to happen whether we are bare or not. This patch just pulls all of the "figure out the default branch" code out of the "!option_bare" block. Only the actual config installation is kept there. Note that this does mean we might allocate "ref" and not use it (if the remote is empty but did not advertise an unborn HEAD). But that's not really a big deal since this isn't a hot code path, and it keeps the code simple. The alternative would be handling unborn_head_target separately, but that gets confusing since its memory ownership is tangled up with the "ref" variable. There's just one new test, for the case we're fixing. The other ones in the table are handled elsewhere (the unborn non-bare case just above, and the actually-born cases in t5601, t5606, and t5609, as they do not require v2's "unborn" protocol extension). Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 225bc32 commit 6b58df5

File tree

2 files changed

+30
-16
lines changed

2 files changed

+30
-16
lines changed

builtin/clone.c

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,6 +1340,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
13401340
our_head_points_at = remote_head_points_at;
13411341
}
13421342
else {
1343+
const char *branch;
1344+
char *ref;
1345+
13431346
if (option_branch)
13441347
die(_("Remote branch %s not found in upstream %s"),
13451348
option_branch, remote_name);
@@ -1350,24 +1353,22 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
13501353
remote_head_points_at = NULL;
13511354
remote_head = NULL;
13521355
option_no_checkout = 1;
1353-
if (!option_bare) {
1354-
const char *branch;
1355-
char *ref;
1356-
1357-
if (transport_ls_refs_options.unborn_head_target &&
1358-
skip_prefix(transport_ls_refs_options.unborn_head_target,
1359-
"refs/heads/", &branch)) {
1360-
ref = transport_ls_refs_options.unborn_head_target;
1361-
transport_ls_refs_options.unborn_head_target = NULL;
1362-
create_symref("HEAD", ref, reflog_msg.buf);
1363-
} else {
1364-
branch = git_default_branch_name(0);
1365-
ref = xstrfmt("refs/heads/%s", branch);
1366-
}
13671356

1368-
install_branch_config(0, branch, remote_name, ref);
1369-
free(ref);
1357+
if (transport_ls_refs_options.unborn_head_target &&
1358+
skip_prefix(transport_ls_refs_options.unborn_head_target,
1359+
"refs/heads/", &branch)) {
1360+
ref = transport_ls_refs_options.unborn_head_target;
1361+
transport_ls_refs_options.unborn_head_target = NULL;
1362+
create_symref("HEAD", ref, reflog_msg.buf);
1363+
} else {
1364+
branch = git_default_branch_name(0);
1365+
ref = xstrfmt("refs/heads/%s", branch);
13701366
}
1367+
1368+
if (!option_bare)
1369+
install_branch_config(0, branch, remote_name, ref);
1370+
1371+
free(ref);
13711372
}
13721373

13731374
write_refspec_config(src_ref_prefix, our_head_points_at,

t/t5702-protocol-v2.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,19 @@ test_expect_success '...but not if explicitly forbidden by config' '
237237
! grep "refs/heads/mydefaultbranch" file_empty_child/.git/HEAD
238238
'
239239

240+
test_expect_success 'bare clone propagates empty default branch' '
241+
test_when_finished "rm -rf file_empty_parent file_empty_child.git" &&
242+
243+
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= \
244+
git -c init.defaultBranch=mydefaultbranch init file_empty_parent &&
245+
246+
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= \
247+
git -c init.defaultBranch=main -c protocol.version=2 \
248+
clone --bare \
249+
"file://$(pwd)/file_empty_parent" file_empty_child.git &&
250+
grep "refs/heads/mydefaultbranch" file_empty_child.git/HEAD
251+
'
252+
240253
test_expect_success 'fetch with file:// using protocol v2' '
241254
test_when_finished "rm -f log" &&
242255

0 commit comments

Comments
 (0)