diff mbox series

[v2,09/12] clone: handle overridden main branch names

Message ID 0e59b6181699abe17eb46fe3ca5a48ce71889780.1592225416.git.gitgitgadget@gmail.com (mailing list archive)
State New, archived
Headers show
Series Allow overriding the default name of the default branch | expand

Commit Message

John Passaro via GitGitGadget June 15, 2020, 12:50 p.m. UTC
From: Johannes Schindelin <johannes.schindelin@gmx.de>

When cloning a repository without any branches, Git chooses a default
branch name for the as-yet unborn branch.

As part of the implicit initialization of the local repository, Git
just learned to respect `init.defaultBranch` to choose a different main
branch name. We now really want that branch name to be used as a
fall-back.

At the same time, we also want to make sure that `core.mainBranch` is
set correctly, reflecting the name of the main branch. In case we detect
a main branch, we do have to do that explicitly, otherwise `init_db()`
will already have done that for us.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 Documentation/config/init.txt |  4 ++--
 builtin/clone.c               | 16 +++++++++++++---
 t/t5606-clone-options.sh      | 17 +++++++++++++++++
 3 files changed, 32 insertions(+), 5 deletions(-)

Comments

Jeff King June 16, 2020, 1:22 p.m. UTC | #1
On Mon, Jun 15, 2020 at 12:50:13PM +0000, Johannes Schindelin via GitGitGadget wrote:

> diff --git a/builtin/clone.c b/builtin/clone.c
> index 487b0a42d75..755fcaeb0ba 100644
> --- a/builtin/clone.c
> +++ b/builtin/clone.c
> @@ -718,6 +718,7 @@ static void update_head(const struct ref *our, const struct ref *remote,
>  		/* Local default branch link */
>  		if (create_symref("HEAD", our->name, NULL) < 0)
>  			die(_("unable to update HEAD"));
> +		git_config_set("core.mainbranch", head);
>  		if (!option_bare) {
>  			update_ref(msg, "HEAD", &our->old_oid, NULL, 0,
>  				   UPDATE_REFS_DIE_ON_ERR);

Just making sure I understand what's going on here...

This covers the case that we've run "clone -b foo" or similar, but there
are two other case arms when "foo" is a tag, or the remote HEAD is
unreachable. And there we don't set core.mainbranch at all.

But we would not want it to be missing, because that will likely need to
stay a default for "master" indefinitely (to keep behavior for existing
repositories). However, it won't be missing. We'll always have set it
during the init_db() call, and this is just overriding that. So we'd end
update_head() with either:

  - core.mainbranch set to the same branch we point HEAD to, whether we
    got it from the remote side or from "-b foo"

  - if we write a detached HEAD, then core.mainbranch remains at
    init.mainbranch (or defaulting to "master" now, and probably "main"
    later). We have no better option.

If so, then that makes sense to me.

-Peff
Johannes Schindelin June 23, 2020, 8:58 p.m. UTC | #2
Hi Peff,

On Tue, 16 Jun 2020, Jeff King wrote:

> On Mon, Jun 15, 2020 at 12:50:13PM +0000, Johannes Schindelin via GitGitGadget wrote:
>
> > diff --git a/builtin/clone.c b/builtin/clone.c
> > index 487b0a42d75..755fcaeb0ba 100644
> > --- a/builtin/clone.c
> > +++ b/builtin/clone.c
> > @@ -718,6 +718,7 @@ static void update_head(const struct ref *our, const struct ref *remote,
> >  		/* Local default branch link */
> >  		if (create_symref("HEAD", our->name, NULL) < 0)
> >  			die(_("unable to update HEAD"));
> > +		git_config_set("core.mainbranch", head);
> >  		if (!option_bare) {
> >  			update_ref(msg, "HEAD", &our->old_oid, NULL, 0,
> >  				   UPDATE_REFS_DIE_ON_ERR);
>
> Just making sure I understand what's going on here...
>
> This covers the case that we've run "clone -b foo" or similar, but there
> are two other case arms when "foo" is a tag, or the remote HEAD is
> unreachable. And there we don't set core.mainbranch at all.

It was actually meant to catch the case where the remote repository has a
default branch other than `master`.

> But we would not want it to be missing, because that will likely need to
> stay a default for "master" indefinitely (to keep behavior for existing
> repositories). However, it won't be missing. We'll always have set it
> during the init_db() call, and this is just overriding that. So we'd end
> update_head() with either:
>
>   - core.mainbranch set to the same branch we point HEAD to, whether we
>     got it from the remote side or from "-b foo"
>
>   - if we write a detached HEAD, then core.mainbranch remains at
>     init.mainbranch (or defaulting to "master" now, and probably "main"
>     later). We have no better option.
>
> If so, then that makes sense to me.

In any case, this does not matter anymore, as I am dropping
`core.mainBranch` from v3, as you had suggested elsewhere in this thread.

Ciao,
Dscho
diff mbox series

Patch

diff --git a/Documentation/config/init.txt b/Documentation/config/init.txt
index 6ae4a38416e..dc77f8c8446 100644
--- a/Documentation/config/init.txt
+++ b/Documentation/config/init.txt
@@ -3,5 +3,5 @@  init.templateDir::
 	(See the "TEMPLATE DIRECTORY" section of linkgit:git-init[1].)
 
 init.defaultBranch::
-	Allows overriding the default branch name when initializing
-	a new repository.
+	Allows overriding the default branch name e.g. when initializing
+	a new repository or when cloning an empty repository.
diff --git a/builtin/clone.c b/builtin/clone.c
index 487b0a42d75..755fcaeb0ba 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -718,6 +718,7 @@  static void update_head(const struct ref *our, const struct ref *remote,
 		/* Local default branch link */
 		if (create_symref("HEAD", our->name, NULL) < 0)
 			die(_("unable to update HEAD"));
+		git_config_set("core.mainbranch", head);
 		if (!option_bare) {
 			update_ref(msg, "HEAD", &our->old_oid, NULL, 0,
 				   UPDATE_REFS_DIE_ON_ERR);
@@ -1264,9 +1265,18 @@  int cmd_clone(int argc, const char **argv, const char *prefix)
 		remote_head_points_at = NULL;
 		remote_head = NULL;
 		option_no_checkout = 1;
-		if (!option_bare)
-			install_branch_config(0, "master", option_origin,
-					      "refs/heads/master");
+		if (!option_bare) {
+			char *main_branch =
+				git_main_branch_name(MAIN_BRANCH_FULL_NAME);
+			const char *nick;
+
+			if (!skip_prefix(main_branch, "refs/heads/", &nick))
+				BUG("unexpected default branch '%s'",
+				    main_branch);
+			install_branch_config(0, nick, option_origin,
+					      main_branch);
+			free(main_branch);
+		}
 	}
 
 	write_refspec_config(src_ref_prefix, our_head_points_at,
diff --git a/t/t5606-clone-options.sh b/t/t5606-clone-options.sh
index 9e24ec88e67..98b2d8527f6 100755
--- a/t/t5606-clone-options.sh
+++ b/t/t5606-clone-options.sh
@@ -35,4 +35,21 @@  test_expect_success 'redirected clone -v does show progress' '
 
 '
 
+test_expect_success 'chooses correct default main branch name' '
+	git init --bare empty &&
+	git -c init.defaultBranch=up clone empty whats-up &&
+	test refs/heads/up = $(git -C whats-up symbolic-ref HEAD) &&
+	test up = $(git -C whats-up config core.mainBranch) &&
+	test refs/heads/up = $(git -C whats-up config branch.up.merge)
+'
+
+test_expect_success 'guesses main branch name correctly' '
+	git init --main-branch=guess main-branch &&
+	test_commit -C main-branch no-spoilers &&
+	git -C main-branch branch abc guess &&
+	git clone main-branch is-it &&
+	test guess = $(git -C is-it config core.mainBranch) &&
+	test refs/heads/guess = $(git -C is-it symbolic-ref HEAD)
+'
+
 test_done