Message ID | 90912e32da1192cfc3b39a18cb606caa46e85b1c.1591823971.git.gitgitgadget@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Allow overriding the default name of the default branch | expand |
On 2020-06-10 at 21:19:22, Don Goodman-Wilson via GitGitGadget wrote: > + /* prepend "refs/heads/" to the branch name */ > + prefixed = xstrfmt("refs/heads/%s", branch_name); > + if (check_refname_format(prefixed, 0)) > + die(_("invalid default branch name: '%s'"), branch_name); I'm glad to see this part and a check for it in the test below. We wouldn't want a typo to create a broken branch name. > +test_expect_success 'invalid custom default branch name' ' > + test_must_fail env GIT_TEST_DEFAULT_BRANCH_NAME="with space" \ > + git init custom-invalid 2>err && > + test_i18ngrep "invalid default branch name" err > +' > +
On Wed, Jun 10, 2020 at 5:19 PM Don Goodman-Wilson via GitGitGadget <gitgitgadget@gmail.com> wrote: > [...] > To make this process much less cumbersome, let's introduce support for > `core.defaultBranchName`. That way, users won't need to keep their > copied template files up to date, and won't interfere with default hooks > installed by their administrators. > [...] > Signed-off-by: Don Goodman-Wilson <don@goodman-wilson.com> > --- > diff --git a/refs.c b/refs.c > @@ -560,6 +560,40 @@ void expand_ref_prefix(struct argv_array *prefixes, const char *prefix) > + die(_("Could not retrieve `core.defaultBranchName`")); Nit: here the error message is capitalized... > + if (from_config) > + branch_name = from_config; > + else > + branch_name = "master"; Non-actionable nit: could be written: branch_name = from_config ? from_config : "master"; > + } > + > + if (short_name) > + return from_config ? from_config : xstrdup(branch_name); The logic overall is a bit difficult to follow when trying to understand when and when not to duplicate the string and when and when not to free(), but seems to be correct. > + /* prepend "refs/heads/" to the branch name */ > + prefixed = xstrfmt("refs/heads/%s", branch_name); > + if (check_refname_format(prefixed, 0)) > + die(_("invalid default branch name: '%s'"), branch_name); Here, the error message is not capitalized. It would be nice for both messages to share a common capitalization scheme. These days, we tend to favor _not_ capitalizing error messages, so perhaps remove capitalization from the earlier one. > +/* > + * Retrieves the name of the default branch. If `short_name` is non-zero, the > + * branch name will be prefixed with "refs/heads/". > + */ > +char *git_default_branch_name(int short_name); Overall, the internal logic regarding duplicating/freeing strings would probably be easier to grok if there were two separate functions: char *git_default_branch_name(void); char *git_default_ref_name(void); but that's subjective.
On 10/06/2020 22:19, Don Goodman-Wilson via GitGitGadget wrote: > From: Don Goodman-Wilson <don@goodman-wilson.com> > > There is a growing number of projects trying to avoid the non-inclusive > name `master` in their repositories. I think it would be helpful to explain why 'master' is no-inclusive even if it originates from the concept of a master copy. i.e. it suggests master/slave even if git is not based on that concept. Have you got some examples of projects that have changed and the names that they are using? I think it would be helpful if we can agree on a replacement for master - if every repository uses a different name for its main branch it adds an extra complication for new contributors to those projects. For existing repositories, this > requires manual work. For new repositories, the only way to do that > automatically is by copying all of Git's template directory, then > hard-coding the desired default branch name into the `.git/HEAD` file, > and then configuring `init.templateDir` to point to those copied > template files. > > To make this process much less cumbersome, let's introduce support for > `core.defaultBranchName`. That way, users won't need to keep their > copied template files up to date, and won't interfere with default hooks > installed by their administrators. > > While at it, also let users set the default branch name via the > environment variable `GIT_TEST_DEFAULT_BRANCH_NAME`, I'm not sure we usually promote the use of GIT_TEST_... environment variables outside of the test suite. > in preparation for > adjusting Git's test suite to a more inclusive default branch name. As > is common in Git, the `GIT_TEST_*` variable takes precedence over the > config setting. > > Note: we use the prefix `core.` instead of `init.` because we want to > adjust also `git clone`, `git fmt-merge-msg` and other commands over the > course of the next commits to respect this setting. > > Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de> > Helped-by: Derrick Stolee <dstolee@microsoft.com> > Signed-off-by: Don Goodman-Wilson <don@goodman-wilson.com> > --- > builtin/init-db.c | 8 +++++--- > refs.c | 34 ++++++++++++++++++++++++++++++++++ > refs.h | 6 ++++++ > t/t0001-init.sh | 20 ++++++++++++++++++++ > 4 files changed, 65 insertions(+), 3 deletions(-) > > diff --git a/builtin/init-db.c b/builtin/init-db.c > index 0b7222e7188..99792adfd43 100644 > --- a/builtin/init-db.c > +++ b/builtin/init-db.c > @@ -258,15 +258,17 @@ static int create_default_files(const char *template_path, > die("failed to set up refs db: %s", err.buf); > > /* > - * Create the default symlink from ".git/HEAD" to the "master" > - * branch, if it does not exist yet. > + * Create the default symlink from ".git/HEAD" to the default > + * branch name, if it does not exist yet. > */ > path = git_path_buf(&buf, "HEAD"); > reinit = (!access(path, R_OK) > || readlink(path, junk, sizeof(junk)-1) != -1); > if (!reinit) { > - if (create_symref("HEAD", "refs/heads/master", NULL) < 0) > + char *default_ref = git_default_branch_name(0); > + if (create_symref("HEAD", default_ref, NULL) < 0) > exit(1); > + free(default_ref); > } > > initialize_repository_version(fmt->hash_algo); > diff --git a/refs.c b/refs.c > index 224ff66c7bb..8499b3865cb 100644 > --- a/refs.c > +++ b/refs.c > @@ -560,6 +560,40 @@ void expand_ref_prefix(struct argv_array *prefixes, const char *prefix) > argv_array_pushf(prefixes, *p, len, prefix); > } > > +char *git_default_branch_name(int short_name) > +{ > + const char *branch_name = getenv("GIT_TEST_DEFAULT_BRANCH_NAME"); > + char *from_config = NULL, *prefixed; > + > + /* > + * If the default branch name was not specified via the environment > + * variable GIT_TEST_DEFAULT_BRANCH_NAME, retrieve it from the config > + * setting core.defaultBranchName. If neither are set, fall back to the > + * hard-coded default. > + */ > + if (!branch_name || !*branch_name) { > + if (git_config_get_string("core.defaultbranchname", > + &from_config) < 0) > + die(_("Could not retrieve `core.defaultBranchName`")); > + > + if (from_config) > + branch_name = from_config; > + else > + branch_name = "master"; > + } > + > + if (short_name) > + return from_config ? from_config : xstrdup(branch_name); If short_name is set we return without validating the name is that intentional? > + > + /* prepend "refs/heads/" to the branch name */ > + prefixed = xstrfmt("refs/heads/%s", branch_name); > + if (check_refname_format(prefixed, 0)) > + die(_("invalid default branch name: '%s'"), branch_name); > + > + free(from_config); > + return prefixed; > +} > + > /* > * *string and *len will only be substituted, and *string returned (for > * later free()ing) if the string passed in is a magic short-hand form > diff --git a/refs.h b/refs.h > index a92d2c74c83..e8d4f6e2f13 100644 > --- a/refs.h > +++ b/refs.h > @@ -154,6 +154,12 @@ int repo_dwim_log(struct repository *r, const char *str, int len, struct object_ > int dwim_ref(const char *str, int len, struct object_id *oid, char **ref); > int dwim_log(const char *str, int len, struct object_id *oid, char **ref); > > +/* > + * Retrieves the name of the default branch. If `short_name` is non-zero, the > + * branch name will be prefixed with "refs/heads/". Isn't the other way around - the branch name is prefixed with "refs/heads/" if short is zero. > + */ > +char *git_default_branch_name(int short_name); > + > /* > * A ref_transaction represents a collection of reference updates that > * should succeed or fail together. > diff --git a/t/t0001-init.sh b/t/t0001-init.sh > index 1edd5aeb8f0..b144cd8f46b 100755 > --- a/t/t0001-init.sh > +++ b/t/t0001-init.sh > @@ -464,4 +464,24 @@ test_expect_success MINGW 'redirect std handles' ' > grep "Needed a single revision" output.txt > ' > > +test_expect_success 'custom default branch name from config' ' > + git config --global core.defaultbranchname nmb && In tests we usually use 'test_config' rather than 'git config' as the former automatically cleans up the config at the end of the test. > + GIT_TEST_DEFAULT_BRANCH_NAME= git init custom-config && > + git config --global --unset core.defaultbranchname && > + git -C custom-config symbolic-ref HEAD >actual && > + grep nmb actual > +' > + > +test_expect_success 'custom default branch name from env' ' > + GIT_TEST_DEFAULT_BRANCH_NAME=nmb git init custom-env && It would be good to test that this overrides the config setting Best Wishes Phillip > + git -C custom-env symbolic-ref HEAD >actual && > + grep nmb actual > +' > + > +test_expect_success 'invalid custom default branch name' ' > + test_must_fail env GIT_TEST_DEFAULT_BRANCH_NAME="with space" \ > + git init custom-invalid 2>err && > + test_i18ngrep "invalid default branch name" err > +' > + > test_done >
Hi Don & Johannes, Le 10/06/2020 à 23:19, Don Goodman-Wilson via GitGitGadget a écrit : > From: Don Goodman-Wilson <don@goodman-wilson.com> > > There is a growing number of projects trying to avoid the non-inclusive > name `master` in their repositories. For existing repositories, this > requires manual work. For new repositories, the only way to do that > automatically is by copying all of Git's template directory, then > hard-coding the desired default branch name into the `.git/HEAD` file, > and then configuring `init.templateDir` to point to those copied > template files. > > To make this process much less cumbersome, let's introduce support for > `core.defaultBranchName`. That way, users won't need to keep their > copied template files up to date, and won't interfere with default hooks > installed by their administrators. > > While at it, also let users set the default branch name via the > environment variable `GIT_TEST_DEFAULT_BRANCH_NAME`, in preparation for > adjusting Git's test suite to a more inclusive default branch name. As > is common in Git, the `GIT_TEST_*` variable takes precedence over the > config setting. > Why adding yet another environment variable instead of relying only on a config option? I understand it's for the tests, but can't we add a shell function in test-lib.sh (and friends) that tries to read `GIT_TEST_DEFAULT_BRANCH_NAME', and, if it exists, sets `core.defaultBranchName'? Cheers, Alban
Hi Eric, On Wed, 10 Jun 2020, Eric Sunshine wrote: > On Wed, Jun 10, 2020 at 5:19 PM Don Goodman-Wilson via GitGitGadget > <gitgitgadget@gmail.com> wrote: > > [...] > > To make this process much less cumbersome, let's introduce support for > > `core.defaultBranchName`. That way, users won't need to keep their > > copied template files up to date, and won't interfere with default hooks > > installed by their administrators. > > [...] > > Signed-off-by: Don Goodman-Wilson <don@goodman-wilson.com> > > --- > > diff --git a/refs.c b/refs.c > > @@ -560,6 +560,40 @@ void expand_ref_prefix(struct argv_array *prefixes, const char *prefix) > > + die(_("Could not retrieve `core.defaultBranchName`")); > > Nit: here the error message is capitalized... I downcased it... > > + if (from_config) > > + branch_name = from_config; > > + else > > + branch_name = "master"; > > Non-actionable nit: could be written: > > branch_name = from_config ? from_config : "master"; Good call. > > + } > > + > > + if (short_name) > > + return from_config ? from_config : xstrdup(branch_name); > > The logic overall is a bit difficult to follow when trying to > understand when and when not to duplicate the string and when and when > not to free(), but seems to be correct. I agree that it is a bit hard to follow, but then, the function is really short, so I hoped it is okay. > > + /* prepend "refs/heads/" to the branch name */ > > + prefixed = xstrfmt("refs/heads/%s", branch_name); > > + if (check_refname_format(prefixed, 0)) > > + die(_("invalid default branch name: '%s'"), branch_name); > > Here, the error message is not capitalized. It would be nice for both > messages to share a common capitalization scheme. These days, we tend > to favor _not_ capitalizing error messages, so perhaps remove > capitalization from the earlier one. > > > +/* > > + * Retrieves the name of the default branch. If `short_name` is non-zero, the > > + * branch name will be prefixed with "refs/heads/". > > + */ > > +char *git_default_branch_name(int short_name); > > Overall, the internal logic regarding duplicating/freeing strings > would probably be easier to grok if there were two separate functions: > > char *git_default_branch_name(void); > char *git_default_ref_name(void); > > but that's subjective. For such a tiny nuance, I'd rather keep it as one function... Thank you, Dscho
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes: >> Overall, the internal logic regarding duplicating/freeing strings >> would probably be easier to grok if there were two separate functions: >> >> char *git_default_branch_name(void); >> char *git_default_ref_name(void); >> >> but that's subjective. > > For such a tiny nuance, I'd rather keep it as one function... And you'd need two functions, default and primary, possibly full and short. Splitting these into two here would mean you'd need four.
Alban Gruin <alban.gruin@gmail.com> writes: > Why adding yet another environment variable instead of relying only on a > config option? I understand it's for the tests, but can't we add a > shell function in test-lib.sh (and friends) that tries to read > `GIT_TEST_DEFAULT_BRANCH_NAME', and, if it exists, sets > `core.defaultBranchName'? Can you produce such a patch that does it cleanly? My knee jerk reaction is that I would suspect that you end up having to touch many places in the t/ scripts, but if you prove otherwise, that would certainly be appreciated. And no, git () { command git -c core.defaultBranchName=master "$@" } is not an acceptable solution.
On 2020-06-11 at 23:14:46, Junio C Hamano wrote: > Alban Gruin <alban.gruin@gmail.com> writes: > > > Why adding yet another environment variable instead of relying only on a > > config option? I understand it's for the tests, but can't we add a > > shell function in test-lib.sh (and friends) that tries to read > > `GIT_TEST_DEFAULT_BRANCH_NAME', and, if it exists, sets > > `core.defaultBranchName'? > > Can you produce such a patch that does it cleanly? My knee jerk > reaction is that I would suspect that you end up having to touch > many places in the t/ scripts, but if you prove otherwise, that > would certainly be appreciated. > > And no, > > git () { command git -c core.defaultBranchName=master "$@" } > > is not an acceptable solution. I would also be delighted to see such a solution, but my experience with the SHA-256 work tells me there's unlikely to be one. We do a lot of "git init" operations in random places in the test suite and as a consequence it's very hard to make a change without touching a large number of tests. If we were writing things today, perhaps we would use a function (e.g., test_init_repo or such) to wrap this case, but we unfortunately didn't think about that and we're stuck with what we have now unless someone retrofits the test suite.
Hi Phillip, On Thu, 11 Jun 2020, Phillip Wood wrote: > On 10/06/2020 22:19, Don Goodman-Wilson via GitGitGadget wrote: > > From: Don Goodman-Wilson <don@goodman-wilson.com> > > > > There is a growing number of projects trying to avoid the non-inclusive > > name `master` in their repositories. > > I think it would be helpful to explain why 'master' is no-inclusive even > if it originates from the concept of a master copy. i.e. it suggests > master/slave even if git is not based on that concept. Unfortunately, we do not even have that defense: the term `master` was copied from BitKeeper, which firmly uses it in the `master/slave` context. See e.g. https://mail.gnome.org/archives/desktop-devel-list/2019-May/msg00066.html I added a _brief_ extension to the context to the first commit's commit message. However, I do not want to go into details here because _this_ patch series is only about empowering users to change their default main branch name. > Have you got some examples of projects that have changed and the names > that they are using? Yes, there are plenty examples, and I do not want to pick a tiny subset to demonstrate that. A more useful resource is probably this post: https://www.hanselman.com/blog/EasilyRenameYourGitDefaultBranchFromMasterToMain.aspx > I think it would be helpful if we can agree on a replacement for master > - if every repository uses a different name for its main branch it adds > an extra complication for new contributors to those projects. Sure, and that's what I thought we'd discuss, too, maybe at the meeting I proposed elsewhere (Emily started a new thread about it: https://lore.kernel.org/git/20200610222719.GE148632@google.com/). > > For existing repositories, this > > requires manual work. For new repositories, the only way to do that > > automatically is by copying all of Git's template directory, then > > hard-coding the desired default branch name into the `.git/HEAD` file, > > and then configuring `init.templateDir` to point to those copied > > template files. > > > > To make this process much less cumbersome, let's introduce support for > > `core.defaultBranchName`. That way, users won't need to keep their > > copied template files up to date, and won't interfere with default hooks > > installed by their administrators. > > > > While at it, also let users set the default branch name via the > > environment variable `GIT_TEST_DEFAULT_BRANCH_NAME`, > > I'm not sure we usually promote the use of GIT_TEST_... environment > variables outside of the test suite. True. Together with Alban's suggestion to make this purely work in the test suite (i.e. not even adjust the C code to respect that environment variable), you convinced me to (re-)move that part of the commit. > > diff --git a/refs.c b/refs.c > > index 224ff66c7bb..8499b3865cb 100644 > > --- a/refs.c > > +++ b/refs.c > > @@ -560,6 +560,40 @@ void expand_ref_prefix(struct argv_array *prefixes, const char *prefix) > > argv_array_pushf(prefixes, *p, len, prefix); > > } > > > > +char *git_default_branch_name(int short_name) > > +{ > > + const char *branch_name = getenv("GIT_TEST_DEFAULT_BRANCH_NAME"); > > + char *from_config = NULL, *prefixed; > > + > > + /* > > + * If the default branch name was not specified via the environment > > + * variable GIT_TEST_DEFAULT_BRANCH_NAME, retrieve it from the config > > + * setting core.defaultBranchName. If neither are set, fall back to the > > + * hard-coded default. > > + */ > > + if (!branch_name || !*branch_name) { > > + if (git_config_get_string("core.defaultbranchname", > > + &from_config) < 0) > > + die(_("Could not retrieve `core.defaultBranchName`")); > > + > > + if (from_config) > > + branch_name = from_config; > > + else > > + branch_name = "master"; > > + } > > + > > + if (short_name) > > + return from_config ? from_config : xstrdup(branch_name); > > If short_name is set we return without validating the name is that > intentional? No, unintentional. Thank you for pointing this out. It will be fixed in v2 (still working on it). > > + > > + /* prepend "refs/heads/" to the branch name */ > > + prefixed = xstrfmt("refs/heads/%s", branch_name); > > + if (check_refname_format(prefixed, 0)) > > + die(_("invalid default branch name: '%s'"), branch_name); > > + > > + free(from_config); > > + return prefixed; > > +} > > + > > /* > > * *string and *len will only be substituted, and *string returned (for > > * later free()ing) if the string passed in is a magic short-hand form > > diff --git a/refs.h b/refs.h > > index a92d2c74c83..e8d4f6e2f13 100644 > > --- a/refs.h > > +++ b/refs.h > > @@ -154,6 +154,12 @@ int repo_dwim_log(struct repository *r, const char *str, int len, struct object_ > > int dwim_ref(const char *str, int len, struct object_id *oid, char **ref); > > int dwim_log(const char *str, int len, struct object_id *oid, char **ref); > > > > +/* > > + * Retrieves the name of the default branch. If `short_name` is non-zero, the > > + * branch name will be prefixed with "refs/heads/". > > Isn't the other way around - the branch name is prefixed with > "refs/heads/" if short is zero. Absolutely. Thank you for your careful review, I read past this at least half a dozen times. > > + */ > > +char *git_default_branch_name(int short_name); > > + > > /* > > * A ref_transaction represents a collection of reference updates that > > * should succeed or fail together. > > diff --git a/t/t0001-init.sh b/t/t0001-init.sh > > index 1edd5aeb8f0..b144cd8f46b 100755 > > --- a/t/t0001-init.sh > > +++ b/t/t0001-init.sh > > @@ -464,4 +464,24 @@ test_expect_success MINGW 'redirect std handles' ' > > grep "Needed a single revision" output.txt > > ' > > > > +test_expect_success 'custom default branch name from config' ' > > + git config --global core.defaultbranchname nmb && > > In tests we usually use 'test_config' rather than 'git config' as the > former automatically cleans up the config at the end of the test. Right, and in this instance it is `test_config_global`. > > + GIT_TEST_DEFAULT_BRANCH_NAME= git init custom-config && > > + git config --global --unset core.defaultbranchname && > > + git -C custom-config symbolic-ref HEAD >actual && > > + grep nmb actual > > +' > > + > > +test_expect_success 'custom default branch name from env' ' > > + GIT_TEST_DEFAULT_BRANCH_NAME=nmb git init custom-env && > > It would be good to test that this overrides the config setting Except that we'll make this a thing that is internal to the test suite now. So this test case can go. Thank you for helping me improve the patch series! Dscho
Hi brian, On Thu, 11 Jun 2020, brian m. carlson wrote: > On 2020-06-11 at 23:14:46, Junio C Hamano wrote: > > Alban Gruin <alban.gruin@gmail.com> writes: > > > > > Why adding yet another environment variable instead of relying only on a > > > config option? I understand it's for the tests, but can't we add a > > > shell function in test-lib.sh (and friends) that tries to read > > > `GIT_TEST_DEFAULT_BRANCH_NAME', and, if it exists, sets > > > `core.defaultBranchName'? > > > > Can you produce such a patch that does it cleanly? My knee jerk > > reaction is that I would suspect that you end up having to touch > > many places in the t/ scripts, but if you prove otherwise, that > > would certainly be appreciated. > > > > And no, > > > > git () { command git -c core.defaultBranchName=master "$@" } > > > > is not an acceptable solution. > > I would also be delighted to see such a solution, but my experience with > the SHA-256 work tells me there's unlikely to be one. We do a lot of > "git init" operations in random places in the test suite and as a > consequence it's very hard to make a change without touching a large > number of tests. That's a valid point, indeed. > If we were writing things today, perhaps we would use a function (e.g., > test_init_repo or such) to wrap this case, but we unfortunately didn't > think about that and we're stuck with what we have now unless someone > retrofits the test suite. There is actually `test_create_repo` (see https://github.com/git/git/blob/v2.27.0/t/test-lib-functions.sh#L1145-L1159): # Most tests can use the created repository, but some may need to create # more. # Usage: test_create_repo <directory> test_create_repo () { test "$#" = 1 || BUG "not 1 parameter to test-create-repo" repo="$1" mkdir -p "$repo" ( cd "$repo" || error "Cannot setup test environment" "${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" 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 ) || exit } But I agree that few test scripts use it: $ git grep 'git init' v2.27.0 -- t/ | wc -l 765 $ git grep 'test_create_repo' v2.27.0 -- t/ | wc -l 296 Ciao, Dscho
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes: > I added a _brief_ extension to the context to the first commit's commit > message. However, I do not want to go into details here because _this_ > patch series is only about empowering users to change their default main > branch name. Sensible. And I do not think the planned follow-up work to rename 'master' to something else needs to be defended with lengthy history lessons. Sufficiently large part of the user population are unhappy with the use of the word 'master' as the default name of the primary branch in a newly created repository, and the mere fact that we are aware of that is good enough justification to move _away_ from 'master'. In other words, we do not have to explain why 'master' was bad, as it does not have to be bad for everybody to be replaced. But you need to defend that the new word you picked is something everybody is happy with. That is much harder ;-).
Hi Junio, Le 12/06/2020 à 01:14, Junio C Hamano a écrit : > Alban Gruin <alban.gruin@gmail.com> writes: > >> Why adding yet another environment variable instead of relying only on a >> config option? I understand it's for the tests, but can't we add a >> shell function in test-lib.sh (and friends) that tries to read >> `GIT_TEST_DEFAULT_BRANCH_NAME', and, if it exists, sets >> `core.defaultBranchName'? > > Can you produce such a patch that does it cleanly? My knee jerk > reaction is that I would suspect that you end up having to touch > many places in the t/ scripts, but if you prove otherwise, that > would certainly be appreciated. > > And no, > > git () { command git -c core.defaultBranchName=master "$@" } > > is not an acceptable solution. > I wanted to to do something like this: if test -n "$GIT_TEST_DEFAULT_BRANCH_NAME"; then git config core.defaultBranchName "$GIT_TEST_DEFAULT_BRANCH_NAME" fi But since we do not have a repository to store the config, it won't work. Sorry for the noise. Alban
Hi Alban, On Sat, 13 Jun 2020, Alban Gruin wrote: > Hi Junio, > > Le 12/06/2020 à 01:14, Junio C Hamano a écrit : > > Alban Gruin <alban.gruin@gmail.com> writes: > > > >> Why adding yet another environment variable instead of relying only on a > >> config option? I understand it's for the tests, but can't we add a > >> shell function in test-lib.sh (and friends) that tries to read > >> `GIT_TEST_DEFAULT_BRANCH_NAME', and, if it exists, sets > >> `core.defaultBranchName'? > > > > Can you produce such a patch that does it cleanly? My knee jerk > > reaction is that I would suspect that you end up having to touch > > many places in the t/ scripts, but if you prove otherwise, that > > would certainly be appreciated. > > > > And no, > > > > git () { command git -c core.defaultBranchName=master "$@" } > > > > is not an acceptable solution. > > > > I wanted to to do something like this: > > if test -n "$GIT_TEST_DEFAULT_BRANCH_NAME"; > then > git config core.defaultBranchName "$GIT_TEST_DEFAULT_BRANCH_NAME" > fi > > But since we do not have a repository to store the config, it won't > work. Sorry for the noise. We actually would have `~/.gitconfig` because `HOME` is set to `t/trash directory.<test-name>/`. However, that would cause all kinds of issues when test scripts expect the directory to be pristine, containing only `.git/` but not `.gitconfig`. It was a good idea to bring up; I share brian's sentiment that it would have been nice if it would have worked out. Ciao, Dscho
Hi Junio, On Fri, 12 Jun 2020, Junio C Hamano wrote: > Johannes Schindelin <Johannes.Schindelin@gmx.de> writes: > > > I added a _brief_ extension to the context to the first commit's commit > > message. However, I do not want to go into details here because _this_ > > patch series is only about empowering users to change their default main > > branch name. > > Sensible. > > And I do not think the planned follow-up work to rename 'master' to > something else needs to be defended with lengthy history lessons. Yes, I agree. It is probably sufficient to just point at a couple high-profile projects that already made the switch to `main`. > Sufficiently large part of the user population are unhappy with the > use of the word 'master' as the default name of the primary branch > in a newly created repository, and the mere fact that we are aware > of that is good enough justification to move _away_ from 'master'. Yes, even Pasky says he regrets the choice of term (see https://twitter.com/xpasky/status/1271477451756056577): I picked the names "master" (and "origin") in the early Git tooling back in 2005. (this probably means you shouldn't give much weight to my name preferences :) ) I have wished many times I would have named them "main" (and "upstream") instead. > In other words, we do not have to explain why 'master' was bad, as > it does not have to be bad for everybody to be replaced. > > But you need to defend that the new word you picked is something > everybody is happy with. That is much harder ;-). To be honest, I stopped looking for got arguments in favor of one name after a couple days, and instead focused on the consensus I saw: Chrome [*1*] and node.js [*2*] apparently stated publicly that they want to change their main branches to `main`, and GitLab [*3*] and GitHub [*4*] seem to intend to change the default for new repositories accordingly. It is not like we have to decide for the community (as we did back in 2005). I am actually quite relieved about that. Ciao, Dscho URL *1*: https://twitter.com/Una/status/1271180494944829441 URL *2*: https://github.com/nodejs/node/issues/33864 URL *3*: https://gitlab.com/gitlab-org/gitlab/-/issues/221164 URL *4*: https://twitter.com/natfriedman/status/1271253144442253312 (this is not really a public announcement, I agree, but it is a public Tweet by the CEO)
On 12/06/2020 17:51, Junio C Hamano wrote: > Johannes Schindelin <Johannes.Schindelin@gmx.de> writes: > >> I added a _brief_ extension to the context to the first commit's commit >> message. However, I do not want to go into details here because _this_ >> patch series is only about empowering users to change their default main >> branch name. > > [...] > > Sufficiently large part of the user population are unhappy with the > use of the word 'master' as the default name of the primary branch > in a newly created repository, and the mere fact that we are aware > of that is good enough justification to move _away_ from 'master'. > In other words, we do not have to explain why 'master' was bad, as > it does not have to be bad for everybody to be replaced. This expresses what I was trying to get at with my comments much more clearly than I managed - Thank you > > But you need to defend that the new word you picked is something > everybody is happy with. That is much harder ;-). Indeed, though I am more optimistic about that having seen a couple of people have indicated that they don't mind too much what we choose so long as it unlikely to cause future problems. Best Wishes Phillip
On Sun, Jun 14, 2020 at 10:57:41AM +0200, Johannes Schindelin wrote: > > >> Why adding yet another environment variable instead of relying only on a > > >> config option? I understand it's for the tests, but can't we add a > > >> shell function in test-lib.sh (and friends) that tries to read > > >> `GIT_TEST_DEFAULT_BRANCH_NAME', and, if it exists, sets > > >> `core.defaultBranchName'? > > > > > > Can you produce such a patch that does it cleanly? My knee jerk > > > reaction is that I would suspect that you end up having to touch > > > many places in the t/ scripts, but if you prove otherwise, that > > > would certainly be appreciated. > > > > > > And no, > > > > > > git () { command git -c core.defaultBranchName=master "$@" } > > > > > > is not an acceptable solution. > > > > > > > I wanted to to do something like this: > > > > if test -n "$GIT_TEST_DEFAULT_BRANCH_NAME"; > > then > > git config core.defaultBranchName "$GIT_TEST_DEFAULT_BRANCH_NAME" > > fi > > > > But since we do not have a repository to store the config, it won't > > work. Sorry for the noise. > > We actually would have `~/.gitconfig` because `HOME` is set to `t/trash > directory.<test-name>/`. > > However, that would cause all kinds of issues when test scripts expect the > directory to be pristine, containing only `.git/` but not `.gitconfig`. Putting: GIT_CONFIG_PARAMETERS="'core.defaultBranchName=...'" into the environment would work (and yes, you need the single quotes embedded in the variable), and solves all of the complaints above. Further "git -c" invocations properly append to it. But: - there are a few tests which explicitly tweak that variable - it technically changes any tests of "-c" because now we'd never cover the case where we start without the variable defined I think baking in a special environment variable like you have is not so bad. If this did become too common a pattern, though (special test-only environment variables that do have a separate config option), I wouldn't be opposed to a GIT_TEST_CONFIG_PARAMETERS which takes precedence over other config, and comes with a big warning label that it shouldn't be relied upon outside the test suite. That's equally ugly to GIT_TEST_DEFAULT_BRANCH_NAME, but at least solves the problem once for all of them. I'm just not sure we have enough "all of them" to make it worth doing. -Peff
On Wed, Jun 10, 2020 at 08:16:38PM -0400, Eric Sunshine wrote: > > +/* > > + * Retrieves the name of the default branch. If `short_name` is non-zero, the > > + * branch name will be prefixed with "refs/heads/". > > + */ > > +char *git_default_branch_name(int short_name); > > Overall, the internal logic regarding duplicating/freeing strings > would probably be easier to grok if there were two separate functions: > > char *git_default_branch_name(void); > char *git_default_ref_name(void); > > but that's subjective. Having seen one of the callers, might it be worth avoiding handing off ownership of the string entirely? I.e., this comes from a string that's already owned for the lifetime of the process (either the environment, or a string stored by the config machinery). Could we just pass that back (or if we want to be more careful about getenv() lifetimes, we can copy it into a static owned by this function)? Then all of the callers can stop dealing with the extra free(), and you can do: const char *git_default_branch_name(void) { return skip_prefix("refs/heads/", git_default_ref_name()); } -Peff
On Tue, Jun 16, 2020 at 08:45:02AM -0400, Jeff King wrote: > On Wed, Jun 10, 2020 at 08:16:38PM -0400, Eric Sunshine wrote: > > > > +/* > > > + * Retrieves the name of the default branch. If `short_name` is non-zero, the > > > + * branch name will be prefixed with "refs/heads/". > > > + */ > > > +char *git_default_branch_name(int short_name); > > > > Overall, the internal logic regarding duplicating/freeing strings > > would probably be easier to grok if there were two separate functions: > > > > char *git_default_branch_name(void); > > char *git_default_ref_name(void); > > > > but that's subjective. > > Having seen one of the callers, might it be worth avoiding handing off > ownership of the string entirely? > > I.e., this comes from a string that's already owned for the lifetime of > the process (either the environment, or a string stored by the config > machinery). Could we just pass that back (or if we want to be more > careful about getenv() lifetimes, we can copy it into a static owned by > this function)? > > Then all of the callers can stop dealing with the extra free(), and you > can do: > > const char *git_default_branch_name(void) > { > return skip_prefix("refs/heads/", git_default_ref_name()); > } Actually, one small hiccup is that the config option specifies the branch name, not the ref name. So you really would have to prepare a static-owned copy of it to turn "foo" into "refs/heads/foo" to get the refname. On the other hand, that would also be a good time to run check_ref_format(). In the patch as-is, the "short" return does not check that the branch is a valid name. -Peff
Hi Peff, On Tue, 16 Jun 2020, Jeff King wrote: > On Sun, Jun 14, 2020 at 10:57:41AM +0200, Johannes Schindelin wrote: > > > > >> Why adding yet another environment variable instead of relying only on a > > > >> config option? I understand it's for the tests, but can't we add a > > > >> shell function in test-lib.sh (and friends) that tries to read > > > >> `GIT_TEST_DEFAULT_BRANCH_NAME', and, if it exists, sets > > > >> `core.defaultBranchName'? > > > > > > > > Can you produce such a patch that does it cleanly? My knee jerk > > > > reaction is that I would suspect that you end up having to touch > > > > many places in the t/ scripts, but if you prove otherwise, that > > > > would certainly be appreciated. > > > > > > > > And no, > > > > > > > > git () { command git -c core.defaultBranchName=master "$@" } > > > > > > > > is not an acceptable solution. > > > > > > > > > > I wanted to to do something like this: > > > > > > if test -n "$GIT_TEST_DEFAULT_BRANCH_NAME"; > > > then > > > git config core.defaultBranchName "$GIT_TEST_DEFAULT_BRANCH_NAME" > > > fi > > > > > > But since we do not have a repository to store the config, it won't > > > work. Sorry for the noise. > > > > We actually would have `~/.gitconfig` because `HOME` is set to `t/trash > > directory.<test-name>/`. > > > > However, that would cause all kinds of issues when test scripts expect the > > directory to be pristine, containing only `.git/` but not `.gitconfig`. > > Putting: > > GIT_CONFIG_PARAMETERS="'core.defaultBranchName=...'" > > into the environment would work (and yes, you need the single quotes > embedded in the variable), and solves all of the complaints above. > Further "git -c" invocations properly append to it. But: > > - there are a few tests which explicitly tweak that variable > > - it technically changes any tests of "-c" because now we'd never > cover the case where we start without the variable defined Indeed. > I think baking in a special environment variable like you have is not so > bad. If this did become too common a pattern, though (special test-only > environment variables that do have a separate config option), I wouldn't > be opposed to a GIT_TEST_CONFIG_PARAMETERS which takes precedence over > other config, and comes with a big warning label that it shouldn't be > relied upon outside the test suite. That's equally ugly to > GIT_TEST_DEFAULT_BRANCH_NAME, but at least solves the problem once for > all of them. I'm just not sure we have enough "all of them" to make it > worth doing. FWIW I do not plan on using that variable for a long time. And it is not in this here patch series any longer, so let's discuss it in the future patch contribution of mine. Thanks, Dscho
Hi Peff, On Tue, 16 Jun 2020, Jeff King wrote: > On Tue, Jun 16, 2020 at 08:45:02AM -0400, Jeff King wrote: > > > On Wed, Jun 10, 2020 at 08:16:38PM -0400, Eric Sunshine wrote: > > > > > > +/* > > > > + * Retrieves the name of the default branch. If `short_name` is non-zero, the > > > > + * branch name will be prefixed with "refs/heads/". > > > > + */ > > > > +char *git_default_branch_name(int short_name); > > > > > > Overall, the internal logic regarding duplicating/freeing strings > > > would probably be easier to grok if there were two separate functions: > > > > > > char *git_default_branch_name(void); > > > char *git_default_ref_name(void); > > > > > > but that's subjective. > > > > Having seen one of the callers, might it be worth avoiding handing off > > ownership of the string entirely? > > > > I.e., this comes from a string that's already owned for the lifetime of > > the process (either the environment, or a string stored by the config > > machinery). Could we just pass that back (or if we want to be more > > careful about getenv() lifetimes, we can copy it into a static owned by > > this function)? > > > > Then all of the callers can stop dealing with the extra free(), and you > > can do: > > > > const char *git_default_branch_name(void) > > { > > return skip_prefix("refs/heads/", git_default_ref_name()); > > } > > Actually, one small hiccup is that the config option specifies the > branch name, not the ref name. So you really would have to prepare a > static-owned copy of it to turn "foo" into "refs/heads/foo" to get the > refname. > > On the other hand, that would also be a good time to run > check_ref_format(). In the patch as-is, the "short" return does not > check that the branch is a valid name. Legit. I will work on this. Thanks, Dscho
Hi Peff, On Tue, 16 Jun 2020, Jeff King wrote: > On Wed, Jun 10, 2020 at 08:16:38PM -0400, Eric Sunshine wrote: > > > > +/* > > > + * Retrieves the name of the default branch. If `short_name` is non-zero, the > > > + * branch name will be prefixed with "refs/heads/". > > > + */ > > > +char *git_default_branch_name(int short_name); > > > > Overall, the internal logic regarding duplicating/freeing strings > > would probably be easier to grok if there were two separate functions: > > > > char *git_default_branch_name(void); > > char *git_default_ref_name(void); > > > > but that's subjective. > > Having seen one of the callers, might it be worth avoiding handing off > ownership of the string entirely? For `git_default_branch_name()`: yes. For `repo_default_branch_name()`, not really, as that is potentially repository-specific. (Side note: while I cannot really think of a use case where you would want to set `init.defaultBranch` in a repository-local config, there _might_ be use cases for that out there, and it _is_ how our config machinery works.) > I.e., this comes from a string that's already owned for the lifetime of > the process (either the environment, or a string stored by the config > machinery). Could we just pass that back (or if we want to be more > careful about getenv() lifetimes, we can copy it into a static owned by > this function)? > > Then all of the callers can stop dealing with the extra free(), and you > can do: > > const char *git_default_branch_name(void) > { > return skip_prefix("refs/heads/", git_default_ref_name()); > } For ease of use, I decided to only ever return the branch name (but check the full ref). Those callers that actually need the full ref usually also need the branch name, and it is easy enough to call `xstrfmt("refs/heads/%s", ...)`. It might make the code a bit less efficient (but who cares, it's not like we're setting up a gazillion repositories per second all the time), but quite a bit easier to reason about. Ciao, Dscho
diff --git a/builtin/init-db.c b/builtin/init-db.c index 0b7222e7188..99792adfd43 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -258,15 +258,17 @@ static int create_default_files(const char *template_path, die("failed to set up refs db: %s", err.buf); /* - * Create the default symlink from ".git/HEAD" to the "master" - * branch, if it does not exist yet. + * Create the default symlink from ".git/HEAD" to the default + * branch name, if it does not exist yet. */ path = git_path_buf(&buf, "HEAD"); reinit = (!access(path, R_OK) || readlink(path, junk, sizeof(junk)-1) != -1); if (!reinit) { - if (create_symref("HEAD", "refs/heads/master", NULL) < 0) + char *default_ref = git_default_branch_name(0); + if (create_symref("HEAD", default_ref, NULL) < 0) exit(1); + free(default_ref); } initialize_repository_version(fmt->hash_algo); diff --git a/refs.c b/refs.c index 224ff66c7bb..8499b3865cb 100644 --- a/refs.c +++ b/refs.c @@ -560,6 +560,40 @@ void expand_ref_prefix(struct argv_array *prefixes, const char *prefix) argv_array_pushf(prefixes, *p, len, prefix); } +char *git_default_branch_name(int short_name) +{ + const char *branch_name = getenv("GIT_TEST_DEFAULT_BRANCH_NAME"); + char *from_config = NULL, *prefixed; + + /* + * If the default branch name was not specified via the environment + * variable GIT_TEST_DEFAULT_BRANCH_NAME, retrieve it from the config + * setting core.defaultBranchName. If neither are set, fall back to the + * hard-coded default. + */ + if (!branch_name || !*branch_name) { + if (git_config_get_string("core.defaultbranchname", + &from_config) < 0) + die(_("Could not retrieve `core.defaultBranchName`")); + + if (from_config) + branch_name = from_config; + else + branch_name = "master"; + } + + if (short_name) + return from_config ? from_config : xstrdup(branch_name); + + /* prepend "refs/heads/" to the branch name */ + prefixed = xstrfmt("refs/heads/%s", branch_name); + if (check_refname_format(prefixed, 0)) + die(_("invalid default branch name: '%s'"), branch_name); + + free(from_config); + return prefixed; +} + /* * *string and *len will only be substituted, and *string returned (for * later free()ing) if the string passed in is a magic short-hand form diff --git a/refs.h b/refs.h index a92d2c74c83..e8d4f6e2f13 100644 --- a/refs.h +++ b/refs.h @@ -154,6 +154,12 @@ int repo_dwim_log(struct repository *r, const char *str, int len, struct object_ int dwim_ref(const char *str, int len, struct object_id *oid, char **ref); int dwim_log(const char *str, int len, struct object_id *oid, char **ref); +/* + * Retrieves the name of the default branch. If `short_name` is non-zero, the + * branch name will be prefixed with "refs/heads/". + */ +char *git_default_branch_name(int short_name); + /* * A ref_transaction represents a collection of reference updates that * should succeed or fail together. diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 1edd5aeb8f0..b144cd8f46b 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -464,4 +464,24 @@ test_expect_success MINGW 'redirect std handles' ' grep "Needed a single revision" output.txt ' +test_expect_success 'custom default branch name from config' ' + git config --global core.defaultbranchname nmb && + GIT_TEST_DEFAULT_BRANCH_NAME= git init custom-config && + git config --global --unset core.defaultbranchname && + git -C custom-config symbolic-ref HEAD >actual && + grep nmb actual +' + +test_expect_success 'custom default branch name from env' ' + GIT_TEST_DEFAULT_BRANCH_NAME=nmb git init custom-env && + git -C custom-env symbolic-ref HEAD >actual && + grep nmb actual +' + +test_expect_success 'invalid custom default branch name' ' + test_must_fail env GIT_TEST_DEFAULT_BRANCH_NAME="with space" \ + git init custom-invalid 2>err && + test_i18ngrep "invalid default branch name" err +' + test_done