Skip to contentSkip to conversation

Add helpful advice about init.defaultBranch

PATCH Superseded Johannes Schindelin via GitGitGadget 6 participants 57 messages Nov 22, 2020 – Feb 3, 2021 Documentation

lore
Share & tools
lore
#0 lore raw

cover Add helpful advice about init.defaultBranch

It is our designated intention
[https://sfconservancy.org/news/2020/jun/23/gitbranchname/] to "to explore changing the name of the first branch created automatically for new repositories away from ‘master’". Further, we promised that we "will minimize disruption for Git's users and will include appropriate deprecation periods".

To that end, introduce a message giving advice to users running git init that the fall-back for init.defaultBranch is subject to change, and how to configure it.

The beauty of this patch series, if I may say so, is that it does not commit us to any concrete plan, but opens the door for all options regarding the default branch name.

Johannes Schindelin (3):
init: document init.defaultBranch better get_default_branch_name(): prepare for showing some advice
init: provide useful advice about init.defaultBranch

 Documentation/git-init.txt    | 11 +++++++----
 builtin/clone.c               |  2 +-
 builtin/init-db.c             |  8 +++++---
 refs.c                        | 19 +++++++++++++++----
 refs.h                        |  4 ++--
 remote.c                      |  5 +++--
 t/t0001-init.sh               |  9 ++++++++-
 t/t1510-repo-setup.sh         |  2 +-
 t/t7414-submodule-mistakes.sh |  2 +-
 t/test-lib-functions.sh       |  3 ++-
 10 files changed, 45 insertions(+), 20 deletions(-)

base-commit: faefdd61ec7c7f6f3c8c9907891465ac9a2a1475
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-921%2Fdscho%2Finit.defaultBranch-advice-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-921/dscho/init.defaultBranch-advice-v1
Pull-Request: https://github.com/git/git/pull/921

Signature · 1 line
gitgitgadget
#1 lore raw

PATCH 1/3 init: document `init.defaultBranch` better

From: Johannes Schindelin <[email protected]>

Our documentation does not mention any future plan to change 'master' to other value. It is a good idea to document this, though.

---
 Documentation/git-init.txt | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
Documentation/git-init.txt +7 -4
index 59ecda6c17..19f9f16e6b 100644
@@ -20,8 +20,9 @@ DESCRIPTION
 
 This command creates an empty Git repository - basically a `.git`
 directory with subdirectories for `objects`, `refs/heads`,
-`refs/tags`, and template files.  An initial `HEAD` file that
-references the HEAD of the master branch is also created.
+`refs/tags`, and template files.  An initial branch without any
+commits will be created (see the `--initial-branch` option below
+for its name).
 
 If the `$GIT_DIR` environment variable is set then it specifies a path
 to use instead of `./.git` for the base of the repository.
@@ -73,8 +74,10 @@ If this is reinitialization, the repository will be moved to the specified path.
 -b <branch-name>::
 --initial-branch=<branch-name>::
 
-Use the specified name for the initial branch in the newly created repository.
-If not specified, fall back to the default name: `master`.
+Use the specified name for the initial branch in the newly created
+repository.  If not specified, fall back to the default name (currently
+`master`, but that will be changed in the future; The name can be customized
+via the `init.defaultBranch` configuration variable).
 
 --shared[=(false|true|umask|group|all|world|everybody|0xxx)]::
 
Signature · 1 line
gitgitgadget
#4 lore raw

PATCH 2/3 get_default_branch_name(): prepare for showing some advice

In reply to Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

We are about to introduce a message giving users running git init some advice about init.defaultBranch. This will necessarily be done in repo_default_branch_name().

Not all code paths want to show that advice, though. In particular, the git clone codepath _specifically_ asks for init_db() to be quiet, via the INIT_DB_QUIET flag.

In preparation for showing users above-mentioned advice, let's change the function signature of get_default_branch_name() to accept the parameter quiet.

---
 builtin/clone.c   | 2 +-
 builtin/init-db.c | 8 +++++---
 refs.c            | 6 +++---
 refs.h            | 4 ++--
 remote.c          | 5 +++--
 5 files changed, 14 insertions(+), 11 deletions(-)
builtin/clone.c +1 -1
index a0841923cf..64b1784011 100644
@@ -1323,7 +1323,7 @@ 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();
+			const char *branch = git_default_branch_name(0);
 			char *ref = xstrfmt("refs/heads/%s", branch);
 
 			install_branch_config(0, branch, remote_name, ref);
builtin/init-db.c +5 -3
index 01bc648d41..dcc45bef51 100644
@@ -202,7 +202,8 @@ void initialize_repository_version(int hash_algo, int reinit)
 static int create_default_files(const char *template_path,
 				const char *original_git_dir,
 				const char *initial_branch,
-				const struct repository_format *fmt)
+				const struct repository_format *fmt,
+				int quiet)
 {
 	struct stat st1;
 	struct strbuf buf = STRBUF_INIT;
@@ -267,7 +268,7 @@ static int create_default_files(const char *template_path,
 		char *ref;
 
 		if (!initial_branch)
-			initial_branch = git_default_branch_name();
+			initial_branch = git_default_branch_name(quiet);
 
 		ref = xstrfmt("refs/heads/%s", initial_branch);
 		if (check_refname_format(ref, 0) < 0)
@@ -438,7 +439,8 @@ int init_db(const char *git_dir, const char *real_git_dir,
 	validate_hash_algorithm(&repo_fmt, hash);
 
 	reinit = create_default_files(template_dir, original_git_dir,
-				      initial_branch, &repo_fmt);
+				      initial_branch, &repo_fmt,
+				      flags & INIT_DB_QUIET);
 	if (reinit && initial_branch)
 		warning(_("re-init: ignored --initial-branch=%s"),
 			initial_branch);
refs.c +3 -3
index 392f0bbf68..8df03122d6 100644
@@ -562,7 +562,7 @@ void expand_ref_prefix(struct strvec *prefixes, const char *prefix)
 		strvec_pushf(prefixes, *p, len, prefix);
 }
 
-char *repo_default_branch_name(struct repository *r)
+char *repo_default_branch_name(struct repository *r, int quiet)
 {
 	const char *config_key = "init.defaultbranch";
 	const char *config_display_key = "init.defaultBranch";
@@ -585,12 +585,12 @@ char *repo_default_branch_name(struct repository *r)
 	return ret;
 }
 
-const char *git_default_branch_name(void)
+const char *git_default_branch_name(int quiet)
 {
 	static char *ret;
 
 	if (!ret)
-		ret = repo_default_branch_name(the_repository);
+		ret = repo_default_branch_name(the_repository, quiet);
 
 	return ret;
 }
refs.h +2 -2
index 6695518156..ff05d2e9fe 100644
@@ -170,8 +170,8 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **ref);
  * The return value of `repo_default_branch_name()` is an allocated string. The
  * return value of `git_default_branch_name()` is a singleton.
  */
-const char *git_default_branch_name(void);
-char *repo_default_branch_name(struct repository *r);
+const char *git_default_branch_name(int quiet);
+char *repo_default_branch_name(struct repository *r, int quiet);
 
 /*
  * A ref_transaction represents a collection of reference updates that
remote.c +3 -2
index 8a6dbbb903..bdb88d4b7d 100644
@@ -284,7 +284,7 @@ static void read_branches_file(struct remote *remote)
 	if (frag)
 		*(frag++) = '\0';
 	else
-		frag = (char *)git_default_branch_name();
+		frag = (char *)git_default_branch_name(0);
 
 	add_url_alias(remote, strbuf_detach(&buf, NULL));
 	refspec_appendf(&remote->fetch, "refs/heads/%s:refs/heads/%s",
@@ -2206,7 +2206,8 @@ struct ref *guess_remote_head(const struct ref *head,
 
 	/* If a remote branch exists with the default branch name, let's use it. */
 	if (!all) {
-		char *ref = xstrfmt("refs/heads/%s", git_default_branch_name());
+		char *ref = xstrfmt("refs/heads/%s",
+				    git_default_branch_name(0));
 
 		r = find_ref_by_name(refs, ref);
 		free(ref);
Signature · 1 line
gitgitgadget
#5 lore raw

PATCH 3/3 init: provide useful advice about init.defaultBranch

In reply to Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

To give ample warning in case we decide to change the fall-back for an unconfigured init.defaultBranch, let's introduce some advice that is shown upon git init when that value is not set.

Note: three test cases in Git's test suite want to verify that the stderr output of git init is empty. With this patch, that is only true if init.defaultBranch is configured, so let's do exactly that in those test cases. The same reasoning applies to test_create_repo().

---
 refs.c                        | 13 ++++++++++++-
 t/t0001-init.sh               |  9 ++++++++-
 t/t1510-repo-setup.sh         |  2 +-
 t/t7414-submodule-mistakes.sh |  2 +-
 t/test-lib-functions.sh       |  3 ++-
 5 files changed, 24 insertions(+), 5 deletions(-)
refs.c +12 -1
index 8df03122d6..61d712ca05 100644
@@ -562,6 +562,14 @@ void expand_ref_prefix(struct strvec *prefixes, const char *prefix)
 		strvec_pushf(prefixes, *p, len, prefix);
 }
 
+static const char default_branch_name_advice[] = N_(
+"Using '%s' as the name for the initial branch. This name is subject\n"
+"to change. To configure the name to use as the initial branch name in\n"
+"new repositories, or to silence this warning, run:\n"
+"\n"
+"\tgit config --global init.defaultBranch <name>\n"
+);
+
 char *repo_default_branch_name(struct repository *r, int quiet)
 {
 	const char *config_key = "init.defaultbranch";
@@ -574,8 +582,11 @@ char *repo_default_branch_name(struct repository *r, int quiet)
 	else if (repo_config_get_string(r, config_key, &ret) < 0)
 		die(_("could not retrieve `%s`"), config_display_key);
 
-	if (!ret)
+	if (!ret) {
 		ret = xstrdup("master");
+		if (!quiet)
+			advise(_(default_branch_name_advice), ret);
+	}
 
 	full_ref = xstrfmt("refs/heads/%s", ret);
 	if (check_refname_format(full_ref, 0))
t/t0001-init.sh +8 -1
index 69a320489f..754dab3bab 100755
@@ -163,7 +163,7 @@ test_expect_success 'reinit' '
 	(
 		mkdir again &&
 		cd again &&
-		git init >out1 2>err1 &&
+		git -c init.defaultBranch=initial init >out1 2>err1 &&
 		git init >out2 2>err2
 	) &&
 	test_i18ngrep "Initialized empty" again/out1 &&
@@ -558,6 +558,13 @@ test_expect_success 'overridden default initial branch name (config)' '
 	grep nmb actual
 '
 
+test_expect_success 'advice on unconfigured init.defaultBranch' '
+	GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= git -c color.advice=always \
+		init unconfigured-default-branch-name 2>err &&
+	test_decode_color <err >decoded &&
+	test_i18ngrep "<YELLOW>hint: " decoded
+'
+
 test_expect_success 'overridden default main branch name (env)' '
 	test_config_global init.defaultBranch nmb &&
 	GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=env git init main-branch-env &&
t/t1510-repo-setup.sh +1 -1
index 9974457f56..5189a520a2 100755
@@ -79,7 +79,7 @@ setup_repo () {
 	name=$1 worktreecfg=$2 gitfile=$3 barecfg=$4 &&
 	sane_unset GIT_DIR GIT_WORK_TREE &&
 
-	git init "$name" &&
+	git -c init.defaultBranch=repo init "$name" &&
 	maybe_config "$name/.git/config" core.worktree "$worktreecfg" &&
 	maybe_config "$name/.git/config" core.bare "$barecfg" &&
 	mkdir -p "$name/sub/sub" &&
t/t7414-submodule-mistakes.sh +1 -1
index f2e7df59cf..0ed02938f9 100755
@@ -30,7 +30,7 @@ test_expect_success 'no warning when updating entry' '
 
 test_expect_success 'submodule add does not warn' '
 	test_when_finished "git rm -rf submodule .gitmodules" &&
-	git submodule add ./embed submodule 2>stderr &&
+	git -c init.defaultBranch=x submodule add ./embed submodule 2>stderr &&
 	test_i18ngrep ! warning stderr
 '
 
t/test-lib-functions.sh +2 -1
index 59bbf75e83..772152320a 100644
@@ -1202,7 +1202,8 @@ test_create_repo () {
 	mkdir -p "$repo"
 	(
 		cd "$repo" || error "Cannot setup test environment"
-		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" init \
+		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" \
+			-c init.defaultBranch=master init \
 			"--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||
 		error "cannot run git init -- have you built things yet?"
 		mv .git/hooks .git/hooks-disabled
Signature · 1 line
gitgitgadget
#2 lore raw

Re: [PATCH 1/3] init: document `init.defaultBranch` better

In reply to Johannes Schindelin via GitGitGadget

"Johannes Schindelin via GitGitGadget" <[email protected]>

Quoted 8 lines · writes:

From: Johannes Schindelin <[email protected]>

Our documentation does not mention any future plan to change 'master' to other value. It is a good idea to document this, though.

---

It would have been nicer to have a reference to the original patch <[email protected]> here after the three-dash lines, which would have made it easier for me to say that the updated phrasing is much better.

I do not think I deserve credit for this step in the series. Please drop "initial-patch-by" when you do a v2.

Quoted 8 lines
 Documentation/git-init.txt | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
Documentation/git-init.txt +0 -0
index 59ecda6c17..19f9f16e6b 100644

Documentation/git-init.txt DESCRIPTION · line 25

Quoted 8 lines
Documentation/git-init.txt +3 -2
@@ -20,8 +20,9 @@ DESCRIPTION
 
 This command creates an empty Git repository - basically a `.git`
 directory with subdirectories for `objects`, `refs/heads`,
-`refs/tags`, and template files.  An initial `HEAD` file that
-references the HEAD of the master branch is also created.
+`refs/tags`, and template files.  An initial branch without any
+commits will be created (see the `--initial-branch` option below
+for its name).

"branch without any commits" is certainly easier to understand than "unborn branch", which was in my weatherballoon patch.

Stepping back a bit more, I wonder if we want to make reference to implementation details even less, e.g.

... an empty Git repository---a .git directory to store objects, branches and tags, hooks, and template files.

which would be in the same spirit as not mentioning 'HEAD file'.

Documentation/git-init.txt If this is reinitialization, the repository will be moved to the specified path. · line 80

Quoted 10 lines
Documentation/git-init.txt +4 -2
@@ -73,8 +74,10 @@ If this is reinitialization, the repository will be moved to the specified path.
 -b <branch-name>::
 --initial-branch=<branch-name>::
 
-Use the specified name for the initial branch in the newly created repository.
-If not specified, fall back to the default name: `master`.
+Use the specified name for the initial branch in the newly created
+repository.  If not specified, fall back to the default name (currently
+`master`, but that will be changed in the future; The name can be customized
+via the `init.defaultBranch` configuration variable).

s/The/the/ after semicolon that ends a half-sentence. Or alternatively, s/in the future;/in the future./

Quoted 2 lines
Documentation/git-init.txt +0 -0
 --shared[=(false|true|umask|group|all|world|everybody|0xxx)]::
#6 lore raw

Re: [PATCH 3/3] init: provide useful advice about init.defaultBranch

In reply to Johannes Schindelin via GitGitGadget

"Johannes Schindelin via GitGitGadget" <[email protected]>

Quoted 5 lines · writes:

From: Johannes Schindelin <[email protected]>

To give ample warning in case we decide to change the fall-back for an unconfigured init.defaultBranch, let's introduce some advice that is shown upon git init when that value is not set.

I know this means well.

I however doubt "ample warning" before we announce an actual decision makes user's life any easier in practice, though. Until they know what it will be changed to (if we decide not to change anything, treat it as changing it to 'master'), they would not be able to decide if the name is more suitable for their use case.

I further suspect that their choice will be influenced the most by the choice made by the projects they most often interact with, and not by our plan.

Quoted 4 lines

+static const char default_branch_name_advice[] = N_(
+"Using '%s' as the name for the initial branch. This name is subject\n" +"to change. To configure the name to use as the initial branch name in\n" +"new repositories, or to silence this warning, run:\n"

s/new repositories/all of your new repositories/ as that is the whole point of using --global option below.

Quoted 18 lines

+"\n"
+"\tgit config --global init.defaultBranch <name>\n"

t/t0001-init.sh +9 -0
+);
+
 
+test_expect_success 'advice on unconfigured init.defaultBranch' '
+	GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= git -c color.advice=always \
+		init unconfigured-default-branch-name 2>err &&
+	test_decode_color <err >decoded &&
+	test_i18ngrep "<YELLOW>hint: " decoded
+'
+
t/t7414-submodule-mistakes.sh +0 -0
index f2e7df59cf..0ed02938f9 100755

t/t7414-submodule-mistakes.sh test_expect_success 'no warning when updating entry' ' · line 35

Quoted 7 lines
t/t7414-submodule-mistakes.sh +1 -1
@@ -30,7 +30,7 @@ test_expect_success 'no warning when updating entry' '
 
 test_expect_success 'submodule add does not warn' '
 	test_when_finished "git rm -rf submodule .gitmodules" &&
-	git submodule add ./embed submodule 2>stderr &&
+	git -c init.defaultBranch=x submodule add ./embed submodule 2>stderr &&
 	test_i18ngrep ! warning stderr
 '

It is a bit subtle that this not only tests whatever "git submodule" test it originally wanted to do but also serves as a test that the new advice message is squelched by the presence of the configuration.

t/test-lib-functions.sh test_create_repo () { · line 1206

Quoted 11 lines
t/test-lib-functions.sh +2 -1
index 59bbf75e83..772152320a 100644
@@ -1202,7 +1202,8 @@ test_create_repo () {
 	mkdir -p "$repo"
 	(
 		cd "$repo" || error "Cannot setup test environment"
-		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" init \
+		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" \
+			-c init.defaultBranch=master init \

I wonder if this should be more like

	-c init.defaultBranch=${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME-master}

so that tests that want a particular branch name would get what they want?

Eventually we would need to do the s/master/X/ if/when the actual default change happens.

Quoted 3 lines
t/test-lib-functions.sh +0 -0
 			"--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||
 		error "cannot run git init -- have you built things yet?"
 		mv .git/hooks .git/hooks-disabled
#7 lore raw

Re: [PATCH 3/3] init: provide useful advice about init.defaultBranch

Quoted 5 lines · Junio C Hamano
Quoted 4 lines

+static const char default_branch_name_advice[] = N_(
+"Using '%s' as the name for the initial branch. This name is subject\n" +"to change. To configure the name to use as the initial branch name in\n" +"new repositories, or to silence this warning, run:\n"

Quoted 7 lines

s/new repositories/all of your new repositories/ as that is the whole point of using --global option below.

refs.c void expand_ref_prefix(struct strvec *prefixes, const char *prefix) · line 572

Quoted 4 lines

+"\n"
+"\tgit config --global init.defaultBranch <name>\n"

refs.c +2 -0
+);
+

The above may give a valuable lesson to those who want to use one branch name across new repositories, but it does not tell those who wanted 'trunk' (to match the project, perhaps github.com/cli/cli, with which they intend to interact) how to recover from having already created the 'master' branch. We may want to add some text to suggest "branch -M" after giving the advice for the permanent option.

Also, it is unclear to those who do not have a good <name> in mind (or, those who do not care to choose a <name> for themselves), what <name> they should give to take the "or to silence this warning" part of the advice. It probably is a good idea to rephrase and say either:

... To configure ... in all your new repositories and squelch this message, run:

git config --global init.defaultBranch <name>

or

... To configure ... in all your new repositories, run:

git config --global init.defaultBranch <name>

Note that this message won't appear after doing so.

I am offhand not sure which one is better.

Thanks.

#3 lore raw

Re: [PATCH 1/3] init: document `init.defaultBranch` better

In reply to Junio C Hamano

Hi Junio,

Quoted 8 lines · Junio C Hamano

"Johannes Schindelin via GitGitGadget" <[email protected]>

Quoted 5 lines · writes:

From: Johannes Schindelin <[email protected]>

Our documentation does not mention any future plan to change 'master' to other value. It is a good idea to document this, though.

Quoted 8 lines
Quoted 3 lines

---

It would have been nicer to have a reference to the original patch <[email protected]> here after the three-dash lines, which would have made it easier for me to say that the updated phrasing is much better.

This is unfortunately not possible with GitGitGadget, which I use because it takes away so much of my burden when contributing patches.

Quoted 2 lines

I do not think I deserve credit for this step in the series. Please drop "initial-patch-by" when you do a v2.

This is not about "deserving". More than half of the patch is still identical to what you wrote, I only pasted it. This is yours, not mine.

Quoted 17 lines

Documentation/git-init.txt DESCRIPTION · line 25

Quoted 13 lines
Documentation/git-init.txt +3 -2
index 59ecda6c17..19f9f16e6b 100644
@@ -20,8 +20,9 @@ DESCRIPTION
 
 This command creates an empty Git repository - basically a `.git`
 directory with subdirectories for `objects`, `refs/heads`,
-`refs/tags`, and template files.  An initial `HEAD` file that
-references the HEAD of the master branch is also created.
+`refs/tags`, and template files.  An initial branch without any
+commits will be created (see the `--initial-branch` option below
+for its name).

"branch without any commits" is certainly easier to understand than "unborn branch", which was in my weatherballoon patch.

Quoted 7 lines

Stepping back a bit more, I wonder if we want to make reference to implementation details even less, e.g.

... an empty Git repository---a .git directory to store objects, branches and tags, hooks, and template files.

which would be in the same spirit as not mentioning 'HEAD file'.

Hmm. I'm of two minds there. On the one hand, it is nice to have a conciser description. On the other hand, it is nice to have a little bit depth in the description.

For the time being, I'll leave it as-is.

Quoted 4 lines
Quoted 4 lines
Documentation/git-init.txt +0 -0
@@ -73,8 +74,10 @@ If this is reinitialization, the repository will be moved to the specified path.
 -b <branch-name>::
 --initial-branch=<branch-name>::
 
Quoted 9 lines

Documentation/git-init.txt If this is reinitialization, the repository will be moved to the specified path. · line 80

Quoted 6 lines
Documentation/git-init.txt +4 -2
-Use the specified name for the initial branch in the newly created repository.
-If not specified, fall back to the default name: `master`.
+Use the specified name for the initial branch in the newly created
+repository.  If not specified, fall back to the default name (currently
+`master`, but that will be changed in the future; The name can be customized
+via the `init.defaultBranch` configuration variable).

s/The/the/ after semicolon that ends a half-sentence. Or alternatively, s/in the future;/in the future./

Okay.

Quoted 1 line

Documentation/git-init.txt If this is reinitialization, the repository will be moved to the specified path. · line 82

Quoted 1 line
Documentation/git-init.txt +0 -0
 --shared[=(false|true|umask|group|all|world|everybody|0xxx)]::

Thanks for the thorough review,
Dscho

#12 lore raw

Re: [PATCH 3/3] init: provide useful advice about init.defaultBranch

In reply to Junio C Hamano

Hi Junio,

Quoted 5 lines · Junio C Hamano

"Johannes Schindelin via GitGitGadget" <[email protected]>

Quoted 2 lines · writes:

From: Johannes Schindelin <[email protected]>

Quoted 8 lines
Quoted 3 lines

To give ample warning in case we decide to change the fall-back for an unconfigured init.defaultBranch, let's introduce some advice that is shown upon git init when that value is not set.

I know this means well.

I however doubt "ample warning" before we announce an actual decision makes user's life any easier in practice, though.

I reworded the commit message to make the rationale more obvious: the ample warning is to give users a chance to override whatever is Git's default branch name by configuring init.defaultBranch. If they care at all.

Quoted 8 lines

Until they know what it will be changed to (if we decide not to change anything, treat it as changing it to 'master'), they would not be able to decide if the name is more suitable for their use case.

I further suspect that their choice will be influenced the most by the choice made by the projects they most often interact with, and not by our plan.

Quoted 7 lines
Quoted 4 lines

+static const char default_branch_name_advice[] = N_(
+"Using '%s' as the name for the initial branch. This name is subject\n" +"to change. To configure the name to use as the initial branch name in\n" +"new repositories, or to silence this warning, run:\n"

s/new repositories/all of your new repositories/ as that is the whole point of using --global option below.

Makes sense.

Quoted 19 lines
Quoted 19 lines

+"\n"
+"\tgit config --global init.defaultBranch <name>\n"

t/t0001-init.sh +9 -0
+);
+
 
+test_expect_success 'advice on unconfigured init.defaultBranch' '
+	GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= git -c color.advice=always \
+		init unconfigured-default-branch-name 2>err &&
+	test_decode_color <err >decoded &&
+	test_i18ngrep "<YELLOW>hint: " decoded
+'
+
t/t7414-submodule-mistakes.sh +0 -0
index f2e7df59cf..0ed02938f9 100755
@@ -30,7 +30,7 @@ test_expect_success 'no warning when updating entry' '
 
Quoted 10 lines

t/t7414-submodule-mistakes.sh test_expect_success 'no warning when updating entry' ' · line 35

Quoted 6 lines
t/t7414-submodule-mistakes.sh +1 -1
 test_expect_success 'submodule add does not warn' '
 	test_when_finished "git rm -rf submodule .gitmodules" &&
-	git submodule add ./embed submodule 2>stderr &&
+	git -c init.defaultBranch=x submodule add ./embed submodule 2>stderr &&
 	test_i18ngrep ! warning stderr
 '

It is a bit subtle that this not only tests whatever "git submodule" test it originally wanted to do but also serves as a test that the new advice message is squelched by the presence of the configuration.

Thank you for catching this. It is a debugging left-over.

The real fix for the underlying issue is in the previous commit, which silences the warning when init_db() is called via clone, as is the case here.

I removed it from v2.

Quoted 14 lines

t/test-lib-functions.sh test_create_repo () { · line 1206

Quoted 11 lines
t/test-lib-functions.sh +2 -1
index 59bbf75e83..772152320a 100644
@@ -1202,7 +1202,8 @@ test_create_repo () {
 	mkdir -p "$repo"
 	(
 		cd "$repo" || error "Cannot setup test environment"
-		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" init \
+		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" \
+			-c init.defaultBranch=master init \

I wonder if this should be more like

Quoted 4 lines
	-c init.defaultBranch=${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME-master}

so that tests that want a particular branch name would get what they want?

As is custom with our GIT_TEST_* variables, GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME overrides init.defaultBranch.

Therefore, _technically_ what you suggested is not even necessary here.

Quoted 2 lines

Eventually we would need to do the s/master/X/ if/when the actual default change happens.

However, _practically_, what you suggested is very helpful, as it will make it easy to find when (if?) we finish the transition to a new fall-back.

Thank you for your thorough feedback,
Dscho

Quoted 4 lines
Quoted 3 lines
t/test-lib-functions.sh +0 -0
 			"--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||
 		error "cannot run git init -- have you built things yet?"
 		mv .git/hooks .git/hooks-disabled
#13 lore raw

Re: [PATCH 3/3] init: provide useful advice about init.defaultBranch

In reply to Johannes Schindelin via GitGitGadget

hi dscho,

Quoted 25 lines · Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

To give ample warning in case we decide to change the fall-back for an unconfigured init.defaultBranch, let's introduce some advice that is shown upon git init when that value is not set.

Note: three test cases in Git's test suite want to verify that the stderr output of git init is empty. With this patch, that is only true if init.defaultBranch is configured, so let's do exactly that in those test cases. The same reasoning applies to test_create_repo().

---
 refs.c                        | 13 ++++++++++++-
 t/t0001-init.sh               |  9 ++++++++-
 t/t1510-repo-setup.sh         |  2 +-
 t/t7414-submodule-mistakes.sh |  2 +-
 t/test-lib-functions.sh       |  3 ++-
 5 files changed, 24 insertions(+), 5 deletions(-)
refs.c +0 -0
index 8df03122d6..61d712ca05 100644

refs.c void expand_ref_prefix(struct strvec *prefixes, const char *prefix) · line 567

Quoted 6 lines
refs.c +3 -0
@@ -562,6 +562,14 @@ void expand_ref_prefix(struct strvec *prefixes, const char *prefix)
 		strvec_pushf(prefixes, *p, len, prefix);
 }
 
+static const char default_branch_name_advice[] = N_(
+"Using '%s' as the name for the initial branch. This name is subject\n"
+"to change. 

This sounds like Git will change the branch name within the user's repo, rather than "The default" being subject to change.  So maybe s/This/The default/   ?

Philip

Quoted 89 lines

To configure the name to use as the initial branch name in\n" +"new repositories, or to silence this warning, run:\n" +"\n"
+"\tgit config --global init.defaultBranch <name>\n"

refs.c +6 -1
+);
+
 char *repo_default_branch_name(struct repository *r, int quiet)
 {
 	const char *config_key = "init.defaultbranch";
@@ -574,8 +582,11 @@ char *repo_default_branch_name(struct repository *r, int quiet)
 	else if (repo_config_get_string(r, config_key, &ret) < 0)
 		die(_("could not retrieve `%s`"), config_display_key);
 
-	if (!ret)
+	if (!ret) {
 		ret = xstrdup("master");
+		if (!quiet)
+			advise(_(default_branch_name_advice), ret);
+	}
 
 	full_ref = xstrfmt("refs/heads/%s", ret);
 	if (check_refname_format(full_ref, 0))
t/t0001-init.sh +8 -1
index 69a320489f..754dab3bab 100755
@@ -163,7 +163,7 @@ test_expect_success 'reinit' '
 	(
 		mkdir again &&
 		cd again &&
-		git init >out1 2>err1 &&
+		git -c init.defaultBranch=initial init >out1 2>err1 &&
 		git init >out2 2>err2
 	) &&
 	test_i18ngrep "Initialized empty" again/out1 &&
@@ -558,6 +558,13 @@ test_expect_success 'overridden default initial branch name (config)' '
 	grep nmb actual
 '
 
+test_expect_success 'advice on unconfigured init.defaultBranch' '
+	GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= git -c color.advice=always \
+		init unconfigured-default-branch-name 2>err &&
+	test_decode_color <err >decoded &&
+	test_i18ngrep "<YELLOW>hint: " decoded
+'
+
 test_expect_success 'overridden default main branch name (env)' '
 	test_config_global init.defaultBranch nmb &&
 	GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=env git init main-branch-env &&
t/t1510-repo-setup.sh +1 -1
index 9974457f56..5189a520a2 100755
@@ -79,7 +79,7 @@ setup_repo () {
 	name=$1 worktreecfg=$2 gitfile=$3 barecfg=$4 &&
 	sane_unset GIT_DIR GIT_WORK_TREE &&
 
-	git init "$name" &&
+	git -c init.defaultBranch=repo init "$name" &&
 	maybe_config "$name/.git/config" core.worktree "$worktreecfg" &&
 	maybe_config "$name/.git/config" core.bare "$barecfg" &&
 	mkdir -p "$name/sub/sub" &&
t/t7414-submodule-mistakes.sh +1 -1
index f2e7df59cf..0ed02938f9 100755
@@ -30,7 +30,7 @@ test_expect_success 'no warning when updating entry' '
 
 test_expect_success 'submodule add does not warn' '
 	test_when_finished "git rm -rf submodule .gitmodules" &&
-	git submodule add ./embed submodule 2>stderr &&
+	git -c init.defaultBranch=x submodule add ./embed submodule 2>stderr &&
 	test_i18ngrep ! warning stderr
 '
 
t/test-lib-functions.sh +2 -1
index 59bbf75e83..772152320a 100644
@@ -1202,7 +1202,8 @@ test_create_repo () {
 	mkdir -p "$repo"
 	(
 		cd "$repo" || error "Cannot setup test environment"
-		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" init \
+		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" \
+			-c init.defaultBranch=master init \
 			"--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||
 		error "cannot run git init -- have you built things yet?"
 		mv .git/hooks .git/hooks-disabled
#8 lore raw

Re: [PATCH 3/3] init: provide useful advice about init.defaultBranch

In reply to Junio C Hamano

Hi Junio,

Quoted 10 lines · Junio C Hamano
Quoted 8 lines · Junio C Hamano
Quoted 4 lines

+static const char default_branch_name_advice[] = N_(
+"Using '%s' as the name for the initial branch. This name is subject\n" +"to change. To configure the name to use as the initial branch name in\n" +"new repositories, or to silence this warning, run:\n"

s/new repositories/all of your new repositories/ as that is the whole point of using --global option below.

Quoted 12 lines
Quoted 4 lines

refs.c void expand_ref_prefix(struct strvec *prefixes, const char *prefix) · line 572

Quoted 4 lines

+"\n"
+"\tgit config --global init.defaultBranch <name>\n"

refs.c +2 -0
+);
+

The above may give a valuable lesson to those who want to use one branch name across new repositories, but it does not tell those who wanted 'trunk' (to match the project, perhaps github.com/cli/cli, with which they intend to interact) how to recover from having already created the 'master' branch. We may want to add some text to suggest "branch -M" after giving the advice for the permanent option.

Good point.

Quoted 4 lines

Also, it is unclear to those who do not have a good <name> in mind (or, those who do not care to choose a <name> for themselves), what <name> they should give to take the "or to silence this warning" part of the advice.

Also a good point.

Quoted 8 lines

It probably is a good idea to rephrase and say
either:

... To configure ... in all your new repositories and squelch this message, run:

git config --global init.defaultBranch <name>

Quoted 7 lines

or

... To configure ... in all your new repositories, run:

git config --global init.defaultBranch <name>

Note that this message won't appear after doing so.

I came up with this, which I intend to submit with v2:

static const char default_branch_name_advice[] = N_(
"Using '%s' as the name for the initial branch. This name is subject\n" "to change. To configure the initial branch name to use in all of your\n" "new repositories (or to suppress this warning), run:\n"
"\n"
"\tgit config --global init.defaultBranch <name>\n"
"\n"
"Common names are 'main', 'trunk' and 'development'. The initial branch\n" "can be renamed via this command:\n"
"\n"
"\tgit branch -m <name>\n"
);

Ciao,
Dscho

#9 lore raw

Re: [PATCH 3/3] init: provide useful advice about init.defaultBranch

Quoted 15 lines · Johannes Schindelin
Quoted 7 lines

The above may give a valuable lesson to those who want to use one branch name across new repositories, but it does not tell those who wanted 'trunk' (to match the project, perhaps github.com/cli/cli, with which they intend to interact) how to recover from having already created the 'master' branch. We may want to add some text to suggest "branch -M" after giving the advice for the permanent option.

Good point.

Quoted 4 lines

Also, it is unclear to those who do not have a good <name> in mind (or, those who do not care to choose a <name> for themselves), what <name> they should give to take the "or to silence this warning" part of the advice.

Quoted 8 lines

Also a good point.

I came up with this, which I intend to submit with v2:

static const char default_branch_name_advice[] = N_(
"Using '%s' as the name for the initial branch. This name is subject\n" "to change. To configure the initial branch name to use in all of your\n" "new repositories (or to suppress this warning), run:\n"

The same issue around "to suppress" is here, though.

Quoted 7 lines

"\n"
"\tgit config --global init.defaultBranch <name>\n"
"\n"
"Common names are 'main', 'trunk' and 'development'. The initial branch\n" "can be renamed via this command:\n"
"\n"
"\tgit branch -m <name>\n"

It is very likely that the users are on an unborn branch when they see this message and "git branch -m/-M <name>" does not work. We'd probably want to update "git branch" to allow renaming the current branch that is unborn.

In the meantime, you could do "git checkout --orphan <name>" here, but once <name> exists as a branch that would not work, so...

Quoted 4 lines

);

Ciao,
Dscho

#10 lore raw

Re: [PATCH 3/3] init: provide useful advice about init.defaultBranch

Hi Junio,

Quoted 19 lines · Junio C Hamano
Quoted 16 lines · Johannes Schindelin
Quoted 7 lines

The above may give a valuable lesson to those who want to use one branch name across new repositories, but it does not tell those who wanted 'trunk' (to match the project, perhaps github.com/cli/cli, with which they intend to interact) how to recover from having already created the 'master' branch. We may want to add some text to suggest "branch -M" after giving the advice for the permanent option.

Good point.

Quoted 4 lines

Also, it is unclear to those who do not have a good <name> in mind (or, those who do not care to choose a <name> for themselves), what <name> they should give to take the "or to silence this warning" part of the advice.

Also a good point.

Quoted 8 lines
Quoted 6 lines

I came up with this, which I intend to submit with v2:

static const char default_branch_name_advice[] = N_(
"Using '%s' as the name for the initial branch. This name is subject\n" "to change. To configure the initial branch name to use in all of your\n" "new repositories (or to suppress this warning), run:\n"

The same issue around "to suppress" is here, though.

Hmm. I would like to believe that readers understand that setting it to _any_ name would suppress this warning.

Quoted 8 lines
Quoted 7 lines

"\n"
"\tgit config --global init.defaultBranch <name>\n"
"\n"
"Common names are 'main', 'trunk' and 'development'. The initial branch\n" "can be renamed via this command:\n"
"\n"
"\tgit branch -m <name>\n"

Quoted 4 lines

It is very likely that the users are on an unborn branch when they see this message and "git branch -m/-M <name>" does not work. We'd probably want to update "git branch" to allow renaming the current branch that is unborn.

Ouch, good point, I had not even realized that that does not work. In v2, I will include a patch that lets it work.

Quoted 2 lines

In the meantime, you could do "git checkout --orphan <name>" here, but once <name> exists as a branch that would not work, so...

Careful. We should start thinking about phasing out either checkout or switch. The latter was intended to supersede the former with respect to working on branches, so I would think of phasing out checkout and favor switch instead.

That issue aside, git switch --orphan <name> is not necessarily a good UI here. Its documentation talks about creating a new branch, deleting all tracked files. While it is technically still correct that this command, when run on an unborn branch, does the same as renaming said branch, it is highly unintuitive to think about it that way. ("I don't want to create a new branch, I want to rename the current one! And whoa, delete tracked files? I don't want to delete _any_ files! What do you mean: there aren't any tracked files, so none are deleted? Why do you talk about deleting files, then?")

So in the interest of _reducing_ confusion, I would really, really, _really_ like to avoid mentioning that command in this advice.

It really is much better to make git branch -m <name> work in this scenario.

Ciao,
Dscho

Quoted 7 lines
Quoted 6 lines

);

Ciao,
Dscho

#14 lore raw

Re: [PATCH 3/3] init: provide useful advice about init.defaultBranch

In reply to Philip Oakley

Hi Philip,

Quoted 29 lines · Philip Oakley
Quoted 28 lines · Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

To give ample warning in case we decide to change the fall-back for an unconfigured init.defaultBranch, let's introduce some advice that is shown upon git init when that value is not set.

Note: three test cases in Git's test suite want to verify that the stderr output of git init is empty. With this patch, that is only true if init.defaultBranch is configured, so let's do exactly that in those test cases. The same reasoning applies to test_create_repo().

---
 refs.c                        | 13 ++++++++++++-
 t/t0001-init.sh               |  9 ++++++++-
 t/t1510-repo-setup.sh         |  2 +-
 t/t7414-submodule-mistakes.sh |  2 +-
 t/test-lib-functions.sh       |  3 ++-
 5 files changed, 24 insertions(+), 5 deletions(-)
refs.c +0 -0
index 8df03122d6..61d712ca05 100644
@@ -562,6 +562,14 @@ void expand_ref_prefix(struct strvec *prefixes, const char *prefix)
 		strvec_pushf(prefixes, *p, len, prefix);
 }
 
Quoted 6 lines

refs.c void expand_ref_prefix(struct strvec *prefixes, const char *prefix)

Quoted 3 lines
refs.c +3 -0
+static const char default_branch_name_advice[] = N_(
+"Using '%s' as the name for the initial branch. This name is subject\n"
+"to change.

This sounds like Git will change the branch name within the user's repo, rather than "The default" being subject to change.  So maybe s/This/The default/   ?

Yes, that sounds clearer to me. Thank you,
Dscho

Quoted 94 lines

Philip

Quoted 89 lines

To configure the name to use as the initial branch name in\n" +"new repositories, or to silence this warning, run:\n" +"\n"
+"\tgit config --global init.defaultBranch <name>\n"

refs.c +6 -1
+);
+
 char *repo_default_branch_name(struct repository *r, int quiet)
 {
 	const char *config_key = "init.defaultbranch";
@@ -574,8 +582,11 @@ char *repo_default_branch_name(struct repository *r, int quiet)
 	else if (repo_config_get_string(r, config_key, &ret) < 0)
 		die(_("could not retrieve `%s`"), config_display_key);
 
-	if (!ret)
+	if (!ret) {
 		ret = xstrdup("master");
+		if (!quiet)
+			advise(_(default_branch_name_advice), ret);
+	}
 
 	full_ref = xstrfmt("refs/heads/%s", ret);
 	if (check_refname_format(full_ref, 0))
t/t0001-init.sh +8 -1
index 69a320489f..754dab3bab 100755
@@ -163,7 +163,7 @@ test_expect_success 'reinit' '
 	(
 		mkdir again &&
 		cd again &&
-		git init >out1 2>err1 &&
+		git -c init.defaultBranch=initial init >out1 2>err1 &&
 		git init >out2 2>err2
 	) &&
 	test_i18ngrep "Initialized empty" again/out1 &&
@@ -558,6 +558,13 @@ test_expect_success 'overridden default initial branch name (config)' '
 	grep nmb actual
 '
 
+test_expect_success 'advice on unconfigured init.defaultBranch' '
+	GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= git -c color.advice=always \
+		init unconfigured-default-branch-name 2>err &&
+	test_decode_color <err >decoded &&
+	test_i18ngrep "<YELLOW>hint: " decoded
+'
+
 test_expect_success 'overridden default main branch name (env)' '
 	test_config_global init.defaultBranch nmb &&
 	GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=env git init main-branch-env &&
t/t1510-repo-setup.sh +1 -1
index 9974457f56..5189a520a2 100755
@@ -79,7 +79,7 @@ setup_repo () {
 	name=$1 worktreecfg=$2 gitfile=$3 barecfg=$4 &&
 	sane_unset GIT_DIR GIT_WORK_TREE &&
 
-	git init "$name" &&
+	git -c init.defaultBranch=repo init "$name" &&
 	maybe_config "$name/.git/config" core.worktree "$worktreecfg" &&
 	maybe_config "$name/.git/config" core.bare "$barecfg" &&
 	mkdir -p "$name/sub/sub" &&
t/t7414-submodule-mistakes.sh +1 -1
index f2e7df59cf..0ed02938f9 100755
@@ -30,7 +30,7 @@ test_expect_success 'no warning when updating entry' '
 
 test_expect_success 'submodule add does not warn' '
 	test_when_finished "git rm -rf submodule .gitmodules" &&
-	git submodule add ./embed submodule 2>stderr &&
+	git -c init.defaultBranch=x submodule add ./embed submodule 2>stderr &&
 	test_i18ngrep ! warning stderr
 '
 
t/test-lib-functions.sh +2 -1
index 59bbf75e83..772152320a 100644
@@ -1202,7 +1202,8 @@ test_create_repo () {
 	mkdir -p "$repo"
 	(
 		cd "$repo" || error "Cannot setup test environment"
-		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" init \
+		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" \
+			-c init.defaultBranch=master init \
 			"--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||
 		error "cannot run git init -- have you built things yet?"
 		mv .git/hooks .git/hooks-disabled
#11 lore raw

Re: [PATCH 3/3] init: provide useful advice about init.defaultBranch

In reply to Johannes Schindelin
Quoted 2 lines · Johannes Schindelin

Hmm. I would like to believe that readers understand that setting it to _any_ name would suppress this warning.

Yes, and the point raised in an earlier messages was that it is not clear that there is no recourse for those who do NOT want to choose but still want to suppress.

Quoted 2 lines

It really is much better to make git branch -m <name> work in this scenario.

Yes, if we can make it work, that is much more preferred.

#15 lore raw

v2 cover Add helpful advice about init.defaultBranch

In reply to Johannes Schindelin via GitGitGadget

It is our designated intention
[https://sfconservancy.org/news/2020/jun/23/gitbranchname/] to "to explore changing the name of the first branch created automatically for new repositories away from ‘master’". Further, we promised that we "will minimize disruption for Git's users and will include appropriate deprecation periods".

To that end, we first clarify git init's documentation (a lightly edited version of Junio's patch
[https://lore.kernel.org/git/[email protected]]), and then introduce a message giving advice to users running git init that the fall-back for init.defaultBranch is subject to change, and how to override Git's fall-back manually.

The beauty of this patch series, if I may say so, is that it does not commit us to any concrete plan, but opens the door for all options regarding the default branch name.

Changes since v1:

* Grammar fix
* Reworded advice and commit messages
* test_create_repo already respected GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME, but now does so more obviously
* Allowed git branch -m <name> to rename unborn branches, so that the advice actually works

Johannes Schindelin (4):
init: document init.defaultBranch better branch -m: allow renaming a yet-unborn branch get_default_branch_name(): prepare for showing some advice
init: provide useful advice about init.defaultBranch

 Documentation/git-init.txt | 11 +++++++----
 builtin/branch.c           |  3 ++-
 builtin/clone.c            |  2 +-
 builtin/init-db.c          |  8 +++++---
 refs.c                     | 25 +++++++++++++++++++++----
 refs.h                     |  4 ++--
 remote.c                   |  5 +++--
 t/t0001-init.sh            | 15 ++++++++++++++-
 t/t1510-repo-setup.sh      |  2 +-
 t/test-lib-functions.sh    |  3 ++-
 10 files changed, 58 insertions(+), 20 deletions(-)

base-commit: faefdd61ec7c7f6f3c8c9907891465ac9a2a1475
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-921%2Fdscho%2Finit.defaultBranch-advice-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-921/dscho/init.defaultBranch-advice-v2
Pull-Request: https://github.com/git/git/pull/921

Range-diff vs v1:

1: 1518387eaa ! 1: 483e490349 init: document init.defaultBranch better
@@ Documentation/git-init.txt: If this is reinitialization, the repository will be
-If not specified, fall back to the default name: master.
+Use the specified name for the initial branch in the newly created +repository. If not specified, fall back to the default name (currently
-+master, but that will be changed in the future; The name can be customized ++master, but that will be changed in the future; the name can be customized
+via the init.defaultBranch configuration variable).

--shared[=(false|true|umask|group|all|world|everybody|0xxx)]::

 -:  ---------- > 2:  8de0c0eb22 branch -m: allow renaming a yet-unborn branch
 2:  42f6940043 = 3:  03314f7ac6 get_default_branch_name(): prepare for showing some advice
 3:  253d6706e6 ! 4:  bccef95391 init: provide useful advice about init.defaultBranch

@@ Metadata
## Commit message ##
init: provide useful advice about init.defaultBranch

- To give ample warning in case we decide to change the fall-back for an
- unconfigured init.defaultBranch, let's introduce some advice that is
- shown upon git init when that value is not set.
+ To give ample warning for users wishing to override Git's the fall-back
+ for an unconfigured init.defaultBranch (in case we decide to change it
+ in a future Git version), let's introduce some advice that is shown upon
+ git init when that value is not set.

- Note: three test cases in Git's test suite want to verify that the
+ Note: two test cases in Git's test suite want to verify that the
stderr output of git init is empty. With this patch, that is only true if init.defaultBranch is configured, so let's do exactly that in those test cases. The same reasoning applies to test_create_repo().
@@ refs.c: void expand_ref_prefix(struct strvec *prefixes, const char *prefix)
}

+static const char default_branch_name_advice[] = N_(
-+"Using '%s' as the name for the initial branch. This name is subject\n" -+"to change. To configure the name to use as the initial branch name in\n" -+"new repositories, or to silence this warning, run:\n"
++"Using '%s' as the name for the initial branch. This default branch name\n" ++"is subject to change. To configure the initial branch name to use in all\n" ++"of your new repositories, run:\n"
+"\n"
+"\tgit config --global init.defaultBranch <name>\n"
++"\n"
++"Common names are 'main', 'trunk' and 'development'. If you merely wish\n" ++"to suppress this warning, you can also use the current default branch\n" ++"name. The current branch can be renamed via this command:\n" ++"\n"
++"\tgit branch -m <name>\n"
+);
+
char *repo_default_branch_name(struct repository *r, int quiet)
@@ t/t1510-repo-setup.sh: setup_repo () {
maybe_config "$name/.git/config" core.bare "$barecfg" &&
mkdir -p "$name/sub/sub" &&

- ## t/t7414-submodule-mistakes.sh ##
-@@ t/t7414-submodule-mistakes.sh: test_expect_success 'no warning when updating entry' ' -
- test_expect_success 'submodule add does not warn' '
- test_when_finished "git rm -rf submodule .gitmodules" &&
-- git submodule add ./embed submodule 2>stderr &&
-+ git -c init.defaultBranch=x submodule add ./embed submodule 2>stderr &&
- test_i18ngrep ! warning stderr
- '
-
-
## t/test-lib-functions.sh ##
@@ t/test-lib-functions.sh: test_create_repo () {
mkdir -p "$repo"
@@ t/test-lib-functions.sh: test_create_repo () {
cd "$repo" || error "Cannot setup test environment"
- "${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" init \
+ "${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" \
-+ -c init.defaultBranch=master init \
++ -c init.defaultBranch=${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME-master} init \
"--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||
error "cannot run git init -- have you built things yet?"
mv .git/hooks .git/hooks-disabled

Signature · 1 line
gitgitgadget
#16 lore raw

PATCH v2 1/4 init: document `init.defaultBranch` better

From: Johannes Schindelin <[email protected]>

Our documentation does not mention any future plan to change 'master' to other value. It is a good idea to document this, though.

---
 Documentation/git-init.txt | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
Documentation/git-init.txt +7 -4
index 59ecda6c17..2b399cb73d 100644
@@ -20,8 +20,9 @@ DESCRIPTION
 
 This command creates an empty Git repository - basically a `.git`
 directory with subdirectories for `objects`, `refs/heads`,
-`refs/tags`, and template files.  An initial `HEAD` file that
-references the HEAD of the master branch is also created.
+`refs/tags`, and template files.  An initial branch without any
+commits will be created (see the `--initial-branch` option below
+for its name).
 
 If the `$GIT_DIR` environment variable is set then it specifies a path
 to use instead of `./.git` for the base of the repository.
@@ -73,8 +74,10 @@ If this is reinitialization, the repository will be moved to the specified path.
 -b <branch-name>::
 --initial-branch=<branch-name>::
 
-Use the specified name for the initial branch in the newly created repository.
-If not specified, fall back to the default name: `master`.
+Use the specified name for the initial branch in the newly created
+repository.  If not specified, fall back to the default name (currently
+`master`, but that will be changed in the future; the name can be customized
+via the `init.defaultBranch` configuration variable).
 
 --shared[=(false|true|umask|group|all|world|everybody|0xxx)]::
 
Signature · 1 line
gitgitgadget
#17 lore raw

PATCH v2 2/4 branch -m: allow renaming a yet-unborn branch

In reply to Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

In one of the next commits, we would like to give users some advice regarding the initial branch name, and how to modify it.

To that end, it would be good if git branch -m <name> worked in a freshly initialized repository without any commits. Let's make it so.

---
 builtin/branch.c | 3 ++-
 t/t0001-init.sh  | 6 ++++++
 2 files changed, 8 insertions(+), 1 deletion(-)
builtin/branch.c +2 -1
index efb30b8820..10609981e6 100644
@@ -538,7 +538,8 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
 		strbuf_addf(&logmsg, "Branch: renamed %s to %s",
 			    oldref.buf, newref.buf);
 
-	if (!copy && rename_ref(oldref.buf, newref.buf, logmsg.buf))
+	if (!copy && (oldname != head || !is_null_oid(&head_oid)) &&
+	    rename_ref(oldref.buf, newref.buf, logmsg.buf))
 		die(_("Branch rename failed"));
 	if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf))
 		die(_("Branch copy failed"));
t/t0001-init.sh +6 -0
index 69a320489f..69c5ad179c 100755
@@ -571,4 +571,10 @@ test_expect_success 'invalid default branch name' '
 	test_i18ngrep "invalid branch name" err
 '
 
+test_expect_success 'branch -m with the initial branch' '
+	git init rename-initial-branch &&
+	git -C rename-initial-branch branch -m renamed &&
+	test renamed = $(git -C rename-initial-branch symbolic-ref --short HEAD)
+'
+
 test_done
Signature · 1 line
gitgitgadget
#21 lore raw

PATCH v2 3/4 get_default_branch_name(): prepare for showing some advice

In reply to Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

We are about to introduce a message giving users running git init some advice about init.defaultBranch. This will necessarily be done in repo_default_branch_name().

Not all code paths want to show that advice, though. In particular, the git clone codepath _specifically_ asks for init_db() to be quiet, via the INIT_DB_QUIET flag.

In preparation for showing users above-mentioned advice, let's change the function signature of get_default_branch_name() to accept the parameter quiet.

---
 builtin/clone.c   | 2 +-
 builtin/init-db.c | 8 +++++---
 refs.c            | 6 +++---
 refs.h            | 4 ++--
 remote.c          | 5 +++--
 5 files changed, 14 insertions(+), 11 deletions(-)
builtin/clone.c +1 -1
index a0841923cf..64b1784011 100644
@@ -1323,7 +1323,7 @@ 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();
+			const char *branch = git_default_branch_name(0);
 			char *ref = xstrfmt("refs/heads/%s", branch);
 
 			install_branch_config(0, branch, remote_name, ref);
builtin/init-db.c +5 -3
index 01bc648d41..dcc45bef51 100644
@@ -202,7 +202,8 @@ void initialize_repository_version(int hash_algo, int reinit)
 static int create_default_files(const char *template_path,
 				const char *original_git_dir,
 				const char *initial_branch,
-				const struct repository_format *fmt)
+				const struct repository_format *fmt,
+				int quiet)
 {
 	struct stat st1;
 	struct strbuf buf = STRBUF_INIT;
@@ -267,7 +268,7 @@ static int create_default_files(const char *template_path,
 		char *ref;
 
 		if (!initial_branch)
-			initial_branch = git_default_branch_name();
+			initial_branch = git_default_branch_name(quiet);
 
 		ref = xstrfmt("refs/heads/%s", initial_branch);
 		if (check_refname_format(ref, 0) < 0)
@@ -438,7 +439,8 @@ int init_db(const char *git_dir, const char *real_git_dir,
 	validate_hash_algorithm(&repo_fmt, hash);
 
 	reinit = create_default_files(template_dir, original_git_dir,
-				      initial_branch, &repo_fmt);
+				      initial_branch, &repo_fmt,
+				      flags & INIT_DB_QUIET);
 	if (reinit && initial_branch)
 		warning(_("re-init: ignored --initial-branch=%s"),
 			initial_branch);
refs.c +3 -3
index 392f0bbf68..8df03122d6 100644
@@ -562,7 +562,7 @@ void expand_ref_prefix(struct strvec *prefixes, const char *prefix)
 		strvec_pushf(prefixes, *p, len, prefix);
 }
 
-char *repo_default_branch_name(struct repository *r)
+char *repo_default_branch_name(struct repository *r, int quiet)
 {
 	const char *config_key = "init.defaultbranch";
 	const char *config_display_key = "init.defaultBranch";
@@ -585,12 +585,12 @@ char *repo_default_branch_name(struct repository *r)
 	return ret;
 }
 
-const char *git_default_branch_name(void)
+const char *git_default_branch_name(int quiet)
 {
 	static char *ret;
 
 	if (!ret)
-		ret = repo_default_branch_name(the_repository);
+		ret = repo_default_branch_name(the_repository, quiet);
 
 	return ret;
 }
refs.h +2 -2
index 6695518156..ff05d2e9fe 100644
@@ -170,8 +170,8 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **ref);
  * The return value of `repo_default_branch_name()` is an allocated string. The
  * return value of `git_default_branch_name()` is a singleton.
  */
-const char *git_default_branch_name(void);
-char *repo_default_branch_name(struct repository *r);
+const char *git_default_branch_name(int quiet);
+char *repo_default_branch_name(struct repository *r, int quiet);
 
 /*
  * A ref_transaction represents a collection of reference updates that
remote.c +3 -2
index 8a6dbbb903..bdb88d4b7d 100644
@@ -284,7 +284,7 @@ static void read_branches_file(struct remote *remote)
 	if (frag)
 		*(frag++) = '\0';
 	else
-		frag = (char *)git_default_branch_name();
+		frag = (char *)git_default_branch_name(0);
 
 	add_url_alias(remote, strbuf_detach(&buf, NULL));
 	refspec_appendf(&remote->fetch, "refs/heads/%s:refs/heads/%s",
@@ -2206,7 +2206,8 @@ struct ref *guess_remote_head(const struct ref *head,
 
 	/* If a remote branch exists with the default branch name, let's use it. */
 	if (!all) {
-		char *ref = xstrfmt("refs/heads/%s", git_default_branch_name());
+		char *ref = xstrfmt("refs/heads/%s",
+				    git_default_branch_name(0));
 
 		r = find_ref_by_name(refs, ref);
 		free(ref);
Signature · 1 line
gitgitgadget
#22 lore raw

PATCH v2 4/4 init: provide useful advice about init.defaultBranch

In reply to Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

To give ample warning for users wishing to override Git's the fall-back for an unconfigured init.defaultBranch (in case we decide to change it in a future Git version), let's introduce some advice that is shown upon git init when that value is not set.

Note: two test cases in Git's test suite want to verify that the stderr output of git init is empty. With this patch, that is only true if init.defaultBranch is configured, so let's do exactly that in those test cases. The same reasoning applies to test_create_repo().

---
 refs.c                  | 19 ++++++++++++++++++-
 t/t0001-init.sh         |  9 ++++++++-
 t/t1510-repo-setup.sh   |  2 +-
 t/test-lib-functions.sh |  3 ++-
 4 files changed, 29 insertions(+), 4 deletions(-)
refs.c +18 -1
index 8df03122d6..67275858fc 100644
@@ -562,6 +562,20 @@ void expand_ref_prefix(struct strvec *prefixes, const char *prefix)
 		strvec_pushf(prefixes, *p, len, prefix);
 }
 
+static const char default_branch_name_advice[] = N_(
+"Using '%s' as the name for the initial branch. This default branch name\n"
+"is subject to change. To configure the initial branch name to use in all\n"
+"of your new repositories, run:\n"
+"\n"
+"\tgit config --global init.defaultBranch <name>\n"
+"\n"
+"Common names are 'main', 'trunk' and 'development'. If you merely wish\n"
+"to suppress this warning, you can also use the current default branch\n"
+"name. The current branch can be renamed via this command:\n"
+"\n"
+"\tgit branch -m <name>\n"
+);
+
 char *repo_default_branch_name(struct repository *r, int quiet)
 {
 	const char *config_key = "init.defaultbranch";
@@ -574,8 +588,11 @@ char *repo_default_branch_name(struct repository *r, int quiet)
 	else if (repo_config_get_string(r, config_key, &ret) < 0)
 		die(_("could not retrieve `%s`"), config_display_key);
 
-	if (!ret)
+	if (!ret) {
 		ret = xstrdup("master");
+		if (!quiet)
+			advise(_(default_branch_name_advice), ret);
+	}
 
 	full_ref = xstrfmt("refs/heads/%s", ret);
 	if (check_refname_format(full_ref, 0))
t/t0001-init.sh +8 -1
index 69c5ad179c..6f693d9609 100755
@@ -163,7 +163,7 @@ test_expect_success 'reinit' '
 	(
 		mkdir again &&
 		cd again &&
-		git init >out1 2>err1 &&
+		git -c init.defaultBranch=initial init >out1 2>err1 &&
 		git init >out2 2>err2
 	) &&
 	test_i18ngrep "Initialized empty" again/out1 &&
@@ -558,6 +558,13 @@ test_expect_success 'overridden default initial branch name (config)' '
 	grep nmb actual
 '
 
+test_expect_success 'advice on unconfigured init.defaultBranch' '
+	GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= git -c color.advice=always \
+		init unconfigured-default-branch-name 2>err &&
+	test_decode_color <err >decoded &&
+	test_i18ngrep "<YELLOW>hint: " decoded
+'
+
 test_expect_success 'overridden default main branch name (env)' '
 	test_config_global init.defaultBranch nmb &&
 	GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=env git init main-branch-env &&
t/t1510-repo-setup.sh +1 -1
index 9974457f56..5189a520a2 100755
@@ -79,7 +79,7 @@ setup_repo () {
 	name=$1 worktreecfg=$2 gitfile=$3 barecfg=$4 &&
 	sane_unset GIT_DIR GIT_WORK_TREE &&
 
-	git init "$name" &&
+	git -c init.defaultBranch=repo init "$name" &&
 	maybe_config "$name/.git/config" core.worktree "$worktreecfg" &&
 	maybe_config "$name/.git/config" core.bare "$barecfg" &&
 	mkdir -p "$name/sub/sub" &&
t/test-lib-functions.sh +2 -1
index 59bbf75e83..68305a4939 100644
@@ -1202,7 +1202,8 @@ test_create_repo () {
 	mkdir -p "$repo"
 	(
 		cd "$repo" || error "Cannot setup test environment"
-		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" init \
+		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" \
+			-c init.defaultBranch=${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME-master} init \
 			"--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||
 		error "cannot run git init -- have you built things yet?"
 		mv .git/hooks .git/hooks-disabled
Signature · 1 line
gitgitgadget
#18 lore raw

Re: [PATCH v2 2/4] branch -m: allow renaming a yet-unborn branch

In reply to Johannes Schindelin via GitGitGadget

"Johannes Schindelin via GitGitGadget" <[email protected]>

Review static void copy_or_rename_branch(const char *oldname, const char *newname, int · line 541

Quoted 6 lines · writes:
(quoted diff) +1 -1
@@ -538,7 +538,8 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
 		strbuf_addf(&logmsg, "Branch: renamed %s to %s",
 			    oldref.buf, newref.buf);
 
-	if (!copy && rename_ref(oldref.buf, newref.buf, logmsg.buf))
+	if (!copy && (oldname != head || !is_null_oid(&head_oid)) &&

It always makes readers uneasy to see pointer comparison of two strings.

Does this mean, after "git -c init.defaultbranch=master init",

git branch -m master main

would not work while

git branch -m main

would? It would be easy to see with the attached patch to the test, I guess.

Quoted 9 lines
(quoted diff) +1 -0
+	    rename_ref(oldref.buf, newref.buf, logmsg.buf))
 		die(_("Branch rename failed"));
 	if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf))
 		die(_("Branch copy failed"));
t/t0001-init.sh +0 -0
index 69a320489f..69c5ad179c 100755

t/t0001-init.sh test_expect_success 'invalid default branch name' ' · line 580

Quoted 10 lines
t/t0001-init.sh +6 -0
@@ -571,4 +571,10 @@ test_expect_success 'invalid default branch name' '
 	test_i18ngrep "invalid branch name" err
 '
 
+test_expect_success 'branch -m with the initial branch' '
+	git init rename-initial-branch &&
+	git -C rename-initial-branch branch -m renamed &&
+	test renamed = $(git -C rename-initial-branch symbolic-ref --short HEAD)
+'
+
 test_done

Thanks.

 t/t0001-init.sh | 6 ++++++
 1 file changed, 6 insertions(+)
t/t0001-init.sh +6 -0
index 69c5ad179c..07c34431d9 100755
@@ -577,4 +577,10 @@ test_expect_success 'branch -m with the initial branch' '
 	test renamed = $(git -C rename-initial-branch symbolic-ref --short HEAD)
 '
 
+test_expect_success 'branch -m with the initial branch' '
+	git -c init.defaultBranch=initial init rename-unborn-branch &&
+	git -C rename-unborn-branch branch -m initial renamed &&
+	test renamed = $(git -C rename-unborn-branch symbolic-ref --short HEAD)
+'
+
 test_done
#23 lore raw

Re: [PATCH v2 4/4] init: provide useful advice about init.defaultBranch

In reply to Johannes Schindelin via GitGitGadget

"Johannes Schindelin via GitGitGadget" <[email protected]>

Quoted 4 lines · writes:

+static const char default_branch_name_advice[] = N_(
+"Using '%s' as the name for the initial branch. This default branch name\n" +"is subject to change. To configure the initial branch name to use in all\n" +"of your new repositories, run:\n"

I think this is good, assuming that "subject to change" covers the case where we end up doing nothing after all. I'd feel safer if we said "s/is subject to change/may change in the future/", but this is not a strong preference.

Quoted 6 lines

+"\n"
+"\tgit config --global init.defaultBranch <name>\n"
+"\n"
+"Common names are 'main', 'trunk' and 'development'. If you merely wish\n" +"to suppress this warning, you can also use the current default branch\n" +"name. The current branch can be renamed via this command:\n"

I think this is worse than the previous one. Those who merely wish to suppress the message without wanting to commit to a particular name (i.e. they just want to take whatever the default we give them) would be mislead and be frozen in time forever. We do not give "I'll just accept the default of the day" choice, and that is OK, but we want to be clear about it, which is why I've kept raising this as an issue.

To configure the initial branch name to use in all of your new repositories and squelch this message, run:

may be better---it makes it clear that the offered two choices are
(1) do nothing and see this message every time, or (2) commit to a name and not see this message again.

Thanks.

#19 lore raw

Re: [PATCH v2 2/4] branch -m: allow renaming a yet-unborn branch

In reply to Junio C Hamano

Hi Junio,

Quoted 7 lines · Junio C Hamano

"Johannes Schindelin via GitGitGadget" <[email protected]>

Quoted 4 lines · writes:
(quoted diff) +0 -0
@@ -538,7 +538,8 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
 		strbuf_addf(&logmsg, "Branch: renamed %s to %s",
 			    oldref.buf, newref.buf);
 
Quoted 5 lines

Review static void copy_or_rename_branch(const char *oldname, const char *newname, int · line 541

Quoted 2 lines
(quoted diff) +1 -1
-	if (!copy && rename_ref(oldref.buf, newref.buf, logmsg.buf))
+	if (!copy && (oldname != head || !is_null_oid(&head_oid)) &&

It always makes readers uneasy to see pointer comparison of two strings.

Even if it was on purpose ;-)

Quoted 10 lines

Does this mean, after "git -c init.defaultbranch=master init",

git branch -m master main

would not work while

git branch -m main

would? It would be easy to see with the attached patch to the test, I guess.

At first, I thought that it would be inappropriate to do that because it would not work with unborn branches in a worktree other than the current one. Like,

	git worktree add --no-checkout --detach other
	git -C other switch --orphan start-over-again
	git branch -m start-over-again fresh-new-start

On second thought, that's a really obscure use case, anyway. It is not even possible to create a secondary worktree! I started down that rabbit hole, but think I'd better let it be. This is where I stopped:

-- snip --

builtin/branch.c +11 -2
index 200da319f1d..c84bffe9632 100644
@@ -489,6 +489,16 @@ static void reject_rebase_or_bisect_branch(const char *target)
 	free_worktrees(worktrees);
 }
 
+static int is_unborn_branch(const char *branch_name, const char *full_ref_name)
+{
+	int flags;
+
+	return (head && !strcmp(branch_name, head) && is_null_oid(&head_oid)) ||
+		(!resolve_ref_unsafe(full_ref_name, RESOLVE_REF_READING, NULL,
+				     &flags) &&
+		 find_shared_symref("HEAD", full_ref));
+}
+
 static void copy_or_rename_branch(const char *oldname, const char *newname, int copy, int force)
 {
 	struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT;
@@ -538,8 +548,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
 		strbuf_addf(&logmsg, "Branch: renamed %s to %s",
 			    oldref.buf, newref.buf);
 
-	if (!copy &&
-	    (!head || strcmp(oldname, head) || !is_null_oid(&head_oid)) &&
+	if (!copy && !is_unborn_branch(oldname, oldref.buf) &&
 	    rename_ref(oldref.buf, newref.buf, logmsg.buf))
 		die(_("Branch rename failed"));
 	if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf))
t/t0001-init.sh +8 -0
index 84047ac64e6..124abeedf19 100755
@@ -586,4 +586,12 @@ test_expect_success 'branch -m with the initial branch' '
 	test again = $(git -C rename-initial symbolic-ref --short HEAD)
 '
 
+test_expect_success 'branch -m with the initial branch in another worktree' '
+	git -c init.defaultBranch=initial init rename-two &&
+	test_commit -C rename-two initial &&
+	git -C rename-two worktree add --no-checkout ../rename-worktree &&
+	git -C rename-worktree switch --orphan brand-new-day &&
+	git -C rename-two branch -m brand-new-day renamed
+'
+
 test_done

-- snap --

Having said that, I fixed the git branch -m <current-unborn> <new-name> use case; the fix will be part of v3.

Ciao,
Dscho

#24 lore raw

Re: [PATCH v2 4/4] init: provide useful advice about init.defaultBranch

In reply to Junio C Hamano

Hi Junio,

Quoted 8 lines · Junio C Hamano

"Johannes Schindelin via GitGitGadget" <[email protected]>

Quoted 4 lines · writes:

+static const char default_branch_name_advice[] = N_(
+"Using '%s' as the name for the initial branch. This default branch name\n" +"is subject to change. To configure the initial branch name to use in all\n" +"of your new repositories, run:\n"

Quoted 4 lines

I think this is good, assuming that "subject to change" covers the case where we end up doing nothing after all. I'd feel safer if we said "s/is subject to change/may change in the future/", but this is not a strong preference.

I'd rather keep the current form, as it sounds a bit more firm to me.

Quoted 15 lines
Quoted 6 lines

+"\n"
+"\tgit config --global init.defaultBranch <name>\n"
+"\n"
+"Common names are 'main', 'trunk' and 'development'. If you merely wish\n" +"to suppress this warning, you can also use the current default branch\n" +"name. The current branch can be renamed via this command:\n"

I think this is worse than the previous one. Those who merely wish to suppress the message without wanting to commit to a particular name (i.e. they just want to take whatever the default we give them) would be mislead and be frozen in time forever. We do not give "I'll just accept the default of the day" choice, and that is OK, but we want to be clear about it, which is why I've kept raising this as an issue.

Quoted 6 lines

To configure the initial branch name to use in all of your new repositories and squelch this message, run:

may be better---it makes it clear that the offered two choices are
(1) do nothing and see this message every time, or (2) commit to a name and not see this message again.

Well, I think I finally understand what you are saying: there is a legitimate need for a way to go with Git's preference but still suppress that message.

I introduced advice.defaultBranchName to that end, and now display prominently, at the top of the message, how to use that flag to avoid seeing this advice ever again.

Ciao,
Dscho

#32 lore raw

PATCH v3 1/4 init: document `init.defaultBranch` better

In reply to Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

Our documentation does not mention any future plan to change 'master' to other value. It is a good idea to document this, though.

---
 Documentation/git-init.txt | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
Documentation/git-init.txt +7 -4
index 59ecda6c17..2b399cb73d 100644
@@ -20,8 +20,9 @@ DESCRIPTION
 
 This command creates an empty Git repository - basically a `.git`
 directory with subdirectories for `objects`, `refs/heads`,
-`refs/tags`, and template files.  An initial `HEAD` file that
-references the HEAD of the master branch is also created.
+`refs/tags`, and template files.  An initial branch without any
+commits will be created (see the `--initial-branch` option below
+for its name).
 
 If the `$GIT_DIR` environment variable is set then it specifies a path
 to use instead of `./.git` for the base of the repository.
@@ -73,8 +74,10 @@ If this is reinitialization, the repository will be moved to the specified path.
 -b <branch-name>::
 --initial-branch=<branch-name>::
 
-Use the specified name for the initial branch in the newly created repository.
-If not specified, fall back to the default name: `master`.
+Use the specified name for the initial branch in the newly created
+repository.  If not specified, fall back to the default name (currently
+`master`, but that will be changed in the future; the name can be customized
+via the `init.defaultBranch` configuration variable).
 
 --shared[=(false|true|umask|group|all|world|everybody|0xxx)]::
 
Signature · 1 line
gitgitgadget
#31 lore raw

v3 cover Add helpful advice about init.defaultBranch

In reply to Johannes Schindelin via GitGitGadget

It is our designated intention
[https://sfconservancy.org/news/2020/jun/23/gitbranchname/] to "to explore changing the name of the first branch created automatically for new repositories away from ‘master’". Further, we promised that we "will minimize disruption for Git's users and will include appropriate deprecation periods".

To that end, we first clarify git init's documentation (a lightly edited version of Junio's patch
[https://lore.kernel.org/git/[email protected]]), and then introduce a message giving advice to users running git init that the fall-back for init.defaultBranch is subject to change, and how to override Git's fall-back manually.

The beauty of this patch series, if I may say so, is that it does not commit us to any concrete plan, but opens the door for all options regarding the default branch name.

Changes since v2:

* git branch -m <initial> <renamed> now works, too
* The config setting advice.defaultBranchName was introduced to allow suppressing this warning specifically
* The advice now first talks about the current default branch name, then how to suppress the advice, and only then explains how to override the default branch name (and that that will also prevent the message from being shown)

Changes since v1:

* Grammar fix
* Reworded advice and commit messages
* test_create_repo already respected GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME, but now does so more obviously
* Allowed git branch -m <name> to rename unborn branches, so that the advice actually works

Johannes Schindelin (4):
init: document init.defaultBranch better branch -m: allow renaming a yet-unborn branch get_default_branch_name(): prepare for showing some advice
init: provide useful advice about init.defaultBranch

 Documentation/git-init.txt | 11 +++++++----
 advice.c                   |  1 +
 advice.h                   |  1 +
 builtin/branch.c           |  4 +++-
 builtin/clone.c            |  2 +-
 builtin/init-db.c          |  8 +++++---
 refs.c                     | 29 +++++++++++++++++++++++++----
 refs.h                     |  4 ++--
 remote.c                   |  5 +++--
 t/t0001-init.sh            | 17 ++++++++++++++++-
 t/t1510-repo-setup.sh      |  2 +-
 t/test-lib-functions.sh    |  3 ++-
 12 files changed, 67 insertions(+), 20 deletions(-)

base-commit: faefdd61ec7c7f6f3c8c9907891465ac9a2a1475
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-921%2Fdscho%2Finit.defaultBranch-advice-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-921/dscho/init.defaultBranch-advice-v3
Pull-Request: https://github.com/git/git/pull/921

Range-diff vs v2:

 1:  483e490349 = 1:  483e490349 init: document `init.defaultBranch` better
 2:  8de0c0eb22 ! 2:  6cbd6692c6 branch -m: allow renaming a yet-unborn branch
     @@ builtin/branch.c: static void copy_or_rename_branch(const char *oldname, const c
       			    oldref.buf, newref.buf);
       
      -	if (!copy && rename_ref(oldref.buf, newref.buf, logmsg.buf))
     -+	if (!copy && (oldname != head || !is_null_oid(&head_oid)) &&
     ++	if (!copy &&
     ++	    (!head || strcmp(oldname, head) || !is_null_oid(&head_oid)) &&
      +	    rename_ref(oldref.buf, newref.buf, logmsg.buf))
       		die(_("Branch rename failed"));
       	if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf))
     @@ t/t0001-init.sh: test_expect_success 'invalid default branch name' '
       '
       
      +test_expect_success 'branch -m with the initial branch' '
     -+	git init rename-initial-branch &&
     -+	git -C rename-initial-branch branch -m renamed &&
     -+	test renamed = $(git -C rename-initial-branch symbolic-ref --short HEAD)
     ++	git init rename-initial &&
     ++	git -C rename-initial branch -m renamed &&
     ++	test renamed = $(git -C rename-initial symbolic-ref --short HEAD) &&
     ++	git -C rename-initial branch -m renamed again &&
     ++	test again = $(git -C rename-initial symbolic-ref --short HEAD)
      +'
      +
       test_done
 3:  03314f7ac6 = 3:  5fc15f7b9a get_default_branch_name(): prepare for showing some advice
 4:  bccef95391 ! 4:  87c9306877 init: provide useful advice about init.defaultBranch
     @@ Commit message
          `git init` when that value is not set.
      
          Note: two test cases in Git's test suite want to verify that the
     -    `stderr` output of `git init` is empty. With this patch, that is only
     -    true if `init.defaultBranch` is configured, so let's do exactly that in
     -    those test cases. The same reasoning applies to `test_create_repo()`.
     +    `stderr` output of `git init` is empty. It is now necessary to suppress
     +    the advice using the newly-added `advice.defaultBranchName` setting.
     +    While not strictly necessary, we also set this to `false` in
     +    `test_create_repo()`.
      
          Signed-off-by: Johannes Schindelin <[email protected]>
      
     + ## advice.c ##
     +@@ advice.c: static struct {
     + 	[ADVICE_AM_WORK_DIR] 				= { "amWorkDir", 1 },
     + 	[ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] 	= { "checkoutAmbiguousRemoteBranchName", 1 },
     + 	[ADVICE_COMMIT_BEFORE_MERGE]			= { "commitBeforeMerge", 1 },
     ++	[ADVICE_DEFAULT_BRANCH_NAME]			= { "defaultBranchName", 1 },
     + 	[ADVICE_DETACHED_HEAD]				= { "detachedHead", 1 },
     + 	[ADVICE_FETCH_SHOW_FORCED_UPDATES]		= { "fetchShowForcedUpdates", 1 },
     + 	[ADVICE_GRAFT_FILE_DEPRECATED]			= { "graftFileDeprecated", 1 },
     +
     + ## advice.h ##
     +@@ advice.h: extern int advice_add_empty_pathspec;
     + 	ADVICE_AM_WORK_DIR,
     + 	ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME,
     + 	ADVICE_COMMIT_BEFORE_MERGE,
     ++	ADVICE_DEFAULT_BRANCH_NAME,
     + 	ADVICE_DETACHED_HEAD,
     + 	ADVICE_FETCH_SHOW_FORCED_UPDATES,
     + 	ADVICE_GRAFT_FILE_DEPRECATED,
     +
       ## refs.c ##
     +@@
     + #include "strvec.h"
     + #include "repository.h"
     + #include "sigchain.h"
     ++#include "advice.h"
     + 
     + /*
     +  * List of all available backends
      @@ refs.c: void expand_ref_prefix(struct strvec *prefixes, const char *prefix)
       		strvec_pushf(prefixes, *p, len, prefix);
       }
       
      +static const char default_branch_name_advice[] = N_(
      +"Using '%s' as the name for the initial branch. This default branch name\n"
     -+"is subject to change. To configure the initial branch name to use in all\n"
     -+"of your new repositories, run:\n"
     ++"is subject to change. To suppress this warning, run:\n"
     ++"\n"
     ++"\tgit config --global advice.defaultBranchName false\n"
     ++"\n"
     ++"Alternatively, you can configure the initial branch name to use in all\n"
     ++"of your new repositories, which will also suppress this warning:\n"
      +"\n"
      +"\tgit config --global init.defaultBranch <name>\n"
      +"\n"
     -+"Common names are 'main', 'trunk' and 'development'. If you merely wish\n"
     -+"to suppress this warning, you can also use the current default branch\n"
     -+"name. The current branch can be renamed via this command:\n"
     ++"Common names are 'main', 'trunk' and 'development'. The initial branch\n"
     ++"that was created can be renamed via this command:\n"
      +"\n"
      +"\tgit branch -m <name>\n"
      +);
     @@ refs.c: char *repo_default_branch_name(struct repository *r, int quiet)
      -	if (!ret)
      +	if (!ret) {
       		ret = xstrdup("master");
     -+		if (!quiet)
     ++		if (!quiet && advice_enabled(ADVICE_DEFAULT_BRANCH_NAME))
      +			advise(_(default_branch_name_advice), ret);
      +	}
       
     @@ t/t0001-init.sh: test_expect_success 'reinit' '
       		mkdir again &&
       		cd again &&
      -		git init >out1 2>err1 &&
     -+		git -c init.defaultBranch=initial init >out1 2>err1 &&
     ++		git -c advice.defaultBranchName=false init >out1 2>err1 &&
       		git init >out2 2>err2
       	) &&
       	test_i18ngrep "Initialized empty" again/out1 &&
     @@ t/t1510-repo-setup.sh: setup_repo () {
       	sane_unset GIT_DIR GIT_WORK_TREE &&
       
      -	git init "$name" &&
     -+	git -c init.defaultBranch=repo init "$name" &&
     ++	git -c advice.defaultBranchName=false init "$name" &&
       	maybe_config "$name/.git/config" core.worktree "$worktreecfg" &&
       	maybe_config "$name/.git/config" core.bare "$barecfg" &&
       	mkdir -p "$name/sub/sub" &&
     @@ t/test-lib-functions.sh: test_create_repo () {
       		cd "$repo" || error "Cannot setup test environment"
      -		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" init \
      +		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" \
     -+			-c init.defaultBranch=${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME-master} init \
     ++			-c advice.defaultBranchName=false init \
       			"--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||
       		error "cannot run git init -- have you built things yet?"
       		mv .git/hooks .git/hooks-disabled
Signature · 1 line
gitgitgadget
#33 lore raw

PATCH v3 2/4 branch -m: allow renaming a yet-unborn branch

From: Johannes Schindelin <[email protected]>

In one of the next commits, we would like to give users some advice regarding the initial branch name, and how to modify it.

To that end, it would be good if git branch -m <name> worked in a freshly initialized repository without any commits. Let's make it so.

---
 builtin/branch.c | 4 +++-
 t/t0001-init.sh  | 8 ++++++++
 2 files changed, 11 insertions(+), 1 deletion(-)
builtin/branch.c +3 -1
index efb30b8820..200da319f1 100644
@@ -538,7 +538,9 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
 		strbuf_addf(&logmsg, "Branch: renamed %s to %s",
 			    oldref.buf, newref.buf);
 
-	if (!copy && rename_ref(oldref.buf, newref.buf, logmsg.buf))
+	if (!copy &&
+	    (!head || strcmp(oldname, head) || !is_null_oid(&head_oid)) &&
+	    rename_ref(oldref.buf, newref.buf, logmsg.buf))
 		die(_("Branch rename failed"));
 	if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf))
 		die(_("Branch copy failed"));
t/t0001-init.sh +8 -0
index 69a320489f..bb23e56a16 100755
@@ -571,4 +571,12 @@ test_expect_success 'invalid default branch name' '
 	test_i18ngrep "invalid branch name" err
 '
 
+test_expect_success 'branch -m with the initial branch' '
+	git init rename-initial &&
+	git -C rename-initial branch -m renamed &&
+	test renamed = $(git -C rename-initial symbolic-ref --short HEAD) &&
+	git -C rename-initial branch -m renamed again &&
+	test again = $(git -C rename-initial symbolic-ref --short HEAD)
+'
+
 test_done
Signature · 1 line
gitgitgadget
#35 lore raw

PATCH v3 4/4 init: provide useful advice about init.defaultBranch

In reply to Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

To give ample warning for users wishing to override Git's the fall-back for an unconfigured init.defaultBranch (in case we decide to change it in a future Git version), let's introduce some advice that is shown upon git init when that value is not set.

Note: two test cases in Git's test suite want to verify that the stderr output of git init is empty. It is now necessary to suppress the advice using the newly-added advice.defaultBranchName setting. While not strictly necessary, we also set this to false in test_create_repo().

---
 advice.c                |  1 +
 advice.h                |  1 +
 refs.c                  | 23 ++++++++++++++++++++++-
 t/t0001-init.sh         |  9 ++++++++-
 t/t1510-repo-setup.sh   |  2 +-
 t/test-lib-functions.sh |  3 ++-
 6 files changed, 35 insertions(+), 4 deletions(-)
advice.c +1 -0
index 164742305f..8a14640193 100644
@@ -108,6 +108,7 @@ static struct {
 	[ADVICE_AM_WORK_DIR] 				= { "amWorkDir", 1 },
 	[ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] 	= { "checkoutAmbiguousRemoteBranchName", 1 },
 	[ADVICE_COMMIT_BEFORE_MERGE]			= { "commitBeforeMerge", 1 },
+	[ADVICE_DEFAULT_BRANCH_NAME]			= { "defaultBranchName", 1 },
 	[ADVICE_DETACHED_HEAD]				= { "detachedHead", 1 },
 	[ADVICE_FETCH_SHOW_FORCED_UPDATES]		= { "fetchShowForcedUpdates", 1 },
 	[ADVICE_GRAFT_FILE_DEPRECATED]			= { "graftFileDeprecated", 1 },
advice.h +1 -0
index bc2432980a..1ae99a1b31 100644
@@ -46,6 +46,7 @@ extern int advice_add_empty_pathspec;
 	ADVICE_AM_WORK_DIR,
 	ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME,
 	ADVICE_COMMIT_BEFORE_MERGE,
+	ADVICE_DEFAULT_BRANCH_NAME,
 	ADVICE_DETACHED_HEAD,
 	ADVICE_FETCH_SHOW_FORCED_UPDATES,
 	ADVICE_GRAFT_FILE_DEPRECATED,
refs.c +22 -1
index 8df03122d6..c56bc1bcfb 100644
@@ -18,6 +18,7 @@
 #include "strvec.h"
 #include "repository.h"
 #include "sigchain.h"
+#include "advice.h"
 
 /*
  * List of all available backends
@@ -562,6 +563,23 @@ void expand_ref_prefix(struct strvec *prefixes, const char *prefix)
 		strvec_pushf(prefixes, *p, len, prefix);
 }
 
+static const char default_branch_name_advice[] = N_(
+"Using '%s' as the name for the initial branch. This default branch name\n"
+"is subject to change. To suppress this warning, run:\n"
+"\n"
+"\tgit config --global advice.defaultBranchName false\n"
+"\n"
+"Alternatively, you can configure the initial branch name to use in all\n"
+"of your new repositories, which will also suppress this warning:\n"
+"\n"
+"\tgit config --global init.defaultBranch <name>\n"
+"\n"
+"Common names are 'main', 'trunk' and 'development'. The initial branch\n"
+"that was created can be renamed via this command:\n"
+"\n"
+"\tgit branch -m <name>\n"
+);
+
 char *repo_default_branch_name(struct repository *r, int quiet)
 {
 	const char *config_key = "init.defaultbranch";
@@ -574,8 +592,11 @@ char *repo_default_branch_name(struct repository *r, int quiet)
 	else if (repo_config_get_string(r, config_key, &ret) < 0)
 		die(_("could not retrieve `%s`"), config_display_key);
 
-	if (!ret)
+	if (!ret) {
 		ret = xstrdup("master");
+		if (!quiet && advice_enabled(ADVICE_DEFAULT_BRANCH_NAME))
+			advise(_(default_branch_name_advice), ret);
+	}
 
 	full_ref = xstrfmt("refs/heads/%s", ret);
 	if (check_refname_format(full_ref, 0))
t/t0001-init.sh +8 -1
index bb23e56a16..84047ac64e 100755
@@ -163,7 +163,7 @@ test_expect_success 'reinit' '
 	(
 		mkdir again &&
 		cd again &&
-		git init >out1 2>err1 &&
+		git -c advice.defaultBranchName=false init >out1 2>err1 &&
 		git init >out2 2>err2
 	) &&
 	test_i18ngrep "Initialized empty" again/out1 &&
@@ -558,6 +558,13 @@ test_expect_success 'overridden default initial branch name (config)' '
 	grep nmb actual
 '
 
+test_expect_success 'advice on unconfigured init.defaultBranch' '
+	GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= git -c color.advice=always \
+		init unconfigured-default-branch-name 2>err &&
+	test_decode_color <err >decoded &&
+	test_i18ngrep "<YELLOW>hint: " decoded
+'
+
 test_expect_success 'overridden default main branch name (env)' '
 	test_config_global init.defaultBranch nmb &&
 	GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=env git init main-branch-env &&
t/t1510-repo-setup.sh +1 -1
index 9974457f56..5305566167 100755
@@ -79,7 +79,7 @@ setup_repo () {
 	name=$1 worktreecfg=$2 gitfile=$3 barecfg=$4 &&
 	sane_unset GIT_DIR GIT_WORK_TREE &&
 
-	git init "$name" &&
+	git -c advice.defaultBranchName=false init "$name" &&
 	maybe_config "$name/.git/config" core.worktree "$worktreecfg" &&
 	maybe_config "$name/.git/config" core.bare "$barecfg" &&
 	mkdir -p "$name/sub/sub" &&
t/test-lib-functions.sh +2 -1
index 59bbf75e83..781d47a4bb 100644
@@ -1202,7 +1202,8 @@ test_create_repo () {
 	mkdir -p "$repo"
 	(
 		cd "$repo" || error "Cannot setup test environment"
-		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" init \
+		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" \
+			-c advice.defaultBranchName=false init \
 			"--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||
 		error "cannot run git init -- have you built things yet?"
 		mv .git/hooks .git/hooks-disabled
Signature · 1 line
gitgitgadget
#34 lore raw

PATCH v3 3/4 get_default_branch_name(): prepare for showing some advice

In reply to Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

We are about to introduce a message giving users running git init some advice about init.defaultBranch. This will necessarily be done in repo_default_branch_name().

Not all code paths want to show that advice, though. In particular, the git clone codepath _specifically_ asks for init_db() to be quiet, via the INIT_DB_QUIET flag.

In preparation for showing users above-mentioned advice, let's change the function signature of get_default_branch_name() to accept the parameter quiet.

---
 builtin/clone.c   | 2 +-
 builtin/init-db.c | 8 +++++---
 refs.c            | 6 +++---
 refs.h            | 4 ++--
 remote.c          | 5 +++--
 5 files changed, 14 insertions(+), 11 deletions(-)
builtin/clone.c +1 -1
index a0841923cf..64b1784011 100644
@@ -1323,7 +1323,7 @@ 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();
+			const char *branch = git_default_branch_name(0);
 			char *ref = xstrfmt("refs/heads/%s", branch);
 
 			install_branch_config(0, branch, remote_name, ref);
builtin/init-db.c +5 -3
index 01bc648d41..dcc45bef51 100644
@@ -202,7 +202,8 @@ void initialize_repository_version(int hash_algo, int reinit)
 static int create_default_files(const char *template_path,
 				const char *original_git_dir,
 				const char *initial_branch,
-				const struct repository_format *fmt)
+				const struct repository_format *fmt,
+				int quiet)
 {
 	struct stat st1;
 	struct strbuf buf = STRBUF_INIT;
@@ -267,7 +268,7 @@ static int create_default_files(const char *template_path,
 		char *ref;
 
 		if (!initial_branch)
-			initial_branch = git_default_branch_name();
+			initial_branch = git_default_branch_name(quiet);
 
 		ref = xstrfmt("refs/heads/%s", initial_branch);
 		if (check_refname_format(ref, 0) < 0)
@@ -438,7 +439,8 @@ int init_db(const char *git_dir, const char *real_git_dir,
 	validate_hash_algorithm(&repo_fmt, hash);
 
 	reinit = create_default_files(template_dir, original_git_dir,
-				      initial_branch, &repo_fmt);
+				      initial_branch, &repo_fmt,
+				      flags & INIT_DB_QUIET);
 	if (reinit && initial_branch)
 		warning(_("re-init: ignored --initial-branch=%s"),
 			initial_branch);
refs.c +3 -3
index 392f0bbf68..8df03122d6 100644
@@ -562,7 +562,7 @@ void expand_ref_prefix(struct strvec *prefixes, const char *prefix)
 		strvec_pushf(prefixes, *p, len, prefix);
 }
 
-char *repo_default_branch_name(struct repository *r)
+char *repo_default_branch_name(struct repository *r, int quiet)
 {
 	const char *config_key = "init.defaultbranch";
 	const char *config_display_key = "init.defaultBranch";
@@ -585,12 +585,12 @@ char *repo_default_branch_name(struct repository *r)
 	return ret;
 }
 
-const char *git_default_branch_name(void)
+const char *git_default_branch_name(int quiet)
 {
 	static char *ret;
 
 	if (!ret)
-		ret = repo_default_branch_name(the_repository);
+		ret = repo_default_branch_name(the_repository, quiet);
 
 	return ret;
 }
refs.h +2 -2
index 6695518156..ff05d2e9fe 100644
@@ -170,8 +170,8 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **ref);
  * The return value of `repo_default_branch_name()` is an allocated string. The
  * return value of `git_default_branch_name()` is a singleton.
  */
-const char *git_default_branch_name(void);
-char *repo_default_branch_name(struct repository *r);
+const char *git_default_branch_name(int quiet);
+char *repo_default_branch_name(struct repository *r, int quiet);
 
 /*
  * A ref_transaction represents a collection of reference updates that
remote.c +3 -2
index 8a6dbbb903..bdb88d4b7d 100644
@@ -284,7 +284,7 @@ static void read_branches_file(struct remote *remote)
 	if (frag)
 		*(frag++) = '\0';
 	else
-		frag = (char *)git_default_branch_name();
+		frag = (char *)git_default_branch_name(0);
 
 	add_url_alias(remote, strbuf_detach(&buf, NULL));
 	refspec_appendf(&remote->fetch, "refs/heads/%s:refs/heads/%s",
@@ -2206,7 +2206,8 @@ struct ref *guess_remote_head(const struct ref *head,
 
 	/* If a remote branch exists with the default branch name, let's use it. */
 	if (!all) {
-		char *ref = xstrfmt("refs/heads/%s", git_default_branch_name());
+		char *ref = xstrfmt("refs/heads/%s",
+				    git_default_branch_name(0));
 
 		r = find_ref_by_name(refs, ref);
 		free(ref);
Signature · 1 line
gitgitgadget
#20 lore raw

Re: [PATCH v2 2/4] branch -m: allow renaming a yet-unborn branch

In reply to Johannes Schindelin
Quoted 7 lines · Johannes Schindelin
Quoted 5 lines

Review

Quoted 2 lines
(quoted diff) +1 -1
-	if (!copy && rename_ref(oldref.buf, newref.buf, logmsg.buf))
+	if (!copy && (oldname != head || !is_null_oid(&head_oid)) &&

It always makes readers uneasy to see pointer comparison of two strings.

Even if it was on purpose ;-)

FWIW, for fun I dropped "oldname != head ||" and tried to run the whole testsuite (plus the "branch -m src dst" form test I gave earlier), and it almost passed all of them except one, which was surprising.

builtin/branch.c static void copy_or_rename_branch(const char *oldname, const char *newname, int · line 552

Quoted 2 lines
builtin/branch.c +1 -0
+	if (!copy && !is_unborn_branch(oldname, oldref.buf) &&
 	    rename_ref(oldref.buf, newref.buf, logmsg.buf))

Yeah, a helper function makes it much more clear what is going on.

Quoted 2 lines

Having said that, I fixed the git branch -m <current-unborn> <new-name> use case; the fix will be part of v3.

;-)

#25 lore raw

Re: [PATCH v2 4/4] init: provide useful advice about init.defaultBranch

In reply to Johannes Schindelin
Quoted 10 lines · Johannes Schindelin
Quoted 6 lines

To configure the initial branch name to use in all of your new repositories and squelch this message, run:

may be better---it makes it clear that the offered two choices are
(1) do nothing and see this message every time, or (2) commit to a name and not see this message again.

Well, I think I finally understand what you are saying: there is a legitimate need for a way to go with Git's preference but still suppress that message.

I am not saying it is a legitimate need. I just wanted to make it clear that we deliberately chose not to grant that wish in the message. An advice flag in this context means that the users can choose to let their distro and sysadm to flip the default silently, which is much worse than having to see the message every time they start a new repository with "git init".

#26 lore raw

Re: [PATCH v2 4/4] init: provide useful advice about init.defaultBranch

Hi Junio,

Quoted 13 lines · Junio C Hamano
Quoted 10 lines · Johannes Schindelin
Quoted 6 lines

To configure the initial branch name to use in all of your new repositories and squelch this message, run:

may be better---it makes it clear that the offered two choices are
(1) do nothing and see this message every time, or (2) commit to a name and not see this message again.

Well, I think I finally understand what you are saying: there is a legitimate need for a way to go with Git's preference but still suppress that message.

Quoted 6 lines

I am not saying it is a legitimate need. I just wanted to make it clear that we deliberately chose not to grant that wish in the message. An advice flag in this context means that the users can choose to let their distro and sysadm to flip the default silently, which is much worse than having to see the message every time they start a new repository with "git init".

The distribution already can add patches, so this objection is a red herring. The sysadm can pick a different value for init.defaultBranch and dictate to the user silently what initial branch name to use, so that is also a red herring.

I still think that there is a legitimate need for this config option to turn the advice off, without having to override Git's default branch name.

In particular in this context, I would think that most users will want to just go with whatever is Git's default.

Ciao,
Dscho

#27 lore raw

Re: [PATCH v2 4/4] init: provide useful advice about init.defaultBranch

Quoted 9 lines · Johannes Schindelin
Quoted 6 lines · Junio C Hamano

I am not saying it is a legitimate need. I just wanted to make it clear that we deliberately chose not to grant that wish in the message. An advice flag in this context means that the users can choose to let their distro and sysadm to flip the default silently, which is much worse than having to see the message every time they start a new repository with "git init".

Quoted 4 lines

The distribution already can add patches, so this objection is a red herring. The sysadm can pick a different value for init.defaultBranch and dictate to the user silently what initial branch name to use, so that is also a red herring.

The "setting init.defaultBranch is the only way to squelch" approach means the ~/.gitconfig will have the settings soon after the user starts using Git and /etc/gitconfig will not allow administrators to force their will over what the user decides to use. Distros adding patches to strip configurability by setting init.defaultBranch in user's ~/.gitconfig? Is that the kind of possibilities worth discussing?

So, no, your counter-argument above is nothing but a red-herring.

If you want a counter-argument, please explain why "I am fine to see the default flipped to whatever the tool picks and having no control over when the flipping happens" can be a sensible choice for users with what kind of workflows. The only folks I can think of who would be fine with that are (1) those who do not create the second branch in the repository and will stay on the primary branch forever, and (2) those who immediately rename the branch to what they want after "git init". For other folks, such a choice is a disaster waiting to happen, and it just feels irresponsible to offer such a choice, at least to me.

Thanks.

#30 lore raw

Re: [PATCH v2 4/4] init: provide useful advice about init.defaultBranch

In reply to Johannes Schindelin
Quoted 6 lines · Johannes Schindelin

On Tue, 24 Nov 2020, Junio C Hamano wrote:

The distribution already can add patches, so this objection is a red herring. The sysadm can pick a different value for init.defaultBranch and dictate to the user silently what initial branch name to use, so that is also a red herring.

Yes, but if they do; they have picked the ball. The user would blame them--and not Git--for any unexpected change in behavior.

Cheers.

Signature · 1 line
Felipe Contreras
#36 lore raw

v4 cover Add helpful advice about init.defaultBranch

In reply to Johannes Schindelin via GitGitGadget

It is our designated intention
[https://sfconservancy.org/news/2020/jun/23/gitbranchname/] to "to explore changing the name of the first branch created automatically for new repositories away from ‘master’". Further, we promised that we "will minimize disruption for Git's users and will include appropriate deprecation periods".

To that end, we first clarify git init's documentation (a lightly edited version of Junio's patch
[https://lore.kernel.org/git/[email protected]]), and then introduce a message giving advice to users running git init that the fall-back for init.defaultBranch is subject to change, and how to override Git's fall-back manually.

The beauty of this patch series, if I may say so, is that it does not commit us to any concrete plan, but opens the door for all options regarding the default branch name.

Changes since v3:

* Kicked out advice.defaultBranchName again. The advice can now only be suppressed by setting init.defaultBranch.

Changes since v2:

* git branch -m <initial> <renamed> now works, too
* The config setting advice.defaultBranchName was introduced to allow suppressing this warning specifically
* The advice now first talks about the current default branch name, then how to suppress the advice, and only then explains how to override the default branch name (and that that will also prevent the message from being shown)

Changes since v1:

* Grammar fix
* Reworded advice and commit messages
* test_create_repo already respected GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME, but now does so more obviously
* Allowed git branch -m <name> to rename unborn branches, so that the advice actually works

Johannes Schindelin (4):
init: document init.defaultBranch better branch -m: allow renaming a yet-unborn branch get_default_branch_name(): prepare for showing some advice
init: provide useful advice about init.defaultBranch

 Documentation/git-init.txt | 11 +++++++----
 builtin/branch.c           |  4 +++-
 builtin/clone.c            |  2 +-
 builtin/init-db.c          |  8 +++++---
 refs.c                     | 24 ++++++++++++++++++++----
 refs.h                     |  4 ++--
 remote.c                   |  5 +++--
 t/t0001-init.sh            | 17 ++++++++++++++++-
 t/t1510-repo-setup.sh      |  2 +-
 t/test-lib-functions.sh    |  4 +++-
 10 files changed, 61 insertions(+), 20 deletions(-)

base-commit: faefdd61ec7c7f6f3c8c9907891465ac9a2a1475
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-921%2Fdscho%2Finit.defaultBranch-advice-v4
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-921/dscho/init.defaultBranch-advice-v4
Pull-Request: https://github.com/git/git/pull/921

Range-diff vs v3:

 1:  483e4903491 = 1:  483e4903491 init: document `init.defaultBranch` better
 2:  6cbd6692c6a = 2:  6cbd6692c6a branch -m: allow renaming a yet-unborn branch
 3:  5fc15f7b9ad = 3:  5fc15f7b9ad get_default_branch_name(): prepare for showing some advice
 4:  87c93068771 ! 4:  2f21c505d56 init: provide useful advice about init.defaultBranch
     @@ Commit message
      
          Note: two test cases in Git's test suite want to verify that the
          `stderr` output of `git init` is empty. It is now necessary to suppress
     -    the advice using the newly-added `advice.defaultBranchName` setting.
     -    While not strictly necessary, we also set this to `false` in
     +    the advice, we now do that via the `init.defaultBranch` setting. While
     +    not strictly necessary, we also set this to `false` in
          `test_create_repo()`.
      
          Signed-off-by: Johannes Schindelin <[email protected]>
      
     - ## advice.c ##
     -@@ advice.c: static struct {
     - 	[ADVICE_AM_WORK_DIR] 				= { "amWorkDir", 1 },
     - 	[ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] 	= { "checkoutAmbiguousRemoteBranchName", 1 },
     - 	[ADVICE_COMMIT_BEFORE_MERGE]			= { "commitBeforeMerge", 1 },
     -+	[ADVICE_DEFAULT_BRANCH_NAME]			= { "defaultBranchName", 1 },
     - 	[ADVICE_DETACHED_HEAD]				= { "detachedHead", 1 },
     - 	[ADVICE_FETCH_SHOW_FORCED_UPDATES]		= { "fetchShowForcedUpdates", 1 },
     - 	[ADVICE_GRAFT_FILE_DEPRECATED]			= { "graftFileDeprecated", 1 },
     -
     - ## advice.h ##
     -@@ advice.h: extern int advice_add_empty_pathspec;
     - 	ADVICE_AM_WORK_DIR,
     - 	ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME,
     - 	ADVICE_COMMIT_BEFORE_MERGE,
     -+	ADVICE_DEFAULT_BRANCH_NAME,
     - 	ADVICE_DETACHED_HEAD,
     - 	ADVICE_FETCH_SHOW_FORCED_UPDATES,
     - 	ADVICE_GRAFT_FILE_DEPRECATED,
     -
       ## refs.c ##
     -@@
     - #include "strvec.h"
     - #include "repository.h"
     - #include "sigchain.h"
     -+#include "advice.h"
     - 
     - /*
     -  * List of all available backends
      @@ refs.c: void expand_ref_prefix(struct strvec *prefixes, const char *prefix)
       		strvec_pushf(prefixes, *p, len, prefix);
       }
       
      +static const char default_branch_name_advice[] = N_(
      +"Using '%s' as the name for the initial branch. This default branch name\n"
     -+"is subject to change. To suppress this warning, run:\n"
     -+"\n"
     -+"\tgit config --global advice.defaultBranchName false\n"
     -+"\n"
     -+"Alternatively, you can configure the initial branch name to use in all\n"
     -+"of your new repositories, which will also suppress this warning:\n"
     ++"is subject to change. To configure the initial branch name to use in all\n"
     ++"of your new repositories, which will suppress this warning, call:\n"
      +"\n"
      +"\tgit config --global init.defaultBranch <name>\n"
      +"\n"
     @@ refs.c: char *repo_default_branch_name(struct repository *r, int quiet)
      -	if (!ret)
      +	if (!ret) {
       		ret = xstrdup("master");
     -+		if (!quiet && advice_enabled(ADVICE_DEFAULT_BRANCH_NAME))
     ++		if (!quiet)
      +			advise(_(default_branch_name_advice), ret);
      +	}
       
     @@ t/t0001-init.sh: test_expect_success 'reinit' '
       		mkdir again &&
       		cd again &&
      -		git init >out1 2>err1 &&
     -+		git -c advice.defaultBranchName=false init >out1 2>err1 &&
     ++		git -c init.defaultBranch=initial init >out1 2>err1 &&
       		git init >out2 2>err2
       	) &&
       	test_i18ngrep "Initialized empty" again/out1 &&
     @@ t/t1510-repo-setup.sh: setup_repo () {
       	sane_unset GIT_DIR GIT_WORK_TREE &&
       
      -	git init "$name" &&
     -+	git -c advice.defaultBranchName=false init "$name" &&
     ++	git -c init.defaultBranch=initial init "$name" &&
       	maybe_config "$name/.git/config" core.worktree "$worktreecfg" &&
       	maybe_config "$name/.git/config" core.bare "$barecfg" &&
       	mkdir -p "$name/sub/sub" &&
     @@ t/test-lib-functions.sh: test_create_repo () {
       	(
       		cd "$repo" || error "Cannot setup test environment"
      -		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" init \
     -+		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" \
     -+			-c advice.defaultBranchName=false init \
     ++		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" -c \
     ++			init.defaultBranch="${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME-master}" \
     ++			init \
       			"--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||
       		error "cannot run git init -- have you built things yet?"
       		mv .git/hooks .git/hooks-disabled
Signature · 1 line
gitgitgadget
#44 lore raw

PATCH v4 4/4 init: provide useful advice about init.defaultBranch

From: Johannes Schindelin <[email protected]>

To give ample warning for users wishing to override Git's the fall-back for an unconfigured init.defaultBranch (in case we decide to change it in a future Git version), let's introduce some advice that is shown upon git init when that value is not set.

Note: two test cases in Git's test suite want to verify that the stderr output of git init is empty. It is now necessary to suppress the advice, we now do that via the init.defaultBranch setting. While not strictly necessary, we also set this to false in test_create_repo().

---
 refs.c                  | 18 +++++++++++++++++-
 t/t0001-init.sh         |  9 ++++++++-
 t/t1510-repo-setup.sh   |  2 +-
 t/test-lib-functions.sh |  4 +++-
 4 files changed, 29 insertions(+), 4 deletions(-)
refs.c +17 -1
index 8df03122d69..6e047b3d1b4 100644
@@ -562,6 +562,19 @@ void expand_ref_prefix(struct strvec *prefixes, const char *prefix)
 		strvec_pushf(prefixes, *p, len, prefix);
 }
 
+static const char default_branch_name_advice[] = N_(
+"Using '%s' as the name for the initial branch. This default branch name\n"
+"is subject to change. To configure the initial branch name to use in all\n"
+"of your new repositories, which will suppress this warning, call:\n"
+"\n"
+"\tgit config --global init.defaultBranch <name>\n"
+"\n"
+"Common names are 'main', 'trunk' and 'development'. The initial branch\n"
+"that was created can be renamed via this command:\n"
+"\n"
+"\tgit branch -m <name>\n"
+);
+
 char *repo_default_branch_name(struct repository *r, int quiet)
 {
 	const char *config_key = "init.defaultbranch";
@@ -574,8 +587,11 @@ char *repo_default_branch_name(struct repository *r, int quiet)
 	else if (repo_config_get_string(r, config_key, &ret) < 0)
 		die(_("could not retrieve `%s`"), config_display_key);
 
-	if (!ret)
+	if (!ret) {
 		ret = xstrdup("master");
+		if (!quiet)
+			advise(_(default_branch_name_advice), ret);
+	}
 
 	full_ref = xstrfmt("refs/heads/%s", ret);
 	if (check_refname_format(full_ref, 0))
t/t0001-init.sh +8 -1
index bb23e56a165..0803994874f 100755
@@ -163,7 +163,7 @@ test_expect_success 'reinit' '
 	(
 		mkdir again &&
 		cd again &&
-		git init >out1 2>err1 &&
+		git -c init.defaultBranch=initial init >out1 2>err1 &&
 		git init >out2 2>err2
 	) &&
 	test_i18ngrep "Initialized empty" again/out1 &&
@@ -558,6 +558,13 @@ test_expect_success 'overridden default initial branch name (config)' '
 	grep nmb actual
 '
 
+test_expect_success 'advice on unconfigured init.defaultBranch' '
+	GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= git -c color.advice=always \
+		init unconfigured-default-branch-name 2>err &&
+	test_decode_color <err >decoded &&
+	test_i18ngrep "<YELLOW>hint: " decoded
+'
+
 test_expect_success 'overridden default main branch name (env)' '
 	test_config_global init.defaultBranch nmb &&
 	GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=env git init main-branch-env &&
t/t1510-repo-setup.sh +1 -1
index 9974457f561..bbfe05b8e4a 100755
@@ -79,7 +79,7 @@ setup_repo () {
 	name=$1 worktreecfg=$2 gitfile=$3 barecfg=$4 &&
 	sane_unset GIT_DIR GIT_WORK_TREE &&
 
-	git init "$name" &&
+	git -c init.defaultBranch=initial init "$name" &&
 	maybe_config "$name/.git/config" core.worktree "$worktreecfg" &&
 	maybe_config "$name/.git/config" core.bare "$barecfg" &&
 	mkdir -p "$name/sub/sub" &&
t/test-lib-functions.sh +3 -1
index 59bbf75e832..9910102ae1f 100644
@@ -1202,7 +1202,9 @@ test_create_repo () {
 	mkdir -p "$repo"
 	(
 		cd "$repo" || error "Cannot setup test environment"
-		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" init \
+		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" -c \
+			init.defaultBranch="${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME-master}" \
+			init \
 			"--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||
 		error "cannot run git init -- have you built things yet?"
 		mv .git/hooks .git/hooks-disabled
Signature · 1 line
gitgitgadget
#42 lore raw

PATCH v4 2/4 branch -m: allow renaming a yet-unborn branch

In reply to Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

In one of the next commits, we would like to give users some advice regarding the initial branch name, and how to modify it.

To that end, it would be good if git branch -m <name> worked in a freshly initialized repository without any commits. Let's make it so.

---
 builtin/branch.c | 4 +++-
 t/t0001-init.sh  | 8 ++++++++
 2 files changed, 11 insertions(+), 1 deletion(-)
builtin/branch.c +3 -1
index efb30b88206..200da319f1d 100644
@@ -538,7 +538,9 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
 		strbuf_addf(&logmsg, "Branch: renamed %s to %s",
 			    oldref.buf, newref.buf);
 
-	if (!copy && rename_ref(oldref.buf, newref.buf, logmsg.buf))
+	if (!copy &&
+	    (!head || strcmp(oldname, head) || !is_null_oid(&head_oid)) &&
+	    rename_ref(oldref.buf, newref.buf, logmsg.buf))
 		die(_("Branch rename failed"));
 	if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf))
 		die(_("Branch copy failed"));
t/t0001-init.sh +8 -0
index 69a320489fc..bb23e56a165 100755
@@ -571,4 +571,12 @@ test_expect_success 'invalid default branch name' '
 	test_i18ngrep "invalid branch name" err
 '
 
+test_expect_success 'branch -m with the initial branch' '
+	git init rename-initial &&
+	git -C rename-initial branch -m renamed &&
+	test renamed = $(git -C rename-initial symbolic-ref --short HEAD) &&
+	git -C rename-initial branch -m renamed again &&
+	test again = $(git -C rename-initial symbolic-ref --short HEAD)
+'
+
 test_done
Signature · 1 line
gitgitgadget
#28 lore raw

Re: [PATCH v2 4/4] init: provide useful advice about init.defaultBranch

In reply to Junio C Hamano

Hi Junio,

Quoted 26 lines · Junio C Hamano
Quoted 9 lines · Johannes Schindelin
Quoted 6 lines · Junio C Hamano

I am not saying it is a legitimate need. I just wanted to make it clear that we deliberately chose not to grant that wish in the message. An advice flag in this context means that the users can choose to let their distro and sysadm to flip the default silently, which is much worse than having to see the message every time they start a new repository with "git init".

Quoted 4 lines

The distribution already can add patches, so this objection is a red herring. The sysadm can pick a different value for init.defaultBranch and dictate to the user silently what initial branch name to use, so that is also a red herring.

The "setting init.defaultBranch is the only way to squelch" approach means the ~/.gitconfig will have the settings soon after the user starts using Git and /etc/gitconfig will not allow administrators to force their will over what the user decides to use. Distros adding patches to strip configurability by setting init.defaultBranch in user's ~/.gitconfig? Is that the kind of possibilities worth discussing?

So, no, your counter-argument above is nothing but a red-herring.

Quoted 10 lines

If you want a counter-argument, please explain why "I am fine to see the default flipped to whatever the tool picks and having no control over when the flipping happens" can be a sensible choice for users with what kind of workflows. The only folks I can think of who would be fine with that are (1) those who do not create the second branch in the repository and will stay on the primary branch forever, and (2) those who immediately rename the branch to what they want after "git init". For other folks, such a choice is a disaster waiting to happen, and it just feels irresponsible to offer such a choice, at least to me.

I'll make this short.

I talked to a couple Git users whether they'd be fine if git init used a different branch name by default, and everybody I asked said essentially "yeah, whatever, I don't really care".

For that reason, Git for Windows' installer has that option, and will keep offering it.

Ciao,
Dscho

#37 lore raw

PATCH v4 1/4 init: document `init.defaultBranch` better

In reply to Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

Our documentation does not mention any future plan to change 'master' to other value. It is a good idea to document this, though.

---
 Documentation/git-init.txt | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
Documentation/git-init.txt +7 -4
index 59ecda6c17d..2b399cb73d7 100644
@@ -20,8 +20,9 @@ DESCRIPTION
 
 This command creates an empty Git repository - basically a `.git`
 directory with subdirectories for `objects`, `refs/heads`,
-`refs/tags`, and template files.  An initial `HEAD` file that
-references the HEAD of the master branch is also created.
+`refs/tags`, and template files.  An initial branch without any
+commits will be created (see the `--initial-branch` option below
+for its name).
 
 If the `$GIT_DIR` environment variable is set then it specifies a path
 to use instead of `./.git` for the base of the repository.
@@ -73,8 +74,10 @@ If this is reinitialization, the repository will be moved to the specified path.
 -b <branch-name>::
 --initial-branch=<branch-name>::
 
-Use the specified name for the initial branch in the newly created repository.
-If not specified, fall back to the default name: `master`.
+Use the specified name for the initial branch in the newly created
+repository.  If not specified, fall back to the default name (currently
+`master`, but that will be changed in the future; the name can be customized
+via the `init.defaultBranch` configuration variable).
 
 --shared[=(false|true|umask|group|all|world|everybody|0xxx)]::
 
Signature · 1 line
gitgitgadget
#43 lore raw

PATCH v4 3/4 get_default_branch_name(): prepare for showing some advice

In reply to Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

We are about to introduce a message giving users running git init some advice about init.defaultBranch. This will necessarily be done in repo_default_branch_name().

Not all code paths want to show that advice, though. In particular, the git clone codepath _specifically_ asks for init_db() to be quiet, via the INIT_DB_QUIET flag.

In preparation for showing users above-mentioned advice, let's change the function signature of get_default_branch_name() to accept the parameter quiet.

---
 builtin/clone.c   | 2 +-
 builtin/init-db.c | 8 +++++---
 refs.c            | 6 +++---
 refs.h            | 4 ++--
 remote.c          | 5 +++--
 5 files changed, 14 insertions(+), 11 deletions(-)
builtin/clone.c +1 -1
index a0841923cfe..64b17840112 100644
@@ -1323,7 +1323,7 @@ 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();
+			const char *branch = git_default_branch_name(0);
 			char *ref = xstrfmt("refs/heads/%s", branch);
 
 			install_branch_config(0, branch, remote_name, ref);
builtin/init-db.c +5 -3
index 01bc648d416..dcc45bef514 100644
@@ -202,7 +202,8 @@ void initialize_repository_version(int hash_algo, int reinit)
 static int create_default_files(const char *template_path,
 				const char *original_git_dir,
 				const char *initial_branch,
-				const struct repository_format *fmt)
+				const struct repository_format *fmt,
+				int quiet)
 {
 	struct stat st1;
 	struct strbuf buf = STRBUF_INIT;
@@ -267,7 +268,7 @@ static int create_default_files(const char *template_path,
 		char *ref;
 
 		if (!initial_branch)
-			initial_branch = git_default_branch_name();
+			initial_branch = git_default_branch_name(quiet);
 
 		ref = xstrfmt("refs/heads/%s", initial_branch);
 		if (check_refname_format(ref, 0) < 0)
@@ -438,7 +439,8 @@ int init_db(const char *git_dir, const char *real_git_dir,
 	validate_hash_algorithm(&repo_fmt, hash);
 
 	reinit = create_default_files(template_dir, original_git_dir,
-				      initial_branch, &repo_fmt);
+				      initial_branch, &repo_fmt,
+				      flags & INIT_DB_QUIET);
 	if (reinit && initial_branch)
 		warning(_("re-init: ignored --initial-branch=%s"),
 			initial_branch);
refs.c +3 -3
index 392f0bbf68b..8df03122d69 100644
@@ -562,7 +562,7 @@ void expand_ref_prefix(struct strvec *prefixes, const char *prefix)
 		strvec_pushf(prefixes, *p, len, prefix);
 }
 
-char *repo_default_branch_name(struct repository *r)
+char *repo_default_branch_name(struct repository *r, int quiet)
 {
 	const char *config_key = "init.defaultbranch";
 	const char *config_display_key = "init.defaultBranch";
@@ -585,12 +585,12 @@ char *repo_default_branch_name(struct repository *r)
 	return ret;
 }
 
-const char *git_default_branch_name(void)
+const char *git_default_branch_name(int quiet)
 {
 	static char *ret;
 
 	if (!ret)
-		ret = repo_default_branch_name(the_repository);
+		ret = repo_default_branch_name(the_repository, quiet);
 
 	return ret;
 }
refs.h +2 -2
index 66955181569..ff05d2e9fe2 100644
@@ -170,8 +170,8 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **ref);
  * The return value of `repo_default_branch_name()` is an allocated string. The
  * return value of `git_default_branch_name()` is a singleton.
  */
-const char *git_default_branch_name(void);
-char *repo_default_branch_name(struct repository *r);
+const char *git_default_branch_name(int quiet);
+char *repo_default_branch_name(struct repository *r, int quiet);
 
 /*
  * A ref_transaction represents a collection of reference updates that
remote.c +3 -2
index 8a6dbbb9030..bdb88d4b7dd 100644
@@ -284,7 +284,7 @@ static void read_branches_file(struct remote *remote)
 	if (frag)
 		*(frag++) = '\0';
 	else
-		frag = (char *)git_default_branch_name();
+		frag = (char *)git_default_branch_name(0);
 
 	add_url_alias(remote, strbuf_detach(&buf, NULL));
 	refspec_appendf(&remote->fetch, "refs/heads/%s:refs/heads/%s",
@@ -2206,7 +2206,8 @@ struct ref *guess_remote_head(const struct ref *head,
 
 	/* If a remote branch exists with the default branch name, let's use it. */
 	if (!all) {
-		char *ref = xstrfmt("refs/heads/%s", git_default_branch_name());
+		char *ref = xstrfmt("refs/heads/%s",
+				    git_default_branch_name(0));
 
 		r = find_ref_by_name(refs, ref);
 		free(ref);
Signature · 1 line
gitgitgadget
#29 lore raw

Re: [PATCH v2 4/4] init: provide useful advice about init.defaultBranch

In reply to Johannes Schindelin
Quoted 3 lines · Johannes Schindelin

I talked to a couple Git users whether they'd be fine if git init used a different branch name by default, and everybody I asked said essentially "yeah, whatever, I don't really care".

Yeah, I would expect that, too. They would not have asked about the details on when that switchover of the default would happen, and would not have been told that the timing is not under their control. I would answer to such a question with "yeah, whatever." that does not give you an assurance that I won't complain when the switchover actually happens ;-).

#45 lore raw

Re: [PATCH v4 4/4] init: provide useful advice about init.defaultBranch

In reply to Johannes Schindelin via GitGitGadget
Quoted 8 lines · Johannes Schindelin via GitGitGadget

+static const char default_branch_name_advice[] = N_(
+"Using '%s' as the name for the initial branch. This default branch name\n" +"is subject to change. To configure the initial branch name to use in all\n" +"of your new repositories, which will suppress this warning, call:\n" +"\n"
+"\tgit config --global init.defaultBranch <name>\n"
+"\n"
+"Common names are 'main', 'trunk' and 'development'. The initial branch\n"

This is disingenuous; the most common name is "master"... by far. In a couple years this might change, but not right now.

If you don't want to mention "master", then don't mention "common names" that are not really the most common names.

Cheers.

Signature · 1 line
Felipe Contreras
#38 lore raw

Re: [PATCH v4 1/4] init: document `init.defaultBranch` better

In reply to Johannes Schindelin via GitGitGadget
Quoted 17 lines · Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

Our documentation does not mention any future plan to change 'master' to other value. It is a good idea to document this, though.

---
 Documentation/git-init.txt | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
Documentation/git-init.txt +0 -0
index 59ecda6c17d..2b399cb73d7 100644

Documentation/git-init.txt DESCRIPTION · line 24

Quoted 5 lines
Documentation/git-init.txt +0 -2
@@ -20,8 +20,9 @@ DESCRIPTION
 
 This command creates an empty Git repository - basically a `.git`
 directory with subdirectories for `objects`, `refs/heads`,
-`refs/tags`, and template files.  An initial `HEAD` file that
-references the HEAD of the master branch is also created.

The current sentence: "An initial HEAD file that references the HEAD of the master branch is also created." is still true. There's no need to change that (yet).

Documentation/git-init.txt DESCRIPTION · line 25

Quoted 3 lines
Documentation/git-init.txt +3 -0
+`refs/tags`, and template files.  An initial branch without any
+commits will be created (see the `--initial-branch` option below
+for its name).

Perhaps: (see the --initial-branch option below to choose another name).

Documentation/git-init.txt If this is reinitialization, the repository will be moved to the specified path. · line 77

Quoted 9 lines
Documentation/git-init.txt +1 -2
 If the `$GIT_DIR` environment variable is set then it specifies a path
 to use instead of `./.git` for the base of the repository.
@@ -73,8 +74,10 @@ If this is reinitialization, the repository will be moved to the specified path.
 -b <branch-name>::
 --initial-branch=<branch-name>::
 
-Use the specified name for the initial branch in the newly created repository.
-If not specified, fall back to the default name: `master`.
+Use the specified name for the initial branch in the newly created

Again; the default name has not changed.

Documentation/git-init.txt If this is reinitialization, the repository will be moved to the specified path. · line 80

Quoted 3 lines
Documentation/git-init.txt +3 -0
+repository.  If not specified, fall back to the default name (currently
+`master`, but that will be changed in the future; the name can be customized
+via the `init.defaultBranch` configuration variable).

Wait a second. The advice warning said "this is subject to change", and the documentation says "that will be changed in the future". Which is it?

"I might give you a fine", and "I will give you a fine" are most definitely not the same thing.

Either say "this is subject to change" in both the documentation and the warning. Or say "that will be changed in the future".

Don't say one thing in one and another thing in the other.

Cheers.

Signature · 1 line
Felipe Contreras
#46 lore raw

Re: [PATCH v4 4/4] init: provide useful advice about init.defaultBranch

In reply to Felipe Contreras
Quoted 12 lines · Felipe Contreras
Quoted 8 lines · Johannes Schindelin via GitGitGadget

+static const char default_branch_name_advice[] = N_(
+"Using '%s' as the name for the initial branch. This default branch name\n" +"is subject to change. To configure the initial branch name to use in all\n" +"of your new repositories, which will suppress this warning, call:\n" +"\n"
+"\tgit config --global init.defaultBranch <name>\n"
+"\n"
+"Common names are 'main', 'trunk' and 'development'. The initial branch\n"

Quoted 5 lines

This is disingenuous; the most common name is "master"... by far. In a couple years this might change, but not right now.

If you don't want to mention "master", then don't mention "common names" that are not really the most common names.

Names commonly chosen by those who want to move away from 'master' are...

#47 lore raw

Re: [PATCH v4 4/4] init: provide useful advice about init.defaultBranch

Quoted 15 lines · Junio C Hamano
Quoted 12 lines · Felipe Contreras
Quoted 8 lines · Johannes Schindelin via GitGitGadget

+static const char default_branch_name_advice[] = N_(
+"Using '%s' as the name for the initial branch. This default branch name\n" +"is subject to change. To configure the initial branch name to use in all\n" +"of your new repositories, which will suppress this warning, call:\n" +"\n"
+"\tgit config --global init.defaultBranch <name>\n"
+"\n"
+"Common names are 'main', 'trunk' and 'development'. The initial branch\n"

Quoted 8 lines
Quoted 5 lines

This is disingenuous; the most common name is "master"... by far. In a couple years this might change, but not right now.

If you don't want to mention "master", then don't mention "common names" that are not really the most common names.

Names commonly chosen by those who want to move away from 'master' are...

But we don't want to spill drama into the user interface.

I think the vast majority of users haven't heard of this drama. Just like the vast majority of users had not heard of the git-foo obsoletion even after several years. Our vantage point is skewed for being too close to Git development.

Those users will ask: "who wants to move away from 'master'?"

If we don't presume our users have the same knowledge as us, we have to explain:

Names commonly chosen by those who want to move away from 'master' are; 'main', 'trunk', and 'development'. For more information read this post:
https://dev.to/rhymu8354/git-renaming-the-master-branch-137b.

I say don't. If the user wants to know why anyone would want to change "the default branch name", she can google it and find out.

Cheer.

Signature · 1 line
Felipe Contreras
#39 lore raw

Re: [PATCH v4 1/4] init: document `init.defaultBranch` better

In reply to Felipe Contreras
Quoted 9 lines · Felipe Contreras

Documentation/git-init.txt DESCRIPTION · line 25

Quoted 5 lines

-refs/tags, and template files. An initial HEAD file that

Documentation/git-init.txt +3 -1
-references the HEAD of the master branch is also created.
+`refs/tags`, and template files.  An initial branch without any
+commits will be created (see the `--initial-branch` option below
+for its name).

The current sentence: "An initial HEAD file that references the HEAD of the master branch is also created." is still true. There's no need to change that (yet).

The change updates the description for readability, lowering the technical level of description, and correcting inaccuracies.

- The readers in the context of understanding what "git init" performs does not have to know nor care that HEAD is implemented as a file. In fact, there is an effort to introduce HEAD and other refs that are implemented as individual files under $GIT_DIR/. Dropping the word "file" is to correct these.

- Also we no longer say "the HEAD of" a branch, even if we used to use that expression. When we really need to refer to the commit directly pointed at by a branch ref, we say "the tip of" instead there days.

- It used to be left unsaid that the initial branch begins its life without any commit. Now it does.

None of these is about "'master' or any other name?" issue.

Quoted 1 line

Perhaps: (see the --initial-branch option below to choose another name).

That changes the meaning of the explanation. It is compensating for not saying what the name of the initial branch is, and is not trying to teach that the name can be changed. The text in the patch is good as-is.

#41 lore raw

Re: [PATCH v4 1/4] init: document `init.defaultBranch` better

In reply to Felipe Contreras
Quoted 10 lines · Felipe Contreras

On Thu, Dec 10, 2020 at 3:58 PM Johannes Schindelin via GitGitGadget

Documentation/git-init.txt If this is reinitialization, the repository will be moved to the specified path. · line 80

Quoted 3 lines
Documentation/git-init.txt +3 -0
+repository.  If not specified, fall back to the default name (currently
+`master`, but that will be changed in the future; the name can be customized
+via the `init.defaultBranch` configuration variable).

Wait a second. The advice warning said "this is subject to change", and the documentation says "that will be changed in the future". Which is it?

Quoted 2 lines

"I might give you a fine", and "I will give you a fine" are most definitely not the same thing.

I think we say "this is subject to change" in other places, and I agree that this part should match to avoid confusing readers, especially the non-native ones like me.

If not specified, fall back to the default name (currently master, but this is subject to change in the future; ...

would be more consistent.

#40 lore raw

Re: [PATCH v4 1/4] init: document `init.defaultBranch` better

In reply to Junio C Hamano
Quoted 13 lines · Junio C Hamano
Quoted 9 lines · Felipe Contreras

Documentation/git-init.txt DESCRIPTION · line 25

Quoted 5 lines

-refs/tags, and template files. An initial HEAD file that

Documentation/git-init.txt +3 -1
-references the HEAD of the master branch is also created.
+`refs/tags`, and template files.  An initial branch without any
+commits will be created (see the `--initial-branch` option below
+for its name).

The current sentence: "An initial HEAD file that references the HEAD of the master branch is also created." is still true. There's no need to change that (yet).

Quoted 2 lines

The change updates the description for readability, lowering the technical level of description, and correcting inaccuracies.

OK.

Quoted 5 lines

- The readers in the context of understanding what "git init" performs does not have to know nor care that HEAD is implemented as a file. In fact, there is an effort to introduce HEAD and other refs that are implemented as individual files under $GIT_DIR/. Dropping the word "file" is to correct these.

Right.

Quoted 4 lines

- Also we no longer say "the HEAD of" a branch, even if we used to use that expression. When we really need to refer to the commit directly pointed at by a branch ref, we say "the tip of" instead there days.

Sure.

Quoted 2 lines

- It used to be left unsaid that the initial branch begins its life without any commit. Now it does.

OK.

Quoted 1 line

None of these is about "'master' or any other name?" issue.

Indeed, but the commit message clearly states:

Our documentation does not mention any future plan to change 'master' to other value. It is a good idea to document this, though.

It doesn't say anything about improving the documentation of "git init", nor any of your three points. The main intention is clear.

On top of your three points it sneaks another change; avoiding the "master" branch name. If this really had nothing to do with the "master" branch name, it could very well be sent as a separate independent patch.

The following text has your three valid points, but doesn't sneak in the extra change:

An initial "master" branch without any commits will be created (see the --initial-branch option below to choose another name).

Quoted 6 lines
Quoted 1 line

Perhaps: (see the --initial-branch option below to choose another name).

That changes the meaning of the explanation. It is compensating for not saying what the name of the initial branch is, and is not trying to teach that the name can be changed. The text in the patch is good as-is.

In English parentheses are used to clarify information, and typically it's *supplementary* information. That is; the sentence must stand on its own without them.

This sentence is missing crucial information and it doesn't stand on its own:

An initial branch without any commits will be created.

This one does stand on its own:

An initial "master" branch without any commits will be created.

(and doesn't omit any current information.)

Cheers.

Signature · 1 line
Felipe Contreras
#48 lore raw

Re: [PATCH v4 4/4] init: provide useful advice about init.defaultBranch

In reply to Junio C Hamano

Hi Junio,

Quoted 14 lines · Junio C Hamano
Quoted 12 lines · Felipe Contreras
Quoted 8 lines · Johannes Schindelin via GitGitGadget

+static const char default_branch_name_advice[] = N_(
+"Using '%s' as the name for the initial branch. This default branch name\n" +"is subject to change. To configure the initial branch name to use in all\n" +"of your new repositories, which will suppress this warning, call:\n" +"\n"
+"\tgit config --global init.defaultBranch <name>\n"
+"\n"
+"Common names are 'main', 'trunk' and 'development'. The initial branch\n"

Quoted 8 lines
Quoted 5 lines

This is disingenuous; the most common name is "master"... by far. In a couple years this might change, but not right now.

If you don't want to mention "master", then don't mention "common names" that are not really the most common names.

Names commonly chosen by those who want to move away from 'master' are...

"those who want to move away" sounds a bit too non-committal for my liking. So I changed it to:

Names commonly chosen instead of 'master' are 'main', 'trunk' and 'development'.

While at it, I also improved the next sentence:

The just-created branch can be renamed via this command:

Ciao,
Dscho

#50 lore raw

PATCH v5 1/4 init: document `init.defaultBranch` better

In reply to Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

Our documentation does not mention any future plan to change 'master' to other value. It is a good idea to document this, though.

---
 Documentation/git-init.txt | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
Documentation/git-init.txt +7 -4
index 59ecda6c17d..b611d80697d 100644
@@ -20,8 +20,9 @@ DESCRIPTION
 
 This command creates an empty Git repository - basically a `.git`
 directory with subdirectories for `objects`, `refs/heads`,
-`refs/tags`, and template files.  An initial `HEAD` file that
-references the HEAD of the master branch is also created.
+`refs/tags`, and template files.  An initial branch without any
+commits will be created (see the `--initial-branch` option below
+for its name).
 
 If the `$GIT_DIR` environment variable is set then it specifies a path
 to use instead of `./.git` for the base of the repository.
@@ -73,8 +74,10 @@ If this is reinitialization, the repository will be moved to the specified path.
 -b <branch-name>::
 --initial-branch=<branch-name>::
 
-Use the specified name for the initial branch in the newly created repository.
-If not specified, fall back to the default name: `master`.
+Use the specified name for the initial branch in the newly created
+repository.  If not specified, fall back to the default name (currently
+`master`, but this is subject to change in the future; the name can be
+customized via the `init.defaultBranch` configuration variable).
 
 --shared[=(false|true|umask|group|all|world|everybody|0xxx)]::
 
Signature · 1 line
gitgitgadget
#51 lore raw

PATCH v5 2/4 branch -m: allow renaming a yet-unborn branch

In reply to Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

In one of the next commits, we would like to give users some advice regarding the initial branch name, and how to modify it.

To that end, it would be good if git branch -m <name> worked in a freshly initialized repository without any commits. Let's make it so.

---
 builtin/branch.c | 4 +++-
 t/t0001-init.sh  | 8 ++++++++
 2 files changed, 11 insertions(+), 1 deletion(-)
builtin/branch.c +3 -1
index efb30b88206..200da319f1d 100644
@@ -538,7 +538,9 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
 		strbuf_addf(&logmsg, "Branch: renamed %s to %s",
 			    oldref.buf, newref.buf);
 
-	if (!copy && rename_ref(oldref.buf, newref.buf, logmsg.buf))
+	if (!copy &&
+	    (!head || strcmp(oldname, head) || !is_null_oid(&head_oid)) &&
+	    rename_ref(oldref.buf, newref.buf, logmsg.buf))
 		die(_("Branch rename failed"));
 	if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf))
 		die(_("Branch copy failed"));
t/t0001-init.sh +8 -0
index 69a320489fc..bb23e56a165 100755
@@ -571,4 +571,12 @@ test_expect_success 'invalid default branch name' '
 	test_i18ngrep "invalid branch name" err
 '
 
+test_expect_success 'branch -m with the initial branch' '
+	git init rename-initial &&
+	git -C rename-initial branch -m renamed &&
+	test renamed = $(git -C rename-initial symbolic-ref --short HEAD) &&
+	git -C rename-initial branch -m renamed again &&
+	test again = $(git -C rename-initial symbolic-ref --short HEAD)
+'
+
 test_done
Signature · 1 line
gitgitgadget
#52 lore raw

PATCH v5 3/4 get_default_branch_name(): prepare for showing some advice

In reply to Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

We are about to introduce a message giving users running git init some advice about init.defaultBranch. This will necessarily be done in repo_default_branch_name().

Not all code paths want to show that advice, though. In particular, the git clone codepath _specifically_ asks for init_db() to be quiet, via the INIT_DB_QUIET flag.

In preparation for showing users above-mentioned advice, let's change the function signature of get_default_branch_name() to accept the parameter quiet.

---
 builtin/clone.c   | 2 +-
 builtin/init-db.c | 8 +++++---
 refs.c            | 6 +++---
 refs.h            | 4 ++--
 remote.c          | 5 +++--
 5 files changed, 14 insertions(+), 11 deletions(-)
builtin/clone.c +1 -1
index a0841923cfe..64b17840112 100644
@@ -1323,7 +1323,7 @@ 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();
+			const char *branch = git_default_branch_name(0);
 			char *ref = xstrfmt("refs/heads/%s", branch);
 
 			install_branch_config(0, branch, remote_name, ref);
builtin/init-db.c +5 -3
index 01bc648d416..dcc45bef514 100644
@@ -202,7 +202,8 @@ void initialize_repository_version(int hash_algo, int reinit)
 static int create_default_files(const char *template_path,
 				const char *original_git_dir,
 				const char *initial_branch,
-				const struct repository_format *fmt)
+				const struct repository_format *fmt,
+				int quiet)
 {
 	struct stat st1;
 	struct strbuf buf = STRBUF_INIT;
@@ -267,7 +268,7 @@ static int create_default_files(const char *template_path,
 		char *ref;
 
 		if (!initial_branch)
-			initial_branch = git_default_branch_name();
+			initial_branch = git_default_branch_name(quiet);
 
 		ref = xstrfmt("refs/heads/%s", initial_branch);
 		if (check_refname_format(ref, 0) < 0)
@@ -438,7 +439,8 @@ int init_db(const char *git_dir, const char *real_git_dir,
 	validate_hash_algorithm(&repo_fmt, hash);
 
 	reinit = create_default_files(template_dir, original_git_dir,
-				      initial_branch, &repo_fmt);
+				      initial_branch, &repo_fmt,
+				      flags & INIT_DB_QUIET);
 	if (reinit && initial_branch)
 		warning(_("re-init: ignored --initial-branch=%s"),
 			initial_branch);
refs.c +3 -3
index 392f0bbf68b..8df03122d69 100644
@@ -562,7 +562,7 @@ void expand_ref_prefix(struct strvec *prefixes, const char *prefix)
 		strvec_pushf(prefixes, *p, len, prefix);
 }
 
-char *repo_default_branch_name(struct repository *r)
+char *repo_default_branch_name(struct repository *r, int quiet)
 {
 	const char *config_key = "init.defaultbranch";
 	const char *config_display_key = "init.defaultBranch";
@@ -585,12 +585,12 @@ char *repo_default_branch_name(struct repository *r)
 	return ret;
 }
 
-const char *git_default_branch_name(void)
+const char *git_default_branch_name(int quiet)
 {
 	static char *ret;
 
 	if (!ret)
-		ret = repo_default_branch_name(the_repository);
+		ret = repo_default_branch_name(the_repository, quiet);
 
 	return ret;
 }
refs.h +2 -2
index 66955181569..ff05d2e9fe2 100644
@@ -170,8 +170,8 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **ref);
  * The return value of `repo_default_branch_name()` is an allocated string. The
  * return value of `git_default_branch_name()` is a singleton.
  */
-const char *git_default_branch_name(void);
-char *repo_default_branch_name(struct repository *r);
+const char *git_default_branch_name(int quiet);
+char *repo_default_branch_name(struct repository *r, int quiet);
 
 /*
  * A ref_transaction represents a collection of reference updates that
remote.c +3 -2
index 8a6dbbb9030..bdb88d4b7dd 100644
@@ -284,7 +284,7 @@ static void read_branches_file(struct remote *remote)
 	if (frag)
 		*(frag++) = '\0';
 	else
-		frag = (char *)git_default_branch_name();
+		frag = (char *)git_default_branch_name(0);
 
 	add_url_alias(remote, strbuf_detach(&buf, NULL));
 	refspec_appendf(&remote->fetch, "refs/heads/%s:refs/heads/%s",
@@ -2206,7 +2206,8 @@ struct ref *guess_remote_head(const struct ref *head,
 
 	/* If a remote branch exists with the default branch name, let's use it. */
 	if (!all) {
-		char *ref = xstrfmt("refs/heads/%s", git_default_branch_name());
+		char *ref = xstrfmt("refs/heads/%s",
+				    git_default_branch_name(0));
 
 		r = find_ref_by_name(refs, ref);
 		free(ref);
Signature · 1 line
gitgitgadget
#53 lore raw

PATCH v5 4/4 init: provide useful advice about init.defaultBranch

In reply to Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

To give ample warning for users wishing to override Git's the fall-back for an unconfigured init.defaultBranch (in case we decide to change it in a future Git version), let's introduce some advice that is shown upon git init when that value is not set.

Note: two test cases in Git's test suite want to verify that the stderr output of git init is empty. It is now necessary to suppress the advice, we now do that via the init.defaultBranch setting. While not strictly necessary, we also set this to false in test_create_repo().

---
 refs.c                  | 18 +++++++++++++++++-
 t/t0001-init.sh         |  9 ++++++++-
 t/t1510-repo-setup.sh   |  2 +-
 t/test-lib-functions.sh |  4 +++-
 4 files changed, 29 insertions(+), 4 deletions(-)
refs.c +17 -1
index 8df03122d69..13dc2c3291b 100644
@@ -562,6 +562,19 @@ void expand_ref_prefix(struct strvec *prefixes, const char *prefix)
 		strvec_pushf(prefixes, *p, len, prefix);
 }
 
+static const char default_branch_name_advice[] = N_(
+"Using '%s' as the name for the initial branch. This default branch name\n"
+"is subject to change. To configure the initial branch name to use in all\n"
+"of your new repositories, which will suppress this warning, call:\n"
+"\n"
+"\tgit config --global init.defaultBranch <name>\n"
+"\n"
+"Names commonly chosen instead of 'master' are 'main', 'trunk' and\n"
+"'development'. The just-created branch can be renamed via this command:\n"
+"\n"
+"\tgit branch -m <name>\n"
+);
+
 char *repo_default_branch_name(struct repository *r, int quiet)
 {
 	const char *config_key = "init.defaultbranch";
@@ -574,8 +587,11 @@ char *repo_default_branch_name(struct repository *r, int quiet)
 	else if (repo_config_get_string(r, config_key, &ret) < 0)
 		die(_("could not retrieve `%s`"), config_display_key);
 
-	if (!ret)
+	if (!ret) {
 		ret = xstrdup("master");
+		if (!quiet)
+			advise(_(default_branch_name_advice), ret);
+	}
 
 	full_ref = xstrfmt("refs/heads/%s", ret);
 	if (check_refname_format(full_ref, 0))
t/t0001-init.sh +8 -1
index bb23e56a165..0803994874f 100755
@@ -163,7 +163,7 @@ test_expect_success 'reinit' '
 	(
 		mkdir again &&
 		cd again &&
-		git init >out1 2>err1 &&
+		git -c init.defaultBranch=initial init >out1 2>err1 &&
 		git init >out2 2>err2
 	) &&
 	test_i18ngrep "Initialized empty" again/out1 &&
@@ -558,6 +558,13 @@ test_expect_success 'overridden default initial branch name (config)' '
 	grep nmb actual
 '
 
+test_expect_success 'advice on unconfigured init.defaultBranch' '
+	GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= git -c color.advice=always \
+		init unconfigured-default-branch-name 2>err &&
+	test_decode_color <err >decoded &&
+	test_i18ngrep "<YELLOW>hint: " decoded
+'
+
 test_expect_success 'overridden default main branch name (env)' '
 	test_config_global init.defaultBranch nmb &&
 	GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=env git init main-branch-env &&
t/t1510-repo-setup.sh +1 -1
index 9974457f561..bbfe05b8e4a 100755
@@ -79,7 +79,7 @@ setup_repo () {
 	name=$1 worktreecfg=$2 gitfile=$3 barecfg=$4 &&
 	sane_unset GIT_DIR GIT_WORK_TREE &&
 
-	git init "$name" &&
+	git -c init.defaultBranch=initial init "$name" &&
 	maybe_config "$name/.git/config" core.worktree "$worktreecfg" &&
 	maybe_config "$name/.git/config" core.bare "$barecfg" &&
 	mkdir -p "$name/sub/sub" &&
t/test-lib-functions.sh +3 -1
index 59bbf75e832..9910102ae1f 100644
@@ -1202,7 +1202,9 @@ test_create_repo () {
 	mkdir -p "$repo"
 	(
 		cd "$repo" || error "Cannot setup test environment"
-		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" init \
+		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" -c \
+			init.defaultBranch="${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME-master}" \
+			init \
 			"--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||
 		error "cannot run git init -- have you built things yet?"
 		mv .git/hooks .git/hooks-disabled
Signature · 1 line
gitgitgadget
#49 lore raw

v5 cover Add helpful advice about init.defaultBranch

In reply to Johannes Schindelin via GitGitGadget

It is our designated intention
[https://sfconservancy.org/news/2020/jun/23/gitbranchname/] to "to explore changing the name of the first branch created automatically for new repositories away from ‘master’". Further, we promised that we "will minimize disruption for Git's users and will include appropriate deprecation periods".

To that end, we first clarify git init's documentation (a lightly edited version of Junio's patch
[https://lore.kernel.org/git/[email protected]]), and then introduce a message giving advice to users running git init that the fall-back for init.defaultBranch is subject to change, and how to override Git's fall-back manually.

The beauty of this patch series, if I may say so, is that it does not commit us to any concrete plan, but opens the door for all options regarding the default branch name.

Changes since v4:

* Reworded the documentation to weaken the "will be changed in the future" to "is subject to change".
* Reworded the advice to explicitly mention "instead of 'master'".

Changes since v3:

* Kicked out advice.defaultBranchName again. The advice can now only be suppressed by setting init.defaultBranch.

Changes since v2:

* git branch -m <initial> <renamed> now works, too
* The config setting advice.defaultBranchName was introduced to allow suppressing this warning specifically
* The advice now first talks about the current default branch name, then how to suppress the advice, and only then explains how to override the default branch name (and that that will also prevent the message from being shown)

Changes since v1:

* Grammar fix
* Reworded advice and commit messages
* test_create_repo already respected GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME, but now does so more obviously
* Allowed git branch -m <name> to rename unborn branches, so that the advice actually works

Johannes Schindelin (4):
init: document init.defaultBranch better branch -m: allow renaming a yet-unborn branch get_default_branch_name(): prepare for showing some advice
init: provide useful advice about init.defaultBranch

 Documentation/git-init.txt | 11 +++++++----
 builtin/branch.c           |  4 +++-
 builtin/clone.c            |  2 +-
 builtin/init-db.c          |  8 +++++---
 refs.c                     | 24 ++++++++++++++++++++----
 refs.h                     |  4 ++--
 remote.c                   |  5 +++--
 t/t0001-init.sh            | 17 ++++++++++++++++-
 t/t1510-repo-setup.sh      |  2 +-
 t/test-lib-functions.sh    |  4 +++-
 10 files changed, 61 insertions(+), 20 deletions(-)

base-commit: faefdd61ec7c7f6f3c8c9907891465ac9a2a1475
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-921%2Fdscho%2Finit.defaultBranch-advice-v5
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-921/dscho/init.defaultBranch-advice-v5
Pull-Request: https://github.com/git/git/pull/921

Range-diff vs v4:

1: 483e4903491 ! 1: ce35cf3da65 init: document init.defaultBranch better
@@ Documentation/git-init.txt: If this is reinitialization, the repository will be
-If not specified, fall back to the default name: master.
+Use the specified name for the initial branch in the newly created +repository. If not specified, fall back to the default name (currently
-+master, but that will be changed in the future; the name can be customized -+via the init.defaultBranch configuration variable).
++master, but this is subject to change in the future; the name can be ++customized via the init.defaultBranch configuration variable).

--shared[=(false|true|umask|group|all|world|everybody|0xxx)]::

 2:  6cbd6692c6a = 2:  ac7b352a0ba branch -m: allow renaming a yet-unborn branch
 3:  5fc15f7b9ad = 3:  aba72340c87 get_default_branch_name(): prepare for showing some advice
 4:  2f21c505d56 ! 4:  ce26446b1a2 init: provide useful advice about init.defaultBranch
     @@ refs.c: void expand_ref_prefix(struct strvec *prefixes, const char *prefix)
      +"\n"
      +"\tgit config --global init.defaultBranch <name>\n"
      +"\n"
     -+"Common names are 'main', 'trunk' and 'development'. The initial branch\n"
     -+"that was created can be renamed via this command:\n"
     ++"Names commonly chosen instead of 'master' are 'main', 'trunk' and\n"
     ++"'development'. The just-created branch can be renamed via this command:\n"
      +"\n"
      +"\tgit branch -m <name>\n"
      +);
Signature · 1 line
gitgitgadget
#54 lore raw

Re: [PATCH v5 4/4] init: provide useful advice about init.defaultBranch

In reply to Johannes Schindelin via GitGitGadget
Quoted 21 lines · Johannes Schindelin via GitGitGadget

From: Johannes Schindelin <[email protected]>

To give ample warning for users wishing to override Git's the fall-back for an unconfigured init.defaultBranch (in case we decide to change it in a future Git version), let's introduce some advice that is shown upon git init when that value is not set.

Note: two test cases in Git's test suite want to verify that the stderr output of git init is empty. It is now necessary to suppress the advice, we now do that via the init.defaultBranch setting. While not strictly necessary, we also set this to false in test_create_repo().

---

t/test-lib-functions.sh +0 -0
index 59bbf75e832..9910102ae1f 100644

t/test-lib-functions.sh test_create_repo () { · line 1208

Quoted 8 lines
t/test-lib-functions.sh +3 -1
@@ -1202,7 +1202,9 @@ test_create_repo () {
 	mkdir -p "$repo"
 	(
 		cd "$repo" || error "Cannot setup test environment"
-		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" init \
+		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" -c \
+			init.defaultBranch="${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME-master}" \
+			init \
 			"--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||

This breaks GIT_TEST_INSTALLED when the given Git version doesn't yet contain 8b1fa77867 (Allow passing of configuration parameters in the command line, 2010-03-26):

  $ GIT_TEST_INSTALLED=.../v1.6.0/bin/ ./t9999-test.sh -x
  Unknown option: -c
  usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate|--no-pager] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]
  error: cannot run git init -- have you built things yet?
Quoted 4 lines
t/test-lib-functions.sh +0 -0
 		error "cannot run git init -- have you built things yet?"
 		mv .git/hooks .git/hooks-disabled
Signature · 1 line
gitgitgadget
#55 lore raw

Re: [PATCH v5 4/4] init: provide useful advice about init.defaultBranch

Quoted 9 lines · SZEDER Gábor

t/test-lib-functions.sh test_create_repo () { · line 1208

Quoted 5 lines
t/test-lib-functions.sh +3 -1
-		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" init \
+		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" -c \
+			init.defaultBranch="${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME-master}" \
+			init \
 			"--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||

This breaks GIT_TEST_INSTALLED when the given Git version doesn't yet contain 8b1fa77867 (Allow passing of configuration parameters in the command line, 2010-03-26):

Yes, but test-installed is about running an old version of Git on the current Git test suite. In the tests we make liberal use of "git -c <var>=<val>", which such an old version of Git has no chance of passing. So...

#56 lore raw

Re: [PATCH v5 4/4] init: provide useful advice about init.defaultBranch

Quoted 12 lines · Junio C Hamano
Quoted 9 lines · SZEDER Gábor

t/test-lib-functions.sh test_create_repo () { · line 1208

Quoted 5 lines
t/test-lib-functions.sh +3 -1
-		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" init \
+		"${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" -c \
+			init.defaultBranch="${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME-master}" \
+			init \
 			"--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 ||

This breaks GIT_TEST_INSTALLED when the given Git version doesn't yet contain 8b1fa77867 (Allow passing of configuration parameters in the command line, 2010-03-26):

Quoted 4 lines

Yes, but test-installed is about running an old version of Git on the current Git test suite. In the tests we make liberal use of "git -c <var>=<val>", which such an old version of Git has no chance of passing. So...

I've never run the whole test suite with GIT_TEST_INSTALLED for the exact reason you mentioned. However, I do regularly use it with custom tests using only commands and options that already existed as early as v1.6.0 (my go-to "old" version) to check when some interesting or puzzling behavior appeared, and did just that yesterday as well.