{"thread":{"id":"50396","subject":"[PATCH v5 0/1] config: allow giving separate author and committer","startedAt":"2019-02-04T18:49:04Z","lastAt":"2019-04-15T14:24:09Z","messageCount":23,"participants":["William Hubbs","Johannes Schindelin","Junio C Hamano","Ævar Arnfjörð Bjarmason","Jeff King","Derrick Stolee"],"isPatch":true,"patchVersion":5,"patchTotal":1},"messages":[{"id":"368470","messageId":"20190204184850.10040-1-williamh@gentoo.org","threadId":"50396","inReplyTo":null,"subject":"[PATCH v5 0/1] config: allow giving separate author and committer","fromName":"William Hubbs","fromEmail":"williamh@gentoo.org","sentAt":"2019-02-04T18:48:49Z","receivedAt":"2019-02-04T18:49:04Z","isPatch":true,"sender":{"key":"williamh@gentoo.org","avatar":"https://avatars.githubusercontent.com/u/64355?v=4"},"body":"*** BLURB HERE ***\nThis update adds back the reference to the EMAIL environment variable.\n\nWilliam Hubbs (1):\n  config: allow giving separate author and committer idents\n\n Documentation/config/user.txt | 23 ++++++---\n blame.c                       |  3 +-\n builtin/am.c                  |  1 +\n builtin/commit.c              |  3 +-\n cache.h                       | 13 ++++-\n config.c                      |  4 +-\n ident.c                       | 92 ++++++++++++++++++++++++++++++++---\n log-tree.c                    |  3 +-\n sequencer.c                   |  5 +-\n t/t7517-per-repo-email.sh     | 74 ++++++++++++++++++++++++++++\n 10 files changed, 197 insertions(+), 24 deletions(-)\n\n-- \n2.19.2\n\n"},{"id":"368471","messageId":"20190204184850.10040-2-williamh@gentoo.org","threadId":"50396","inReplyTo":"20190204184850.10040-1-williamh@gentoo.org","subject":"[PATCH v5 1/1] config: allow giving separate author and committer idents","fromName":"William Hubbs","fromEmail":"williamh@gentoo.org","sentAt":"2019-02-04T18:48:50Z","receivedAt":"2019-02-04T18:49:10Z","isPatch":true,"sender":{"key":"williamh@gentoo.org","avatar":"https://avatars.githubusercontent.com/u/64355?v=4"},"body":"The author.email, author.name, committer.email and committer.name\nsettings are analogous to the GIT_AUTHOR_* and GIT_COMMITTER_*\nenvironment variables, but for the git config system. This allows them\nto be set separately for each repository.\n\nGit supports setting different authorship and committer\ninformation with environment variables. However, environment variables\nare set in the shell, so if different authorship and committer\ninformation is needed for different repositories an external tool is\nrequired.\n\nThis adds support to git config for author.email, author.name,\ncommitter.email and committer.name  settings so this information\ncan be set per repository.\n\nAlso, it generalizes the fmt_ident function so it can handle author vs\ncommitter identification.\n\nSigned-off-by: William Hubbs <williamh@gentoo.org>\n---\n Documentation/config/user.txt | 23 ++++++---\n blame.c                       |  3 +-\n builtin/am.c                  |  1 +\n builtin/commit.c              |  3 +-\n cache.h                       | 13 ++++-\n config.c                      |  4 +-\n ident.c                       | 92 ++++++++++++++++++++++++++++++++---\n log-tree.c                    |  3 +-\n sequencer.c                   |  5 +-\n t/t7517-per-repo-email.sh     | 74 ++++++++++++++++++++++++++++\n 10 files changed, 197 insertions(+), 24 deletions(-)\n\ndiff --git a/Documentation/config/user.txt b/Documentation/config/user.txt\nindex b5b2ba1199..0557cbbceb 100644\n--- a/Documentation/config/user.txt\n+++ b/Documentation/config/user.txt\n@@ -1,12 +1,19 @@\n-user.email::\n-\tYour email address to be recorded in any newly created commits.\n-\tCan be overridden by the `GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_EMAIL`, and\n-\t`EMAIL` environment variables.  See linkgit:git-commit-tree[1].\n-\n user.name::\n-\tYour full name to be recorded in any newly created commits.\n-\tCan be overridden by the `GIT_AUTHOR_NAME` and `GIT_COMMITTER_NAME`\n-\tenvironment variables.  See linkgit:git-commit-tree[1].\n+user.email::\n+author.name::\n+author.email::\n+committer.name::\n+committer.email::\n+\tThe `user.name` and `user.email` variables determine what ends\n+\tup in the `author` and `committer` field of commit\n+\tobjects.\n+\tIf you need the `author` or `committer` to be different, the\n+\t`author.name`, `author.email`, `committer.name` or\n+\t`committer.email` variables can be set.\n+\tAlso, all of these can be overridden by the `GIT_AUTHOR_NAME`,\n+\t`GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME`,\n+\t`GIT_COMMITTER_EMAIL` and `EMAIL` environment variables.\n+\tSee linkgit:git-commit-tree[1] for more information.\n \n user.useConfigOnly::\n \tInstruct Git to avoid trying to guess defaults for `user.email`\ndiff --git a/blame.c b/blame.c\nindex 43861437f7..c9c351eb36 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -204,7 +204,8 @@ static struct commit *fake_working_tree_commit(struct repository *r,\n \n \torigin = make_origin(commit, path);\n \n-\tident = fmt_ident(\"Not Committed Yet\", \"not.committed.yet\", NULL, 0);\n+\tident = fmt_ident(\"Not Committed Yet\", \"not.committed.yet\",\n+\t\t\tWANT_BLANK_IDENT, NULL, 0);\n \tstrbuf_addstr(&msg, \"tree 0000000000000000000000000000000000000000\\n\");\n \tfor (parent = commit->parents; parent; parent = parent->next)\n \t\tstrbuf_addf(&msg, \"parent %s\\n\",\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 95370313b6..3727d4d267 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -1594,6 +1594,7 @@ static void do_commit(const struct am_state *state)\n \t}\n \n \tauthor = fmt_ident(state->author_name, state->author_email,\n+\t\tWANT_AUTHOR_IDENT,\n \t\t\tstate->ignore_date ? NULL : state->author_date,\n \t\t\tIDENT_STRICT);\n \ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 7d2e0b61e5..98c642d993 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -608,7 +608,8 @@ static void determine_author_info(struct strbuf *author_ident)\n \t\tset_ident_var(&date, strbuf_detach(&date_buf, NULL));\n \t}\n \n-\tstrbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT));\n+\tstrbuf_addstr(author_ident, fmt_ident(name, email, WANT_AUTHOR_IDENT, date,\n+\t\t\t\tIDENT_STRICT));\n \tassert_split_ident(&author, author_ident);\n \texport_one(\"GIT_AUTHOR_NAME\", author.name_begin, author.name_end, 0);\n \texport_one(\"GIT_AUTHOR_EMAIL\", author.mail_begin, author.mail_end, 0);\ndiff --git a/cache.h b/cache.h\nindex 009e8b3b15..e9b870e536 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1494,10 +1494,19 @@ int date_overflows(timestamp_t date);\n #define IDENT_STRICT\t       1\n #define IDENT_NO_DATE\t       2\n #define IDENT_NO_NAME\t       4\n+\n+enum want_ident {\n+\tWANT_BLANK_IDENT,\n+\tWANT_AUTHOR_IDENT,\n+\tWANT_COMMITTER_IDENT\n+};\n+\n extern const char *git_author_info(int);\n extern const char *git_committer_info(int);\n-extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);\n-extern const char *fmt_name(const char *name, const char *email);\n+extern const char *fmt_ident(const char *name, const char *email,\n+\t\tenum want_ident whose_ident,\n+\t\tconst char *date_str, int);\n+extern const char *fmt_name(enum want_ident);\n extern const char *ident_default_name(void);\n extern const char *ident_default_email(void);\n extern const char *git_editor(void);\ndiff --git a/config.c b/config.c\nindex ff521eb27a..13349f308c 100644\n--- a/config.c\n+++ b/config.c\n@@ -1445,7 +1445,9 @@ int git_default_config(const char *var, const char *value, void *cb)\n \tif (starts_with(var, \"core.\"))\n \t\treturn git_default_core_config(var, value, cb);\n \n-\tif (starts_with(var, \"user.\"))\n+\tif (starts_with(var, \"user.\") ||\n+\t\tstarts_with(var, \"author.\") ||\n+\t\t\tstarts_with(var, \"committer.\"))\n \t\treturn git_ident_config(var, value, cb);\n \n \tif (starts_with(var, \"i18n.\"))\ndiff --git a/ident.c b/ident.c\nindex 33bcf40644..9c2eb0a2d0 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -11,6 +11,10 @@\n static struct strbuf git_default_name = STRBUF_INIT;\n static struct strbuf git_default_email = STRBUF_INIT;\n static struct strbuf git_default_date = STRBUF_INIT;\n+static struct strbuf git_author_name = STRBUF_INIT;\n+static struct strbuf git_author_email = STRBUF_INIT;\n+static struct strbuf git_committer_name = STRBUF_INIT;\n+static struct strbuf git_committer_email = STRBUF_INIT;\n static int default_email_is_bogus;\n static int default_name_is_bogus;\n \n@@ -355,13 +359,19 @@ N_(\"\\n\"\n    \"\\n\");\n \n const char *fmt_ident(const char *name, const char *email,\n-\t\t      const char *date_str, int flag)\n+\t\t      enum want_ident whose_ident, const char *date_str, int flag)\n {\n \tstatic struct strbuf ident = STRBUF_INIT;\n \tint strict = (flag & IDENT_STRICT);\n \tint want_date = !(flag & IDENT_NO_DATE);\n \tint want_name = !(flag & IDENT_NO_NAME);\n \n+\tif (!email) {\n+\t\tif (whose_ident == WANT_AUTHOR_IDENT && git_author_email.len)\n+\t\t\temail = git_author_email.buf;\n+\t\telse if (whose_ident == WANT_COMMITTER_IDENT && git_committer_email.len)\n+\t\t\temail = git_committer_email.buf;\n+\t}\n \tif (!email) {\n \t\tif (strict && ident_use_config_only\n \t\t    && !(ident_config_given & IDENT_MAIL_GIVEN)) {\n@@ -377,6 +387,13 @@ const char *fmt_ident(const char *name, const char *email,\n \n \tif (want_name) {\n \t\tint using_default = 0;\n+\t\tif (!name) {\n+\t\t\tif (whose_ident == WANT_AUTHOR_IDENT && git_author_name.len)\n+\t\t\t\tname = git_author_name.buf;\n+\t\t\telse if (whose_ident == WANT_COMMITTER_IDENT &&\n+\t\t\t\t\tgit_committer_name.len)\n+\t\t\t\tname = git_committer_name.buf;\n+\t\t}\n \t\tif (!name) {\n \t\t\tif (strict && ident_use_config_only\n \t\t\t    && !(ident_config_given & IDENT_NAME_GIVEN)) {\n@@ -425,9 +442,25 @@ const char *fmt_ident(const char *name, const char *email,\n \treturn ident.buf;\n }\n \n-const char *fmt_name(const char *name, const char *email)\n+const char *fmt_name(enum want_ident whose_ident)\n {\n-\treturn fmt_ident(name, email, NULL, IDENT_STRICT | IDENT_NO_DATE);\n+\tchar *name = NULL;\n+\tchar *email = NULL;\n+\n+\tswitch (whose_ident) {\n+\tcase WANT_BLANK_IDENT:\n+\t\tbreak;\n+\tcase WANT_AUTHOR_IDENT:\n+\t\tname = getenv(\"GIT_AUTHOR_NAME\");\n+\t\temail = getenv(\"GIT_AUTHOR_EMAIL\");\n+\t\tbreak;\n+\tcase WANT_COMMITTER_IDENT:\n+\t\tname = getenv(\"GIT_COMMITTER_NAME\");\n+\t\temail = getenv(\"GIT_COMMITTER_EMAIL\");\n+\t\tbreak;\n+\t}\n+\treturn fmt_ident(name, email, whose_ident, NULL,\n+\t\t\tIDENT_STRICT | IDENT_NO_DATE);\n }\n \n const char *git_author_info(int flag)\n@@ -438,6 +471,7 @@ const char *git_author_info(int flag)\n \t\tauthor_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n \treturn fmt_ident(getenv(\"GIT_AUTHOR_NAME\"),\n \t\t\t getenv(\"GIT_AUTHOR_EMAIL\"),\n+\t\t\t WANT_AUTHOR_IDENT,\n \t\t\t getenv(\"GIT_AUTHOR_DATE\"),\n \t\t\t flag);\n }\n@@ -450,6 +484,7 @@ const char *git_committer_info(int flag)\n \t\tcommitter_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n \treturn fmt_ident(getenv(\"GIT_COMMITTER_NAME\"),\n \t\t\t getenv(\"GIT_COMMITTER_EMAIL\"),\n+\t\t\t WANT_COMMITTER_IDENT,\n \t\t\t getenv(\"GIT_COMMITTER_DATE\"),\n \t\t\t flag);\n }\n@@ -473,10 +508,45 @@ int author_ident_sufficiently_given(void)\n \treturn ident_is_sufficient(author_ident_explicitly_given);\n }\n \n-int git_ident_config(const char *var, const char *value, void *data)\n+static int set_ident(const char *var, const char *value)\n {\n-\tif (!strcmp(var, \"user.useconfigonly\")) {\n-\t\tident_use_config_only = git_config_bool(var, value);\n+\tif (!strcmp(var, \"author.name\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\tstrbuf_reset(&git_author_name);\n+\t\tstrbuf_addstr(&git_author_name, value);\n+\t\tauthor_ident_explicitly_given |= IDENT_NAME_GIVEN;\n+\t\tident_config_given |= IDENT_NAME_GIVEN;\n+\t\treturn 0;\n+\t}\n+\n+\tif (!strcmp(var, \"author.email\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\tstrbuf_reset(&git_author_email);\n+\t\tstrbuf_addstr(&git_author_email, value);\n+\t\tauthor_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n+\t\tident_config_given |= IDENT_MAIL_GIVEN;\n+\t\treturn 0;\n+\t}\n+\n+\tif (!strcmp(var, \"committer.name\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\tstrbuf_reset(&git_committer_name);\n+\t\tstrbuf_addstr(&git_committer_name, value);\n+\t\tcommitter_ident_explicitly_given |= IDENT_NAME_GIVEN;\n+\t\tident_config_given |= IDENT_NAME_GIVEN;\n+\t\treturn 0;\n+\t}\n+\n+\tif (!strcmp(var, \"committer.email\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\tstrbuf_reset(&git_committer_email);\n+\t\tstrbuf_addstr(&git_committer_email, value);\n+\t\tcommitter_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n+\t\tident_config_given |= IDENT_MAIL_GIVEN;\n \t\treturn 0;\n \t}\n \n@@ -505,6 +575,16 @@ int git_ident_config(const char *var, const char *value, void *data)\n \treturn 0;\n }\n \n+int git_ident_config(const char *var, const char *value, void *data)\n+{\n+\tif (!strcmp(var, \"user.useconfigonly\")) {\n+\t\tident_use_config_only = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n+\treturn set_ident(var, value);\n+}\n+\n static int buf_cmp(const char *a_begin, const char *a_end,\n \t\t   const char *b_begin, const char *b_end)\n {\ndiff --git a/log-tree.c b/log-tree.c\nindex 3cb14256ec..1e56df62a7 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -687,8 +687,7 @@ void show_log(struct rev_info *opt)\n \t */\n \tif (ctx.need_8bit_cte >= 0 && opt->add_signoff)\n \t\tctx.need_8bit_cte =\n-\t\t\thas_non_ascii(fmt_name(getenv(\"GIT_COMMITTER_NAME\"),\n-\t\t\t\t\t       getenv(\"GIT_COMMITTER_EMAIL\")));\n+\t\t\thas_non_ascii(fmt_name(WANT_COMMITTER_IDENT));\n \tctx.date_mode = opt->date_mode;\n \tctx.date_mode_explicit = opt->date_mode_explicit;\n \tctx.abbrev = opt->diffopt.abbrev;\ndiff --git a/sequencer.c b/sequencer.c\nindex 213815dbfc..fe2a1b2fcf 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -837,7 +837,7 @@ static const char *read_author_ident(struct strbuf *buf)\n \t}\n \n \tstrbuf_reset(&out);\n-\tstrbuf_addstr(&out, fmt_ident(name, email, date, 0));\n+\tstrbuf_addstr(&out, fmt_ident(name, email, WANT_AUTHOR_IDENT, date, 0));\n \tstrbuf_swap(buf, &out);\n \tstrbuf_release(&out);\n \tfree(name);\n@@ -4094,8 +4094,7 @@ void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag)\n \tint has_footer;\n \n \tstrbuf_addstr(&sob, sign_off_header);\n-\tstrbuf_addstr(&sob, fmt_name(getenv(\"GIT_COMMITTER_NAME\"),\n-\t\t\t\tgetenv(\"GIT_COMMITTER_EMAIL\")));\n+\tstrbuf_addstr(&sob, fmt_name(WANT_COMMITTER_IDENT));\n \tstrbuf_addch(&sob, '\\n');\n \n \tif (!ignore_footer)\ndiff --git a/t/t7517-per-repo-email.sh b/t/t7517-per-repo-email.sh\nindex 231b8cc19d..b2401cec3e 100755\n--- a/t/t7517-per-repo-email.sh\n+++ b/t/t7517-per-repo-email.sh\n@@ -85,4 +85,78 @@ test_expect_success REBASE_P \\\n \ttest_must_fail git rebase -p master\n '\n \n+test_expect_success 'author.name overrides user.name' '\n+\ttest_config user.name user &&\n+\ttest_config user.email user@example.com &&\n+\ttest_config author.name author &&\n+\ttest_commit author-name-override-user &&\n+\techo author user@example.com > expected-author &&\n+\techo user user@example.com > expected-committer &&\n+\tgit log --format=\"%an %ae\" -1 > actual-author &&\n+\tgit log --format=\"%cn %ce\" -1 > actual-committer &&\n+\ttest_cmp expected-author actual-author &&\n+\ttest_cmp expected-committer actual-committer\n+'\n+\n+test_expect_success 'author.email overrides user.email' '\n+\ttest_config user.name user &&\n+\ttest_config user.email user@example.com &&\n+\ttest_config author.email author@example.com &&\n+\ttest_commit author-email-override-user &&\n+\techo user author@example.com > expected-author &&\n+\techo user user@example.com > expected-committer &&\n+\tgit log --format=\"%an %ae\" -1 > actual-author &&\n+\tgit log --format=\"%cn %ce\" -1 > actual-committer &&\n+\ttest_cmp expected-author actual-author &&\n+\ttest_cmp expected-committer actual-committer\n+'\n+\n+test_expect_success 'committer.name overrides user.name' '\n+\ttest_config user.name user &&\n+\ttest_config user.email user@example.com &&\n+\ttest_config committer.name committer &&\n+\ttest_commit committer-name-override-user &&\n+\techo user user@example.com > expected-author &&\n+\techo committer user@example.com > expected-committer &&\n+\tgit log --format=\"%an %ae\" -1 > actual-author &&\n+\tgit log --format=\"%cn %ce\" -1 > actual-committer &&\n+\ttest_cmp expected-author actual-author &&\n+\ttest_cmp expected-committer actual-committer\n+'\n+\n+test_expect_success 'committer.email overrides user.email' '\n+\ttest_config user.name user &&\n+\ttest_config user.email user@example.com &&\n+\ttest_config committer.email committer@example.com &&\n+\ttest_commit committer-email-override-user &&\n+\techo user user@example.com > expected-author &&\n+\techo user committer@example.com > expected-committer &&\n+\tgit log --format=\"%an %ae\" -1 > actual-author &&\n+\tgit log --format=\"%cn %ce\" -1 > actual-committer &&\n+\ttest_cmp expected-author actual-author &&\n+\ttest_cmp expected-committer actual-committer\n+'\n+\n+test_expect_success 'author and committer environment variables override config settings' '\n+\ttest_config user.name user &&\n+\ttest_config user.email user@example.com &&\n+\ttest_config author.name author &&\n+\ttest_config author.email author@example.com &&\n+\ttest_config committer.name committer &&\n+\ttest_config committer.email committer@example.com &&\n+\tGIT_AUTHOR_NAME=env_author && export GIT_AUTHOR_NAME &&\n+\tGIT_AUTHOR_EMAIL=env_author@example.com && export GIT_AUTHOR_EMAIL &&\n+\tGIT_COMMITTER_NAME=env_commit && export GIT_COMMITTER_NAME &&\n+\tGIT_COMMITTER_EMAIL=env_commit@example.com && export GIT_COMMITTER_EMAIL &&\n+\ttest_commit env-override-conf &&\n+\techo env_author env_author@example.com > expected-author &&\n+\techo env_commit env_commit@example.com > expected-committer &&\n+\tgit log --format=\"%an %ae\" -1 > actual-author &&\n+\tgit log --format=\"%cn %ce\" -1 > actual-committer &&\n+\tsane_unset GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL &&\n+\tsane_unset GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL &&\n+\ttest_cmp expected-author actual-author &&\n+\ttest_cmp expected-committer actual-committer\n+'\n+\n test_done\n-- \n2.19.2\n\n"},{"id":"368512","messageId":"nycvar.QRO.7.76.6.1902051016190.41@tvgsbejvaqbjf.bet","threadId":"50396","inReplyTo":"20190204184850.10040-2-williamh@gentoo.org","subject":"Re: [PATCH v5 1/1] config: allow giving separate author and committer idents","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2019-02-05T09:16:48Z","receivedAt":"2019-02-05T09:17:03Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi William,\n\nOn Mon, 4 Feb 2019, William Hubbs wrote:\n\n> diff --git a/Documentation/config/user.txt b/Documentation/config/user.txt\n> index b5b2ba1199..0557cbbceb 100644\n> --- a/Documentation/config/user.txt\n> +++ b/Documentation/config/user.txt\n> @@ -1,12 +1,19 @@\n> -user.email::\n> -\tYour email address to be recorded in any newly created commits.\n> -\tCan be overridden by the `GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_EMAIL`, and\n> -\t`EMAIL` environment variables.  See linkgit:git-commit-tree[1].\n> -\n>  user.name::\n> -\tYour full name to be recorded in any newly created commits.\n> -\tCan be overridden by the `GIT_AUTHOR_NAME` and `GIT_COMMITTER_NAME`\n> -\tenvironment variables.  See linkgit:git-commit-tree[1].\n> +user.email::\n> +author.name::\n> +author.email::\n> +committer.name::\n> +committer.email::\n> +\tThe `user.name` and `user.email` variables determine what ends\n> +\tup in the `author` and `committer` field of commit\n> +\tobjects.\n> +\tIf you need the `author` or `committer` to be different, the\n> +\t`author.name`, `author.email`, `committer.name` or\n> +\t`committer.email` variables can be set.\n> +\tAlso, all of these can be overridden by the `GIT_AUTHOR_NAME`,\n> +\t`GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME`,\n> +\t`GIT_COMMITTER_EMAIL` and `EMAIL` environment variables.\n> +\tSee linkgit:git-commit-tree[1] for more information.\n\nThank you, this looks good to me.\n\nCiao,\nJohannes\n"},{"id":"368533","messageId":"xmqqva1yru3x.fsf@gitster-ct.c.googlers.com","threadId":"50396","inReplyTo":"nycvar.QRO.7.76.6.1902051016190.41@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v5 1/1] config: allow giving separate author and committer idents","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-05T18:02:58Z","receivedAt":"2019-02-05T18:03:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> +\tobjects.\n>> +\tIf you need the `author` or `committer` to be different, the\n>> +\t`author.name`, `author.email`, `committer.name` or\n>> +\t`committer.email` variables can be set.\n>> +\tAlso, all of these can be overridden by the `GIT_AUTHOR_NAME`,\n>> +\t`GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME`,\n>> +\t`GIT_COMMITTER_EMAIL` and `EMAIL` environment variables.\n>> +\tSee linkgit:git-commit-tree[1] for more information.\n>\n> Thank you, this looks good to me.\n\nThanks, both.  Queued.\n"},{"id":"368538","messageId":"20190205195212.25550-1-avarab@gmail.com","threadId":"50396","inReplyTo":"20190204184850.10040-1-williamh@gentoo.org","subject":"[PATCH v6 0/2] New {author,committer}.{name,email} config","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-02-05T19:52:10Z","receivedAt":"2019-02-05T19:52:28Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"I had some feedback on v2 that wasn't addressed. See\nhttps://public-inbox.org/git/875zuc49uj.fsf@evledraar.gmail.com/ &\nhttps://public-inbox.org/git/871s4w4khs.fsf@evledraar.gmail.com/\n\nThis fixes that, except I couldn't with limited time reproduce the bug\nI was talking about in the latter E-Mail in the test suite, maybe we\nonly infer the E-Mail from the hostname outside of it? So 1/1 is the\npatch I was going to fleshen out with that test, but didn't, but I\nfigured I'd leave it.\n\nOther changes can be seen in the range-diff, briefly:\n\n* We now update the git-commit-tree docs\n* Bunch of coding style nits fixed (alignment, past 79 chars)\n* Factored a bunch of copy/pasted code into a helper in ident.c\n* Fixed a test to skip a whole GIT_*= && export && sane_unset dance,\n  and just use test_env instead.\n* Test style: \">f\" not \"> f\" in redirection.\n\nWilliam Hubbs (1):\n  config: allow giving separate author and committer idents\n\nÆvar Arnfjörð Bjarmason (1):\n  ident: test how GIT_* and user.{name,email} interact\n\n Documentation/config/user.txt     |  23 ++++---\n Documentation/git-commit-tree.txt |   3 +-\n blame.c                           |   3 +-\n builtin/am.c                      |   1 +\n builtin/commit.c                  |   3 +-\n cache.h                           |  13 +++-\n config.c                          |   4 +-\n ident.c                           | 101 +++++++++++++++++++++-------\n log-tree.c                        |   3 +-\n sequencer.c                       |   6 +-\n t/t7517-per-repo-email.sh         | 108 ++++++++++++++++++++++++++++++\n 11 files changed, 223 insertions(+), 45 deletions(-)\n\nRange-diff:\n-:  ---------- > 1:  ffd41a882a ident: test how GIT_* and user.{name,email} interact\n1:  1172f91155 ! 2:  788ec8412d config: allow giving separate author and committer idents\n    @@ -21,6 +21,7 @@\n         committer identification.\n     \n         Signed-off-by: William Hubbs <williamh@gentoo.org>\n    +    Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      diff --git a/Documentation/config/user.txt b/Documentation/config/user.txt\n      --- a/Documentation/config/user.txt\n    @@ -54,6 +55,20 @@\n      user.useConfigOnly::\n      \tInstruct Git to avoid trying to guess defaults for `user.email`\n     \n    + diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt\n    + --- a/Documentation/git-commit-tree.txt\n    + +++ b/Documentation/git-commit-tree.txt\n    +@@\n    + (nb \"<\", \">\" and \"\\n\"s are stripped)\n    + \n    + In case (some of) these environment variables are not set, the information\n    +-is taken from the configuration items user.name and user.email, or, if not\n    ++is taken from the configuration items user.name and user.email, or the more\n    ++specific author.{name,email} and committer.{name,email} variables, or, if not\n    + present, the environment variable EMAIL, or, if that is not set,\n    + system user name and the hostname used for outgoing mail (taken\n    + from `/etc/mailname` and falling back to the fully qualified hostname when\n    +\n      diff --git a/blame.c b/blame.c\n      --- a/blame.c\n      +++ b/blame.c\n    @@ -75,7 +90,7 @@\n      \t}\n      \n      \tauthor = fmt_ident(state->author_name, state->author_email,\n    -+\t\tWANT_AUTHOR_IDENT,\n    ++\t\t\tWANT_AUTHOR_IDENT,\n      \t\t\tstate->ignore_date ? NULL : state->author_date,\n      \t\t\tIDENT_STRICT);\n      \n    @@ -89,7 +104,7 @@\n      \n     -\tstrbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT));\n     +\tstrbuf_addstr(author_ident, fmt_ident(name, email, WANT_AUTHOR_IDENT, date,\n    -+\t\t\t\tIDENT_STRICT));\n    ++\t\t\t\t\t      IDENT_STRICT));\n      \tassert_split_ident(&author, author_ident);\n      \texport_one(\"GIT_AUTHOR_NAME\", author.name_begin, author.name_end, 0);\n      \texport_one(\"GIT_AUTHOR_EMAIL\", author.mail_begin, author.mail_end, 0);\n    @@ -113,8 +128,8 @@\n     -extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);\n     -extern const char *fmt_name(const char *name, const char *email);\n     +extern const char *fmt_ident(const char *name, const char *email,\n    -+\t\tenum want_ident whose_ident,\n    -+\t\tconst char *date_str, int);\n    ++\t\t\t     enum want_ident whose_ident,\n    ++\t\t\t     const char *date_str, int flag);\n     +extern const char *fmt_name(enum want_ident);\n      extern const char *ident_default_name(void);\n      extern const char *ident_default_email(void);\n    @@ -129,8 +144,8 @@\n      \n     -\tif (starts_with(var, \"user.\"))\n     +\tif (starts_with(var, \"user.\") ||\n    -+\t\tstarts_with(var, \"author.\") ||\n    -+\t\t\tstarts_with(var, \"committer.\"))\n    ++\t    starts_with(var, \"author.\") ||\n    ++\t    starts_with(var, \"committer.\"))\n      \t\treturn git_ident_config(var, value, cb);\n      \n      \tif (starts_with(var, \"i18n.\"))\n    @@ -154,7 +169,8 @@\n      \n      const char *fmt_ident(const char *name, const char *email,\n     -\t\t      const char *date_str, int flag)\n    -+\t\t      enum want_ident whose_ident, const char *date_str, int flag)\n    ++\t\t      enum want_ident whose_ident, const char *date_str,\n    ++\t\t      int flag)\n      {\n      \tstatic struct strbuf ident = STRBUF_INIT;\n      \tint strict = (flag & IDENT_STRICT);\n    @@ -232,68 +248,75 @@\n      \treturn ident_is_sufficient(author_ident_explicitly_given);\n      }\n      \n    --int git_ident_config(const char *var, const char *value, void *data)\n    -+static int set_ident(const char *var, const char *value)\n    - {\n    --\tif (!strcmp(var, \"user.useconfigonly\")) {\n    --\t\tident_use_config_only = git_config_bool(var, value);\n    -+\tif (!strcmp(var, \"author.name\")) {\n    -+\t\tif (!value)\n    -+\t\t\treturn config_error_nonbool(var);\n    -+\t\tstrbuf_reset(&git_author_name);\n    -+\t\tstrbuf_addstr(&git_author_name, value);\n    -+\t\tauthor_ident_explicitly_given |= IDENT_NAME_GIVEN;\n    -+\t\tident_config_given |= IDENT_NAME_GIVEN;\n    -+\t\treturn 0;\n    -+\t}\n    -+\n    -+\tif (!strcmp(var, \"author.email\")) {\n    -+\t\tif (!value)\n    -+\t\t\treturn config_error_nonbool(var);\n    -+\t\tstrbuf_reset(&git_author_email);\n    -+\t\tstrbuf_addstr(&git_author_email, value);\n    -+\t\tauthor_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n    -+\t\tident_config_given |= IDENT_MAIL_GIVEN;\n    -+\t\treturn 0;\n    -+\t}\n    ++static int set_ident_internal(const char *var, const char *value,\n    ++\t\t\t    struct strbuf *sb, const int flag)\n    ++{\n    ++\tif (!value)\n    ++\t\treturn config_error_nonbool(var);\n    ++\tstrbuf_reset(sb);\n    ++\tstrbuf_addstr(sb, value);\n    ++\tauthor_ident_explicitly_given |= flag;\n    ++\tident_config_given |= flag;\n    ++\treturn 0;\n    ++}\n     +\n    -+\tif (!strcmp(var, \"committer.name\")) {\n    -+\t\tif (!value)\n    -+\t\t\treturn config_error_nonbool(var);\n    -+\t\tstrbuf_reset(&git_committer_name);\n    -+\t\tstrbuf_addstr(&git_committer_name, value);\n    -+\t\tcommitter_ident_explicitly_given |= IDENT_NAME_GIVEN;\n    -+\t\tident_config_given |= IDENT_NAME_GIVEN;\n    -+\t\treturn 0;\n    -+\t}\n    ++static int set_ident(const char *var, const char *value)\n    ++{\n    ++\tif (!strcmp(var, \"author.name\"))\n    ++\t\treturn set_ident_internal(var, value, &git_author_name,\n    ++\t\t\t\t\t  IDENT_NAME_GIVEN);\n    ++\telse if (!strcmp(var, \"author.email\"))\n    ++\t\treturn set_ident_internal(var, value, &git_author_email,\n    ++\t\t\t\t\t  IDENT_MAIL_GIVEN);\n    ++\telse if (!strcmp(var, \"committer.name\"))\n    ++\t\treturn set_ident_internal(var, value, &git_committer_name,\n    ++\t\t\t\t\t  IDENT_NAME_GIVEN);\n    ++\telse if (!strcmp(var, \"committer.email\"))\n    ++\t\treturn set_ident_internal(var, value, &git_committer_email,\n    ++\t\t\t\t\t  IDENT_MAIL_GIVEN);\n    ++\telse if (!strcmp(var, \"user.name\"))\n    ++\t\treturn set_ident_internal(var, value, &git_default_name,\n    ++\t\t\t\t\t  IDENT_NAME_GIVEN);\n    ++\telse if (!strcmp(var, \"user.email\"))\n    ++\t\treturn set_ident_internal(var, value, &git_default_email,\n    ++\t\t\t\t\t  IDENT_MAIL_GIVEN);\n    ++\treturn 0;\n    ++}\n     +\n    -+\tif (!strcmp(var, \"committer.email\")) {\n    -+\t\tif (!value)\n    -+\t\t\treturn config_error_nonbool(var);\n    -+\t\tstrbuf_reset(&git_committer_email);\n    -+\t\tstrbuf_addstr(&git_committer_email, value);\n    -+\t\tcommitter_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n    -+\t\tident_config_given |= IDENT_MAIL_GIVEN;\n    + int git_ident_config(const char *var, const char *value, void *data)\n    + {\n    + \tif (!strcmp(var, \"user.useconfigonly\")) {\n    +@@\n      \t\treturn 0;\n      \t}\n      \n    -@@\n    - \treturn 0;\n    +-\tif (!strcmp(var, \"user.name\")) {\n    +-\t\tif (!value)\n    +-\t\t\treturn config_error_nonbool(var);\n    +-\t\tstrbuf_reset(&git_default_name);\n    +-\t\tstrbuf_addstr(&git_default_name, value);\n    +-\t\tcommitter_ident_explicitly_given |= IDENT_NAME_GIVEN;\n    +-\t\tauthor_ident_explicitly_given |= IDENT_NAME_GIVEN;\n    +-\t\tident_config_given |= IDENT_NAME_GIVEN;\n    +-\t\treturn 0;\n    +-\t}\n    +-\n    +-\tif (!strcmp(var, \"user.email\")) {\n    +-\t\tif (!value)\n    +-\t\t\treturn config_error_nonbool(var);\n    +-\t\tstrbuf_reset(&git_default_email);\n    +-\t\tstrbuf_addstr(&git_default_email, value);\n    +-\t\tcommitter_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n    +-\t\tauthor_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n    +-\t\tident_config_given |= IDENT_MAIL_GIVEN;\n    +-\t\treturn 0;\n    +-\t}\n    +-\n    +-\treturn 0;\n    ++\treturn set_ident(var, value);\n      }\n      \n    -+int git_ident_config(const char *var, const char *value, void *data)\n    -+{\n    -+\tif (!strcmp(var, \"user.useconfigonly\")) {\n    -+\t\tident_use_config_only = git_config_bool(var, value);\n    -+\t\treturn 0;\n    -+\t}\n    -+\n    -+\treturn set_ident(var, value);\n    -+}\n    -+\n      static int buf_cmp(const char *a_begin, const char *a_end,\n    - \t\t   const char *b_begin, const char *b_end)\n    - {\n     \n      diff --git a/log-tree.c b/log-tree.c\n      --- a/log-tree.c\n    @@ -317,7 +340,8 @@\n      \n      \tstrbuf_reset(&out);\n     -\tstrbuf_addstr(&out, fmt_ident(name, email, date, 0));\n    -+\tstrbuf_addstr(&out, fmt_ident(name, email, WANT_AUTHOR_IDENT, date, 0));\n    ++\tstrbuf_addstr(&out, fmt_ident(name, email, WANT_AUTHOR_IDENT, date,\n    ++\t\t\t\t      0));\n      \tstrbuf_swap(buf, &out);\n      \tstrbuf_release(&out);\n      \tfree(name);\n    @@ -339,15 +363,24 @@\n      \ttest_must_fail git rebase -p master\n      '\n      \n    +-test_expect_success 'fallbacks for GIT_* and user.{name,email}' '\n    ++test_expect_success 'fallbacks for GIT_* and {user,author,committer}.{name,email}' '\n    + \t# We must have committer in the object\n    + \ttest_must_fail test_env \\\n    + \t\tGIT_AUTHOR_NAME=author.name \\\n    +@@\n    + \ttest_cmp expected actual\n    + '\n    + \n     +test_expect_success 'author.name overrides user.name' '\n     +\ttest_config user.name user &&\n     +\ttest_config user.email user@example.com &&\n     +\ttest_config author.name author &&\n     +\ttest_commit author-name-override-user &&\n    -+\techo author user@example.com > expected-author &&\n    -+\techo user user@example.com > expected-committer &&\n    -+\tgit log --format=\"%an %ae\" -1 > actual-author &&\n    -+\tgit log --format=\"%cn %ce\" -1 > actual-committer &&\n    ++\techo author user@example.com >expected-author &&\n    ++\techo user user@example.com >expected-committer &&\n    ++\tgit log --format=\"%an %ae\" -1 >actual-author &&\n    ++\tgit log --format=\"%cn %ce\" -1 >actual-committer &&\n     +\ttest_cmp expected-author actual-author &&\n     +\ttest_cmp expected-committer actual-committer\n     +'\n    @@ -357,10 +390,10 @@\n     +\ttest_config user.email user@example.com &&\n     +\ttest_config author.email author@example.com &&\n     +\ttest_commit author-email-override-user &&\n    -+\techo user author@example.com > expected-author &&\n    -+\techo user user@example.com > expected-committer &&\n    -+\tgit log --format=\"%an %ae\" -1 > actual-author &&\n    -+\tgit log --format=\"%cn %ce\" -1 > actual-committer &&\n    ++\techo user author@example.com >expected-author &&\n    ++\techo user user@example.com >expected-committer &&\n    ++\tgit log --format=\"%an %ae\" -1 >actual-author &&\n    ++\tgit log --format=\"%cn %ce\" -1 >actual-committer &&\n     +\ttest_cmp expected-author actual-author &&\n     +\ttest_cmp expected-committer actual-committer\n     +'\n    @@ -370,10 +403,10 @@\n     +\ttest_config user.email user@example.com &&\n     +\ttest_config committer.name committer &&\n     +\ttest_commit committer-name-override-user &&\n    -+\techo user user@example.com > expected-author &&\n    -+\techo committer user@example.com > expected-committer &&\n    -+\tgit log --format=\"%an %ae\" -1 > actual-author &&\n    -+\tgit log --format=\"%cn %ce\" -1 > actual-committer &&\n    ++\techo user user@example.com >expected-author &&\n    ++\techo committer user@example.com >expected-committer &&\n    ++\tgit log --format=\"%an %ae\" -1 >actual-author &&\n    ++\tgit log --format=\"%cn %ce\" -1 >actual-committer &&\n     +\ttest_cmp expected-author actual-author &&\n     +\ttest_cmp expected-committer actual-committer\n     +'\n    @@ -383,10 +416,10 @@\n     +\ttest_config user.email user@example.com &&\n     +\ttest_config committer.email committer@example.com &&\n     +\ttest_commit committer-email-override-user &&\n    -+\techo user user@example.com > expected-author &&\n    -+\techo user committer@example.com > expected-committer &&\n    -+\tgit log --format=\"%an %ae\" -1 > actual-author &&\n    -+\tgit log --format=\"%cn %ce\" -1 > actual-committer &&\n    ++\techo user user@example.com >expected-author &&\n    ++\techo user committer@example.com >expected-committer &&\n    ++\tgit log --format=\"%an %ae\" -1 >actual-author &&\n    ++\tgit log --format=\"%cn %ce\" -1 >actual-committer &&\n     +\ttest_cmp expected-author actual-author &&\n     +\ttest_cmp expected-committer actual-committer\n     +'\n    @@ -398,17 +431,17 @@\n     +\ttest_config author.email author@example.com &&\n     +\ttest_config committer.name committer &&\n     +\ttest_config committer.email committer@example.com &&\n    -+\tGIT_AUTHOR_NAME=env_author && export GIT_AUTHOR_NAME &&\n    -+\tGIT_AUTHOR_EMAIL=env_author@example.com && export GIT_AUTHOR_EMAIL &&\n    -+\tGIT_COMMITTER_NAME=env_commit && export GIT_COMMITTER_NAME &&\n    -+\tGIT_COMMITTER_EMAIL=env_commit@example.com && export GIT_COMMITTER_EMAIL &&\n    -+\ttest_commit env-override-conf &&\n    -+\techo env_author env_author@example.com > expected-author &&\n    -+\techo env_commit env_commit@example.com > expected-committer &&\n    -+\tgit log --format=\"%an %ae\" -1 > actual-author &&\n    -+\tgit log --format=\"%cn %ce\" -1 > actual-committer &&\n    -+\tsane_unset GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL &&\n    -+\tsane_unset GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL &&\n    ++\n    ++\ttest_env \\\n    ++\t\tGIT_AUTHOR_NAME=env_author \\\n    ++\t\tGIT_AUTHOR_EMAIL=env_author@example.com \\\n    ++\t\tGIT_COMMITTER_NAME=env_commit \\\n    ++\t\tGIT_COMMITTER_EMAIL=env_commit@example.com \\\n    ++\t\ttest_commit env-override-conf &&\n    ++\techo env_author env_author@example.com >expected-author &&\n    ++\techo env_commit env_commit@example.com >expected-committer &&\n    ++\tgit log --format=\"%an %ae\" -1 >actual-author &&\n    ++\tgit log --format=\"%cn %ce\" -1 >actual-committer &&\n     +\ttest_cmp expected-author actual-author &&\n     +\ttest_cmp expected-committer actual-committer\n     +'\n-- \n2.20.1.611.gfbb209baf1\n\n"},{"id":"368539","messageId":"20190205195212.25550-2-avarab@gmail.com","threadId":"50396","inReplyTo":"20190204184850.10040-1-williamh@gentoo.org","subject":"[PATCH v6 1/2] ident: test how GIT_* and user.{name,email} interact","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-02-05T19:52:11Z","receivedAt":"2019-02-05T19:52:30Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"There were no explicit tests for the interaction between setting GIT_*\nin the environment, and the user.{name,email} config variables. These\ntests are basic, but we're about to learn\n{author,committer}.{name,email} in addition to user.{name,email}, so\nthey'll soon become more useful.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7517-per-repo-email.sh | 34 ++++++++++++++++++++++++++++++++++\n 1 file changed, 34 insertions(+)\n\ndiff --git a/t/t7517-per-repo-email.sh b/t/t7517-per-repo-email.sh\nindex 231b8cc19d..84bd9e89e5 100755\n--- a/t/t7517-per-repo-email.sh\n+++ b/t/t7517-per-repo-email.sh\n@@ -85,4 +85,38 @@ test_expect_success REBASE_P \\\n \ttest_must_fail git rebase -p master\n '\n \n+test_expect_success 'fallbacks for GIT_* and user.{name,email}' '\n+\t# We must have committer in the object\n+\ttest_must_fail test_env \\\n+\t\tGIT_AUTHOR_NAME=author.name \\\n+\t\tGIT_AUTHOR_EMAIL=author@email \\\n+\t\tGIT_COMMITTER_NAME= \\\n+\t\tGIT_COMMITTER_EMAIL= \\\n+\t\ttest_commit A 2>stderr &&\n+\ttest_i18ngrep \"empty ident name.*not allowed\" stderr &&\n+\n+\t# With no committer E-Mail we will have an empty field\n+\ttest_env \\\n+\t\tGIT_AUTHOR_NAME=author.name \\\n+\t\tGIT_AUTHOR_EMAIL=author@email \\\n+\t\tGIT_COMMITTER_NAME=committer.name \\\n+\t\tGIT_COMMITTER_EMAIL= \\\n+\t\ttest_commit B 2>stderr &&\n+\techo \"author.name author@email committer.name \" >expected &&\n+\tgit log --format=\"%an %ae %cn %ce\" -1 >actual &&\n+\ttest_cmp expected actual &&\n+\n+\t# Environment overrides config\n+\ttest_config user.name author.config.name &&\n+\ttest_env \\\n+\t\tGIT_AUTHOR_NAME=author.name \\\n+\t\tGIT_AUTHOR_EMAIL=author@email \\\n+\t\tGIT_COMMITTER_NAME=committer.name \\\n+\t\tGIT_COMMITTER_EMAIL= \\\n+\t\ttest_commit C 2>stderr &&\n+\techo \"author.name author@email committer.name \" >expected &&\n+\tgit log --format=\"%an %ae %cn %ce\" -1 >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n2.20.1.611.gfbb209baf1\n\n"},{"id":"368540","messageId":"20190205195212.25550-3-avarab@gmail.com","threadId":"50396","inReplyTo":"20190204184850.10040-1-williamh@gentoo.org","subject":"[PATCH v6 2/2] config: allow giving separate author and committer idents","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-02-05T19:52:12Z","receivedAt":"2019-02-05T19:52:33Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: William Hubbs <williamh@gentoo.org>\n\nThe author.email, author.name, committer.email and committer.name\nsettings are analogous to the GIT_AUTHOR_* and GIT_COMMITTER_*\nenvironment variables, but for the git config system. This allows them\nto be set separately for each repository.\n\nGit supports setting different authorship and committer\ninformation with environment variables. However, environment variables\nare set in the shell, so if different authorship and committer\ninformation is needed for different repositories an external tool is\nrequired.\n\nThis adds support to git config for author.email, author.name,\ncommitter.email and committer.name  settings so this information\ncan be set per repository.\n\nAlso, it generalizes the fmt_ident function so it can handle author vs\ncommitter identification.\n\nSigned-off-by: William Hubbs <williamh@gentoo.org>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/config/user.txt     |  23 ++++---\n Documentation/git-commit-tree.txt |   3 +-\n blame.c                           |   3 +-\n builtin/am.c                      |   1 +\n builtin/commit.c                  |   3 +-\n cache.h                           |  13 +++-\n config.c                          |   4 +-\n ident.c                           | 101 ++++++++++++++++++++++--------\n log-tree.c                        |   3 +-\n sequencer.c                       |   6 +-\n t/t7517-per-repo-email.sh         |  76 +++++++++++++++++++++-\n 11 files changed, 190 insertions(+), 46 deletions(-)\n\ndiff --git a/Documentation/config/user.txt b/Documentation/config/user.txt\nindex b5b2ba1199..0557cbbceb 100644\n--- a/Documentation/config/user.txt\n+++ b/Documentation/config/user.txt\n@@ -1,12 +1,19 @@\n-user.email::\n-\tYour email address to be recorded in any newly created commits.\n-\tCan be overridden by the `GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_EMAIL`, and\n-\t`EMAIL` environment variables.  See linkgit:git-commit-tree[1].\n-\n user.name::\n-\tYour full name to be recorded in any newly created commits.\n-\tCan be overridden by the `GIT_AUTHOR_NAME` and `GIT_COMMITTER_NAME`\n-\tenvironment variables.  See linkgit:git-commit-tree[1].\n+user.email::\n+author.name::\n+author.email::\n+committer.name::\n+committer.email::\n+\tThe `user.name` and `user.email` variables determine what ends\n+\tup in the `author` and `committer` field of commit\n+\tobjects.\n+\tIf you need the `author` or `committer` to be different, the\n+\t`author.name`, `author.email`, `committer.name` or\n+\t`committer.email` variables can be set.\n+\tAlso, all of these can be overridden by the `GIT_AUTHOR_NAME`,\n+\t`GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME`,\n+\t`GIT_COMMITTER_EMAIL` and `EMAIL` environment variables.\n+\tSee linkgit:git-commit-tree[1] for more information.\n \n user.useConfigOnly::\n \tInstruct Git to avoid trying to guess defaults for `user.email`\ndiff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt\nindex 002dae625e..091e3a77ca 100644\n--- a/Documentation/git-commit-tree.txt\n+++ b/Documentation/git-commit-tree.txt\n@@ -88,7 +88,8 @@ if set:\n (nb \"<\", \">\" and \"\\n\"s are stripped)\n \n In case (some of) these environment variables are not set, the information\n-is taken from the configuration items user.name and user.email, or, if not\n+is taken from the configuration items user.name and user.email, or the more\n+specific author.{name,email} and committer.{name,email} variables, or, if not\n present, the environment variable EMAIL, or, if that is not set,\n system user name and the hostname used for outgoing mail (taken\n from `/etc/mailname` and falling back to the fully qualified hostname when\ndiff --git a/blame.c b/blame.c\nindex 43861437f7..c9c351eb36 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -204,7 +204,8 @@ static struct commit *fake_working_tree_commit(struct repository *r,\n \n \torigin = make_origin(commit, path);\n \n-\tident = fmt_ident(\"Not Committed Yet\", \"not.committed.yet\", NULL, 0);\n+\tident = fmt_ident(\"Not Committed Yet\", \"not.committed.yet\",\n+\t\t\tWANT_BLANK_IDENT, NULL, 0);\n \tstrbuf_addstr(&msg, \"tree 0000000000000000000000000000000000000000\\n\");\n \tfor (parent = commit->parents; parent; parent = parent->next)\n \t\tstrbuf_addf(&msg, \"parent %s\\n\",\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 95370313b6..d4a1cbe828 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -1594,6 +1594,7 @@ static void do_commit(const struct am_state *state)\n \t}\n \n \tauthor = fmt_ident(state->author_name, state->author_email,\n+\t\t\tWANT_AUTHOR_IDENT,\n \t\t\tstate->ignore_date ? NULL : state->author_date,\n \t\t\tIDENT_STRICT);\n \ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 7d2e0b61e5..0af8fc3503 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -608,7 +608,8 @@ static void determine_author_info(struct strbuf *author_ident)\n \t\tset_ident_var(&date, strbuf_detach(&date_buf, NULL));\n \t}\n \n-\tstrbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT));\n+\tstrbuf_addstr(author_ident, fmt_ident(name, email, WANT_AUTHOR_IDENT, date,\n+\t\t\t\t\t      IDENT_STRICT));\n \tassert_split_ident(&author, author_ident);\n \texport_one(\"GIT_AUTHOR_NAME\", author.name_begin, author.name_end, 0);\n \texport_one(\"GIT_AUTHOR_EMAIL\", author.mail_begin, author.mail_end, 0);\ndiff --git a/cache.h b/cache.h\nindex 009e8b3b15..c2f9d4e680 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1494,10 +1494,19 @@ int date_overflows(timestamp_t date);\n #define IDENT_STRICT\t       1\n #define IDENT_NO_DATE\t       2\n #define IDENT_NO_NAME\t       4\n+\n+enum want_ident {\n+\tWANT_BLANK_IDENT,\n+\tWANT_AUTHOR_IDENT,\n+\tWANT_COMMITTER_IDENT\n+};\n+\n extern const char *git_author_info(int);\n extern const char *git_committer_info(int);\n-extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);\n-extern const char *fmt_name(const char *name, const char *email);\n+extern const char *fmt_ident(const char *name, const char *email,\n+\t\t\t     enum want_ident whose_ident,\n+\t\t\t     const char *date_str, int flag);\n+extern const char *fmt_name(enum want_ident);\n extern const char *ident_default_name(void);\n extern const char *ident_default_email(void);\n extern const char *git_editor(void);\ndiff --git a/config.c b/config.c\nindex ff521eb27a..fd36db7790 100644\n--- a/config.c\n+++ b/config.c\n@@ -1445,7 +1445,9 @@ int git_default_config(const char *var, const char *value, void *cb)\n \tif (starts_with(var, \"core.\"))\n \t\treturn git_default_core_config(var, value, cb);\n \n-\tif (starts_with(var, \"user.\"))\n+\tif (starts_with(var, \"user.\") ||\n+\t    starts_with(var, \"author.\") ||\n+\t    starts_with(var, \"committer.\"))\n \t\treturn git_ident_config(var, value, cb);\n \n \tif (starts_with(var, \"i18n.\"))\ndiff --git a/ident.c b/ident.c\nindex 33bcf40644..7c3be81ee1 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -11,6 +11,10 @@\n static struct strbuf git_default_name = STRBUF_INIT;\n static struct strbuf git_default_email = STRBUF_INIT;\n static struct strbuf git_default_date = STRBUF_INIT;\n+static struct strbuf git_author_name = STRBUF_INIT;\n+static struct strbuf git_author_email = STRBUF_INIT;\n+static struct strbuf git_committer_name = STRBUF_INIT;\n+static struct strbuf git_committer_email = STRBUF_INIT;\n static int default_email_is_bogus;\n static int default_name_is_bogus;\n \n@@ -355,13 +359,20 @@ N_(\"\\n\"\n    \"\\n\");\n \n const char *fmt_ident(const char *name, const char *email,\n-\t\t      const char *date_str, int flag)\n+\t\t      enum want_ident whose_ident, const char *date_str,\n+\t\t      int flag)\n {\n \tstatic struct strbuf ident = STRBUF_INIT;\n \tint strict = (flag & IDENT_STRICT);\n \tint want_date = !(flag & IDENT_NO_DATE);\n \tint want_name = !(flag & IDENT_NO_NAME);\n \n+\tif (!email) {\n+\t\tif (whose_ident == WANT_AUTHOR_IDENT && git_author_email.len)\n+\t\t\temail = git_author_email.buf;\n+\t\telse if (whose_ident == WANT_COMMITTER_IDENT && git_committer_email.len)\n+\t\t\temail = git_committer_email.buf;\n+\t}\n \tif (!email) {\n \t\tif (strict && ident_use_config_only\n \t\t    && !(ident_config_given & IDENT_MAIL_GIVEN)) {\n@@ -377,6 +388,13 @@ const char *fmt_ident(const char *name, const char *email,\n \n \tif (want_name) {\n \t\tint using_default = 0;\n+\t\tif (!name) {\n+\t\t\tif (whose_ident == WANT_AUTHOR_IDENT && git_author_name.len)\n+\t\t\t\tname = git_author_name.buf;\n+\t\t\telse if (whose_ident == WANT_COMMITTER_IDENT &&\n+\t\t\t\t\tgit_committer_name.len)\n+\t\t\t\tname = git_committer_name.buf;\n+\t\t}\n \t\tif (!name) {\n \t\t\tif (strict && ident_use_config_only\n \t\t\t    && !(ident_config_given & IDENT_NAME_GIVEN)) {\n@@ -425,9 +443,25 @@ const char *fmt_ident(const char *name, const char *email,\n \treturn ident.buf;\n }\n \n-const char *fmt_name(const char *name, const char *email)\n+const char *fmt_name(enum want_ident whose_ident)\n {\n-\treturn fmt_ident(name, email, NULL, IDENT_STRICT | IDENT_NO_DATE);\n+\tchar *name = NULL;\n+\tchar *email = NULL;\n+\n+\tswitch (whose_ident) {\n+\tcase WANT_BLANK_IDENT:\n+\t\tbreak;\n+\tcase WANT_AUTHOR_IDENT:\n+\t\tname = getenv(\"GIT_AUTHOR_NAME\");\n+\t\temail = getenv(\"GIT_AUTHOR_EMAIL\");\n+\t\tbreak;\n+\tcase WANT_COMMITTER_IDENT:\n+\t\tname = getenv(\"GIT_COMMITTER_NAME\");\n+\t\temail = getenv(\"GIT_COMMITTER_EMAIL\");\n+\t\tbreak;\n+\t}\n+\treturn fmt_ident(name, email, whose_ident, NULL,\n+\t\t\tIDENT_STRICT | IDENT_NO_DATE);\n }\n \n const char *git_author_info(int flag)\n@@ -438,6 +472,7 @@ const char *git_author_info(int flag)\n \t\tauthor_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n \treturn fmt_ident(getenv(\"GIT_AUTHOR_NAME\"),\n \t\t\t getenv(\"GIT_AUTHOR_EMAIL\"),\n+\t\t\t WANT_AUTHOR_IDENT,\n \t\t\t getenv(\"GIT_AUTHOR_DATE\"),\n \t\t\t flag);\n }\n@@ -450,6 +485,7 @@ const char *git_committer_info(int flag)\n \t\tcommitter_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n \treturn fmt_ident(getenv(\"GIT_COMMITTER_NAME\"),\n \t\t\t getenv(\"GIT_COMMITTER_EMAIL\"),\n+\t\t\t WANT_COMMITTER_IDENT,\n \t\t\t getenv(\"GIT_COMMITTER_DATE\"),\n \t\t\t flag);\n }\n@@ -473,6 +509,41 @@ int author_ident_sufficiently_given(void)\n \treturn ident_is_sufficient(author_ident_explicitly_given);\n }\n \n+static int set_ident_internal(const char *var, const char *value,\n+\t\t\t    struct strbuf *sb, const int flag)\n+{\n+\tif (!value)\n+\t\treturn config_error_nonbool(var);\n+\tstrbuf_reset(sb);\n+\tstrbuf_addstr(sb, value);\n+\tauthor_ident_explicitly_given |= flag;\n+\tident_config_given |= flag;\n+\treturn 0;\n+}\n+\n+static int set_ident(const char *var, const char *value)\n+{\n+\tif (!strcmp(var, \"author.name\"))\n+\t\treturn set_ident_internal(var, value, &git_author_name,\n+\t\t\t\t\t  IDENT_NAME_GIVEN);\n+\telse if (!strcmp(var, \"author.email\"))\n+\t\treturn set_ident_internal(var, value, &git_author_email,\n+\t\t\t\t\t  IDENT_MAIL_GIVEN);\n+\telse if (!strcmp(var, \"committer.name\"))\n+\t\treturn set_ident_internal(var, value, &git_committer_name,\n+\t\t\t\t\t  IDENT_NAME_GIVEN);\n+\telse if (!strcmp(var, \"committer.email\"))\n+\t\treturn set_ident_internal(var, value, &git_committer_email,\n+\t\t\t\t\t  IDENT_MAIL_GIVEN);\n+\telse if (!strcmp(var, \"user.name\"))\n+\t\treturn set_ident_internal(var, value, &git_default_name,\n+\t\t\t\t\t  IDENT_NAME_GIVEN);\n+\telse if (!strcmp(var, \"user.email\"))\n+\t\treturn set_ident_internal(var, value, &git_default_email,\n+\t\t\t\t\t  IDENT_MAIL_GIVEN);\n+\treturn 0;\n+}\n+\n int git_ident_config(const char *var, const char *value, void *data)\n {\n \tif (!strcmp(var, \"user.useconfigonly\")) {\n@@ -480,29 +551,7 @@ int git_ident_config(const char *var, const char *value, void *data)\n \t\treturn 0;\n \t}\n \n-\tif (!strcmp(var, \"user.name\")) {\n-\t\tif (!value)\n-\t\t\treturn config_error_nonbool(var);\n-\t\tstrbuf_reset(&git_default_name);\n-\t\tstrbuf_addstr(&git_default_name, value);\n-\t\tcommitter_ident_explicitly_given |= IDENT_NAME_GIVEN;\n-\t\tauthor_ident_explicitly_given |= IDENT_NAME_GIVEN;\n-\t\tident_config_given |= IDENT_NAME_GIVEN;\n-\t\treturn 0;\n-\t}\n-\n-\tif (!strcmp(var, \"user.email\")) {\n-\t\tif (!value)\n-\t\t\treturn config_error_nonbool(var);\n-\t\tstrbuf_reset(&git_default_email);\n-\t\tstrbuf_addstr(&git_default_email, value);\n-\t\tcommitter_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n-\t\tauthor_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n-\t\tident_config_given |= IDENT_MAIL_GIVEN;\n-\t\treturn 0;\n-\t}\n-\n-\treturn 0;\n+\treturn set_ident(var, value);\n }\n \n static int buf_cmp(const char *a_begin, const char *a_end,\ndiff --git a/log-tree.c b/log-tree.c\nindex 3cb14256ec..1e56df62a7 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -687,8 +687,7 @@ void show_log(struct rev_info *opt)\n \t */\n \tif (ctx.need_8bit_cte >= 0 && opt->add_signoff)\n \t\tctx.need_8bit_cte =\n-\t\t\thas_non_ascii(fmt_name(getenv(\"GIT_COMMITTER_NAME\"),\n-\t\t\t\t\t       getenv(\"GIT_COMMITTER_EMAIL\")));\n+\t\t\thas_non_ascii(fmt_name(WANT_COMMITTER_IDENT));\n \tctx.date_mode = opt->date_mode;\n \tctx.date_mode_explicit = opt->date_mode_explicit;\n \tctx.abbrev = opt->diffopt.abbrev;\ndiff --git a/sequencer.c b/sequencer.c\nindex 213815dbfc..c031787826 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -837,7 +837,8 @@ static const char *read_author_ident(struct strbuf *buf)\n \t}\n \n \tstrbuf_reset(&out);\n-\tstrbuf_addstr(&out, fmt_ident(name, email, date, 0));\n+\tstrbuf_addstr(&out, fmt_ident(name, email, WANT_AUTHOR_IDENT, date,\n+\t\t\t\t      0));\n \tstrbuf_swap(buf, &out);\n \tstrbuf_release(&out);\n \tfree(name);\n@@ -4094,8 +4095,7 @@ void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag)\n \tint has_footer;\n \n \tstrbuf_addstr(&sob, sign_off_header);\n-\tstrbuf_addstr(&sob, fmt_name(getenv(\"GIT_COMMITTER_NAME\"),\n-\t\t\t\tgetenv(\"GIT_COMMITTER_EMAIL\")));\n+\tstrbuf_addstr(&sob, fmt_name(WANT_COMMITTER_IDENT));\n \tstrbuf_addch(&sob, '\\n');\n \n \tif (!ignore_footer)\ndiff --git a/t/t7517-per-repo-email.sh b/t/t7517-per-repo-email.sh\nindex 84bd9e89e5..e0182779ed 100755\n--- a/t/t7517-per-repo-email.sh\n+++ b/t/t7517-per-repo-email.sh\n@@ -85,7 +85,7 @@ test_expect_success REBASE_P \\\n \ttest_must_fail git rebase -p master\n '\n \n-test_expect_success 'fallbacks for GIT_* and user.{name,email}' '\n+test_expect_success 'fallbacks for GIT_* and {user,author,committer}.{name,email}' '\n \t# We must have committer in the object\n \ttest_must_fail test_env \\\n \t\tGIT_AUTHOR_NAME=author.name \\\n@@ -119,4 +119,78 @@ test_expect_success 'fallbacks for GIT_* and user.{name,email}' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'author.name overrides user.name' '\n+\ttest_config user.name user &&\n+\ttest_config user.email user@example.com &&\n+\ttest_config author.name author &&\n+\ttest_commit author-name-override-user &&\n+\techo author user@example.com >expected-author &&\n+\techo user user@example.com >expected-committer &&\n+\tgit log --format=\"%an %ae\" -1 >actual-author &&\n+\tgit log --format=\"%cn %ce\" -1 >actual-committer &&\n+\ttest_cmp expected-author actual-author &&\n+\ttest_cmp expected-committer actual-committer\n+'\n+\n+test_expect_success 'author.email overrides user.email' '\n+\ttest_config user.name user &&\n+\ttest_config user.email user@example.com &&\n+\ttest_config author.email author@example.com &&\n+\ttest_commit author-email-override-user &&\n+\techo user author@example.com >expected-author &&\n+\techo user user@example.com >expected-committer &&\n+\tgit log --format=\"%an %ae\" -1 >actual-author &&\n+\tgit log --format=\"%cn %ce\" -1 >actual-committer &&\n+\ttest_cmp expected-author actual-author &&\n+\ttest_cmp expected-committer actual-committer\n+'\n+\n+test_expect_success 'committer.name overrides user.name' '\n+\ttest_config user.name user &&\n+\ttest_config user.email user@example.com &&\n+\ttest_config committer.name committer &&\n+\ttest_commit committer-name-override-user &&\n+\techo user user@example.com >expected-author &&\n+\techo committer user@example.com >expected-committer &&\n+\tgit log --format=\"%an %ae\" -1 >actual-author &&\n+\tgit log --format=\"%cn %ce\" -1 >actual-committer &&\n+\ttest_cmp expected-author actual-author &&\n+\ttest_cmp expected-committer actual-committer\n+'\n+\n+test_expect_success 'committer.email overrides user.email' '\n+\ttest_config user.name user &&\n+\ttest_config user.email user@example.com &&\n+\ttest_config committer.email committer@example.com &&\n+\ttest_commit committer-email-override-user &&\n+\techo user user@example.com >expected-author &&\n+\techo user committer@example.com >expected-committer &&\n+\tgit log --format=\"%an %ae\" -1 >actual-author &&\n+\tgit log --format=\"%cn %ce\" -1 >actual-committer &&\n+\ttest_cmp expected-author actual-author &&\n+\ttest_cmp expected-committer actual-committer\n+'\n+\n+test_expect_success 'author and committer environment variables override config settings' '\n+\ttest_config user.name user &&\n+\ttest_config user.email user@example.com &&\n+\ttest_config author.name author &&\n+\ttest_config author.email author@example.com &&\n+\ttest_config committer.name committer &&\n+\ttest_config committer.email committer@example.com &&\n+\n+\ttest_env \\\n+\t\tGIT_AUTHOR_NAME=env_author \\\n+\t\tGIT_AUTHOR_EMAIL=env_author@example.com \\\n+\t\tGIT_COMMITTER_NAME=env_commit \\\n+\t\tGIT_COMMITTER_EMAIL=env_commit@example.com \\\n+\t\ttest_commit env-override-conf &&\n+\techo env_author env_author@example.com >expected-author &&\n+\techo env_commit env_commit@example.com >expected-committer &&\n+\tgit log --format=\"%an %ae\" -1 >actual-author &&\n+\tgit log --format=\"%cn %ce\" -1 >actual-committer &&\n+\ttest_cmp expected-author actual-author &&\n+\ttest_cmp expected-committer actual-committer\n+'\n+\n test_done\n-- \n2.20.1.611.gfbb209baf1\n\n"},{"id":"368541","messageId":"xmqqef8mrnnj.fsf@gitster-ct.c.googlers.com","threadId":"50396","inReplyTo":"20190205195212.25550-3-avarab@gmail.com","subject":"Re: [PATCH v6 2/2] config: allow giving separate author and committer idents","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-05T20:22:24Z","receivedAt":"2019-02-05T20:22:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> +static int set_ident_internal(const char *var, const char *value,\n> +\t\t\t    struct strbuf *sb, const int flag)\n> +{\n> +\tif (!value)\n> +\t\treturn config_error_nonbool(var);\n> +\tstrbuf_reset(sb);\n> +\tstrbuf_addstr(sb, value);\n> +\tauthor_ident_explicitly_given |= flag;\n> +\tident_config_given |= flag;\n> +\treturn 0;\n> +}\n> +\n> +static int set_ident(const char *var, const char *value)\n> +{\n> +\tif (!strcmp(var, \"author.name\"))\n> +\t\treturn set_ident_internal(var, value, &git_author_name,\n> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n> +\telse if (!strcmp(var, \"author.email\"))\n> +\t\treturn set_ident_internal(var, value, &git_author_email,\n> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n> +\telse if (!strcmp(var, \"committer.name\"))\n> +\t\treturn set_ident_internal(var, value, &git_committer_name,\n> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n> +\telse if (!strcmp(var, \"committer.email\"))\n> +\t\treturn set_ident_internal(var, value, &git_committer_email,\n> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n> +\telse if (!strcmp(var, \"user.name\"))\n> +\t\treturn set_ident_internal(var, value, &git_default_name,\n> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n> +\telse if (!strcmp(var, \"user.email\"))\n> +\t\treturn set_ident_internal(var, value, &git_default_email,\n> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n> +\treturn 0;\n> +}\n\nIn the v5 patch from William, author_ident_explicitly_given and\ncommitter_ident_explicitly_given were set separately depending on\nwhat variable was given (e.g. user.name marked both, author.name\nmarked only author but not committer_ident_explicitly_given).  In\nthe original before the addition of this feature with v6, giving\nuser.name would have set both, as we can see below.\n\nIs this change intended?  \n\nOr did you find that committer_ident_explicitly_given is no longer\nuseful and the variable is not used anymore?\n\n>  int git_ident_config(const char *var, const char *value, void *data)\n>  {\n>  \tif (!strcmp(var, \"user.useconfigonly\")) {\n> @@ -480,29 +551,7 @@ int git_ident_config(const char *var, const char *value, void *data)\n>  \t\treturn 0;\n>  \t}\n>  \n> -\tif (!strcmp(var, \"user.name\")) {\n> -\t\tif (!value)\n> -\t\t\treturn config_error_nonbool(var);\n> -\t\tstrbuf_reset(&git_default_name);\n> -\t\tstrbuf_addstr(&git_default_name, value);\n> -\t\tcommitter_ident_explicitly_given |= IDENT_NAME_GIVEN;\n> -\t\tauthor_ident_explicitly_given |= IDENT_NAME_GIVEN;\n> -\t\tident_config_given |= IDENT_NAME_GIVEN;\n> -\t\treturn 0;\n> -\t}\n> -\n> -\tif (!strcmp(var, \"user.email\")) {\n> -\t\tif (!value)\n> -\t\t\treturn config_error_nonbool(var);\n> -\t\tstrbuf_reset(&git_default_email);\n> -\t\tstrbuf_addstr(&git_default_email, value);\n> -\t\tcommitter_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n> -\t\tauthor_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n> -\t\tident_config_given |= IDENT_MAIL_GIVEN;\n> -\t\treturn 0;\n> -\t}\n> -\n> -\treturn 0;\n> +\treturn set_ident(var, value);\n>  }\n"},{"id":"368546","messageId":"87k1iekkea.fsf@evledraar.gmail.com","threadId":"50396","inReplyTo":"xmqqef8mrnnj.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v6 2/2] config: allow giving separate author and committer idents","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-02-05T21:14:37Z","receivedAt":"2019-02-05T21:14:42Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Feb 05 2019, Junio C Hamano wrote:\n\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>\n>> +static int set_ident_internal(const char *var, const char *value,\n>> +\t\t\t    struct strbuf *sb, const int flag)\n>> +{\n>> +\tif (!value)\n>> +\t\treturn config_error_nonbool(var);\n>> +\tstrbuf_reset(sb);\n>> +\tstrbuf_addstr(sb, value);\n>> +\tauthor_ident_explicitly_given |= flag;\n>> +\tident_config_given |= flag;\n>> +\treturn 0;\n>> +}\n>> +\n>> +static int set_ident(const char *var, const char *value)\n>> +{\n>> +\tif (!strcmp(var, \"author.name\"))\n>> +\t\treturn set_ident_internal(var, value, &git_author_name,\n>> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n>> +\telse if (!strcmp(var, \"author.email\"))\n>> +\t\treturn set_ident_internal(var, value, &git_author_email,\n>> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n>> +\telse if (!strcmp(var, \"committer.name\"))\n>> +\t\treturn set_ident_internal(var, value, &git_committer_name,\n>> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n>> +\telse if (!strcmp(var, \"committer.email\"))\n>> +\t\treturn set_ident_internal(var, value, &git_committer_email,\n>> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n>> +\telse if (!strcmp(var, \"user.name\"))\n>> +\t\treturn set_ident_internal(var, value, &git_default_name,\n>> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n>> +\telse if (!strcmp(var, \"user.email\"))\n>> +\t\treturn set_ident_internal(var, value, &git_default_email,\n>> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n>> +\treturn 0;\n>> +}\n>\n> In the v5 patch from William, author_ident_explicitly_given and\n> committer_ident_explicitly_given were set separately depending on\n> what variable was given (e.g. user.name marked both, author.name\n> marked only author but not committer_ident_explicitly_given).  In\n> the original before the addition of this feature with v6, giving\n> user.name would have set both, as we can see below.\n>\n> Is this change intended?\n>\n> Or did you find that committer_ident_explicitly_given is no longer\n> useful and the variable is not used anymore?\n\nNo, that's a mistake of mine when porting this over, but also clearly a\nblindspot in our tests since they all pass with this.\n\nI haven't dug (don't have time right now) to check what the effect of\nthat is. William?\n\n>>  int git_ident_config(const char *var, const char *value, void *data)\n>>  {\n>>  \tif (!strcmp(var, \"user.useconfigonly\")) {\n>> @@ -480,29 +551,7 @@ int git_ident_config(const char *var, const char *value, void *data)\n>>  \t\treturn 0;\n>>  \t}\n>>\n>> -\tif (!strcmp(var, \"user.name\")) {\n>> -\t\tif (!value)\n>> -\t\t\treturn config_error_nonbool(var);\n>> -\t\tstrbuf_reset(&git_default_name);\n>> -\t\tstrbuf_addstr(&git_default_name, value);\n>> -\t\tcommitter_ident_explicitly_given |= IDENT_NAME_GIVEN;\n>> -\t\tauthor_ident_explicitly_given |= IDENT_NAME_GIVEN;\n>> -\t\tident_config_given |= IDENT_NAME_GIVEN;\n>> -\t\treturn 0;\n>> -\t}\n>> -\n>> -\tif (!strcmp(var, \"user.email\")) {\n>> -\t\tif (!value)\n>> -\t\t\treturn config_error_nonbool(var);\n>> -\t\tstrbuf_reset(&git_default_email);\n>> -\t\tstrbuf_addstr(&git_default_email, value);\n>> -\t\tcommitter_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n>> -\t\tauthor_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n>> -\t\tident_config_given |= IDENT_MAIL_GIVEN;\n>> -\t\treturn 0;\n>> -\t}\n>> -\n>> -\treturn 0;\n>> +\treturn set_ident(var, value);\n>>  }\n"},{"id":"368551","messageId":"20190206000413.GA734@whubbs1.gaikai.biz","threadId":"50396","inReplyTo":"87k1iekkea.fsf@evledraar.gmail.com","subject":"Re: [PATCH v6 2/2] config: allow giving separate author and committer idents","fromName":"William Hubbs","fromEmail":"williamh@gentoo.org","sentAt":"2019-02-06T00:04:13Z","receivedAt":"2019-02-06T00:04:17Z","isPatch":true,"sender":{"key":"williamh@gentoo.org","avatar":"https://avatars.githubusercontent.com/u/64355?v=4"},"body":"On Tue, Feb 05, 2019 at 10:14:37PM +0100, Ævar Arnfjörð Bjarmason wrote:\n> \n> On Tue, Feb 05 2019, Junio C Hamano wrote:\n> \n> > Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n> >\n> >> +static int set_ident_internal(const char *var, const char *value,\n> >> +\t\t\t    struct strbuf *sb, const int flag)\n> >> +{\n> >> +\tif (!value)\n> >> +\t\treturn config_error_nonbool(var);\n> >> +\tstrbuf_reset(sb);\n> >> +\tstrbuf_addstr(sb, value);\n> >> +\tauthor_ident_explicitly_given |= flag;\n> >> +\tident_config_given |= flag;\n> >> +\treturn 0;\n> >> +}\n> >> +\n> >> +static int set_ident(const char *var, const char *value)\n> >> +{\n> >> +\tif (!strcmp(var, \"author.name\"))\n> >> +\t\treturn set_ident_internal(var, value, &git_author_name,\n> >> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n> >> +\telse if (!strcmp(var, \"author.email\"))\n> >> +\t\treturn set_ident_internal(var, value, &git_author_email,\n> >> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n> >> +\telse if (!strcmp(var, \"committer.name\"))\n> >> +\t\treturn set_ident_internal(var, value, &git_committer_name,\n> >> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n> >> +\telse if (!strcmp(var, \"committer.email\"))\n> >> +\t\treturn set_ident_internal(var, value, &git_committer_email,\n> >> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n> >> +\telse if (!strcmp(var, \"user.name\"))\n> >> +\t\treturn set_ident_internal(var, value, &git_default_name,\n> >> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n> >> +\telse if (!strcmp(var, \"user.email\"))\n> >> +\t\treturn set_ident_internal(var, value, &git_default_email,\n> >> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n> >> +\treturn 0;\n> >> +}\n> >\n> > In the v5 patch from William, author_ident_explicitly_given and\n> > committer_ident_explicitly_given were set separately depending on\n> > what variable was given (e.g. user.name marked both, author.name\n> > marked only author but not committer_ident_explicitly_given).  In\n> > the original before the addition of this feature with v6, giving\n> > user.name would have set both, as we can see below.\n> >\n> > Is this change intended?\n> >\n> > Or did you find that committer_ident_explicitly_given is no longer\n> > useful and the variable is not used anymore?\n> \n> No, that's a mistake of mine when porting this over, but also clearly a\n> blindspot in our tests since they all pass with this.\n> \n> I haven't dug (don't have time right now) to check what the effect of\n> that is. William?\n\nI attempted to save your patches to apply them, but didn't have any luck\n\nAlso, according to Junio's report, my patch is already merged to next,\nso if you give me your patch based on that, I'll take a look, but it may\nbe a day or so.\n\nWilliam\n"},{"id":"368552","messageId":"20190206001558.GB734@whubbs1.gaikai.biz","threadId":"50396","inReplyTo":"20190206000413.GA734@whubbs1.gaikai.biz","subject":"Re: [PATCH v6 2/2] config: allow giving separate author and committer idents","fromName":"William Hubbs","fromEmail":"williamh@gentoo.org","sentAt":"2019-02-06T00:15:58Z","receivedAt":"2019-02-06T00:16:03Z","isPatch":true,"sender":{"key":"williamh@gentoo.org","avatar":"https://avatars.githubusercontent.com/u/64355?v=4"},"body":"On Tue, Feb 05, 2019 at 06:04:13PM -0600, William Hubbs wrote:\n> On Tue, Feb 05, 2019 at 10:14:37PM +0100, Ævar Arnfjörð Bjarmason wrote:\n> > \n> > On Tue, Feb 05 2019, Junio C Hamano wrote:\n> > \n> > > Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n> > >\n> > >> +static int set_ident_internal(const char *var, const char *value,\n> > >> +\t\t\t    struct strbuf *sb, const int flag)\n> > >> +{\n> > >> +\tif (!value)\n> > >> +\t\treturn config_error_nonbool(var);\n> > >> +\tstrbuf_reset(sb);\n> > >> +\tstrbuf_addstr(sb, value);\n> > >> +\tauthor_ident_explicitly_given |= flag;\n> > >> +\tident_config_given |= flag;\n> > >> +\treturn 0;\n> > >> +}\n> > >> +\n> > >> +static int set_ident(const char *var, const char *value)\n> > >> +{\n> > >> +\tif (!strcmp(var, \"author.name\"))\n> > >> +\t\treturn set_ident_internal(var, value, &git_author_name,\n> > >> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n> > >> +\telse if (!strcmp(var, \"author.email\"))\n> > >> +\t\treturn set_ident_internal(var, value, &git_author_email,\n> > >> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n> > >> +\telse if (!strcmp(var, \"committer.name\"))\n> > >> +\t\treturn set_ident_internal(var, value, &git_committer_name,\n> > >> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n> > >> +\telse if (!strcmp(var, \"committer.email\"))\n> > >> +\t\treturn set_ident_internal(var, value, &git_committer_email,\n> > >> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n> > >> +\telse if (!strcmp(var, \"user.name\"))\n> > >> +\t\treturn set_ident_internal(var, value, &git_default_name,\n> > >> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n> > >> +\telse if (!strcmp(var, \"user.email\"))\n> > >> +\t\treturn set_ident_internal(var, value, &git_default_email,\n> > >> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n> > >> +\treturn 0;\n> > >> +}\n> > >\n> > > In the v5 patch from William, author_ident_explicitly_given and\n> > > committer_ident_explicitly_given were set separately depending on\n> > > what variable was given (e.g. user.name marked both, author.name\n> > > marked only author but not committer_ident_explicitly_given).  In\n> > > the original before the addition of this feature with v6, giving\n> > > user.name would have set both, as we can see below.\n> > >\n> > > Is this change intended?\n> > >\n> > > Or did you find that committer_ident_explicitly_given is no longer\n> > > useful and the variable is not used anymore?\n> > \n> > No, that's a mistake of mine when porting this over, but also clearly a\n> > blindspot in our tests since they all pass with this.\n> > \n> > I haven't dug (don't have time right now) to check what the effect of\n> > that is. William?\n> \n> I attempted to save your patches to apply them, but didn't have any luck\n\nMore info here. I use mutt and when I tagged the patches and saved them\nto a mailbox, they went to a mailldir type folder, and \"git am\" didn't\nseem to like that, but I'll try again.\n\n> Also, according to Junio's report, my patch is already merged to next,\n> so if you give me your patch based on that, I'll take a look, but it may\n> be a day or so.\n\nSorry, I misread, my patch is not in next.\n\nBut, Junio's discussion above is why I didn't make this change. I don't\nknow the code base all that well, so I didn't want my first patch to\npossibly introduce regressions. :-)\n\nWilliam\n"},{"id":"368562","messageId":"20190206010543.GA1035@whubbs1.gaikai.biz","threadId":"50396","inReplyTo":"20190206001558.GB734@whubbs1.gaikai.biz","subject":"Re: [PATCH v6 2/2] config: allow giving separate author and committer idents","fromName":"William Hubbs","fromEmail":"williamh@gentoo.org","sentAt":"2019-02-06T01:05:43Z","receivedAt":"2019-02-06T01:05:48Z","isPatch":true,"sender":{"key":"williamh@gentoo.org","avatar":"https://avatars.githubusercontent.com/u/64355?v=4"},"body":"On Tue, Feb 05, 2019 at 06:15:58PM -0600, William Hubbs wrote:\n> On Tue, Feb 05, 2019 at 06:04:13PM -0600, William Hubbs wrote:\n> > On Tue, Feb 05, 2019 at 10:14:37PM +0100, Ævar Arnfjörð Bjarmason wrote:\n> > > \n> > > On Tue, Feb 05 2019, Junio C Hamano wrote:\n> > > \n> > > > Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n> > > >\n> > > >> +static int set_ident_internal(const char *var, const char *value,\n> > > >> +\t\t\t    struct strbuf *sb, const int flag)\n> > > >> +{\n> > > >> +\tif (!value)\n> > > >> +\t\treturn config_error_nonbool(var);\n> > > >> +\tstrbuf_reset(sb);\n> > > >> +\tstrbuf_addstr(sb, value);\n> > > >> +\tauthor_ident_explicitly_given |= flag;\n> > > >> +\tident_config_given |= flag;\n> > > >> +\treturn 0;\n> > > >> +}\n> > > >> +\n> > > >> +static int set_ident(const char *var, const char *value)\n> > > >> +{\n> > > >> +\tif (!strcmp(var, \"author.name\"))\n> > > >> +\t\treturn set_ident_internal(var, value, &git_author_name,\n> > > >> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n> > > >> +\telse if (!strcmp(var, \"author.email\"))\n> > > >> +\t\treturn set_ident_internal(var, value, &git_author_email,\n> > > >> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n> > > >> +\telse if (!strcmp(var, \"committer.name\"))\n> > > >> +\t\treturn set_ident_internal(var, value, &git_committer_name,\n> > > >> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n> > > >> +\telse if (!strcmp(var, \"committer.email\"))\n> > > >> +\t\treturn set_ident_internal(var, value, &git_committer_email,\n> > > >> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n> > > >> +\telse if (!strcmp(var, \"user.name\"))\n> > > >> +\t\treturn set_ident_internal(var, value, &git_default_name,\n> > > >> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n> > > >> +\telse if (!strcmp(var, \"user.email\"))\n> > > >> +\t\treturn set_ident_internal(var, value, &git_default_email,\n> > > >> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n> > > >> +\treturn 0;\n> > > >> +}\n> > > >\n> > > > In the v5 patch from William, author_ident_explicitly_given and\n> > > > committer_ident_explicitly_given were set separately depending on\n> > > > what variable was given (e.g. user.name marked both, author.name\n> > > > marked only author but not committer_ident_explicitly_given).  In\n> > > > the original before the addition of this feature with v6, giving\n> > > > user.name would have set both, as we can see below.\n> > > >\n> > > > Is this change intended?\n> > > >\n> > > > Or did you find that committer_ident_explicitly_given is no longer\n> > > > useful and the variable is not used anymore?\n> > > \n> > > No, that's a mistake of mine when porting this over, but also clearly a\n> > > blindspot in our tests since they all pass with this.\n> > > \n> > > I haven't dug (don't have time right now) to check what the effect of\n> > > that is. William?\n> > \n> > I attempted to save your patches to apply them, but didn't have any luck\n> \n> More info here. I use mutt and when I tagged the patches and saved them\n> to a mailbox, they went to a mailldir type folder, and \"git am\" didn't\n> seem to like that, but I'll try again.\n\nI tried one more time, saving the patches to individual files, and they\nstill would not apply.\n\nThanks,\n\nWilliam\n\n"},{"id":"368566","messageId":"xmqqwomdqzik.fsf@gitster-ct.c.googlers.com","threadId":"50396","inReplyTo":"20190206000413.GA734@whubbs1.gaikai.biz","subject":"Re: [PATCH v6 2/2] config: allow giving separate author and committer idents","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-06T05:03:47Z","receivedAt":"2019-02-06T05:03:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"William Hubbs <williamh@gentoo.org> writes:\n\n> I attempted to save your patches to apply them, but didn't have any luck\n\nI'll push a topic branch (not merged to any of the integration\nbranches) ab/author-committer-ident-config later today at the\nhttps://github.com/gitster/git repository.\n\n> Also, according to Junio's report, my patch is already merged to next,\n\nIn an earlier \"What's cooking\" I may have said that I plan to merge\nit to 'next', but I think the plan is now to leave it there for now\nuntil this discussion settles and the latest report should reflect\nthat.\n\nI just double-checked and wh/author-committer-ident-config is not in\n'next'.  Whew.\n\nHere is a diff that turns wh/author-committer-ident-config into what\nab/author-committer-ident-config has.  There are some formatting\nchanges, all of which I agree with, a bogus set_ident() refactoring\nthat should not be used, in addition to some test changes.\n\n Documentation/git-commit-tree.txt |  3 +-\n builtin/am.c                      |  2 +-\n builtin/commit.c                  |  2 +-\n cache.h                           |  4 +-\n ident.c                           | 95 +++++++++++++--------------------------\n sequencer.c                       |  3 +-\n t/t7517-per-repo-email.sh         | 88 +++++++++++++++++++++++++-----------\n 7 files changed, 101 insertions(+), 96 deletions(-)\n\ndiff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt\nindex 002dae625e..091e3a77ca 100644\n--- a/Documentation/git-commit-tree.txt\n+++ b/Documentation/git-commit-tree.txt\n@@ -88,7 +88,8 @@ if set:\n (nb \"<\", \">\" and \"\\n\"s are stripped)\n \n In case (some of) these environment variables are not set, the information\n-is taken from the configuration items user.name and user.email, or, if not\n+is taken from the configuration items user.name and user.email, or the more\n+specific author.{name,email} and committer.{name,email} variables, or, if not\n present, the environment variable EMAIL, or, if that is not set,\n system user name and the hostname used for outgoing mail (taken\n from `/etc/mailname` and falling back to the fully qualified hostname when\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 3727d4d267..d4a1cbe828 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -1594,7 +1594,7 @@ static void do_commit(const struct am_state *state)\n \t}\n \n \tauthor = fmt_ident(state->author_name, state->author_email,\n-\t\tWANT_AUTHOR_IDENT,\n+\t\t\tWANT_AUTHOR_IDENT,\n \t\t\tstate->ignore_date ? NULL : state->author_date,\n \t\t\tIDENT_STRICT);\n \ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex f96b90daeb..a7879d65d1 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -608,7 +608,7 @@ static void determine_author_info(struct strbuf *author_ident)\n \t}\n \n \tstrbuf_addstr(author_ident, fmt_ident(name, email, WANT_AUTHOR_IDENT, date,\n-\t\t\t\tIDENT_STRICT));\n+\t\t\t\t\t      IDENT_STRICT));\n \tassert_split_ident(&author, author_ident);\n \texport_one(\"GIT_AUTHOR_NAME\", author.name_begin, author.name_end, 0);\n \texport_one(\"GIT_AUTHOR_EMAIL\", author.mail_begin, author.mail_end, 0);\ndiff --git a/cache.h b/cache.h\nindex bb78eb9a3a..ca6ba1e423 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1489,8 +1489,8 @@ enum want_ident {\n extern const char *git_author_info(int);\n extern const char *git_committer_info(int);\n extern const char *fmt_ident(const char *name, const char *email,\n-\t\tenum want_ident whose_ident,\n-\t\tconst char *date_str, int);\n+\t\t\t     enum want_ident whose_ident,\n+\t\t\t     const char *date_str, int flag);\n extern const char *fmt_name(enum want_ident);\n extern const char *ident_default_name(void);\n extern const char *ident_default_email(void);\ndiff --git a/ident.c b/ident.c\nindex 9c2eb0a2d0..7c3be81ee1 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -359,7 +359,8 @@ N_(\"\\n\"\n    \"\\n\");\n \n const char *fmt_ident(const char *name, const char *email,\n-\t\t      enum want_ident whose_ident, const char *date_str, int flag)\n+\t\t      enum want_ident whose_ident, const char *date_str,\n+\t\t      int flag)\n {\n \tstatic struct strbuf ident = STRBUF_INIT;\n \tint strict = (flag & IDENT_STRICT);\n@@ -508,70 +509,38 @@ int author_ident_sufficiently_given(void)\n \treturn ident_is_sufficient(author_ident_explicitly_given);\n }\n \n-static int set_ident(const char *var, const char *value)\n+static int set_ident_internal(const char *var, const char *value,\n+\t\t\t    struct strbuf *sb, const int flag)\n {\n-\tif (!strcmp(var, \"author.name\")) {\n-\t\tif (!value)\n-\t\t\treturn config_error_nonbool(var);\n-\t\tstrbuf_reset(&git_author_name);\n-\t\tstrbuf_addstr(&git_author_name, value);\n-\t\tauthor_ident_explicitly_given |= IDENT_NAME_GIVEN;\n-\t\tident_config_given |= IDENT_NAME_GIVEN;\n-\t\treturn 0;\n-\t}\n-\n-\tif (!strcmp(var, \"author.email\")) {\n-\t\tif (!value)\n-\t\t\treturn config_error_nonbool(var);\n-\t\tstrbuf_reset(&git_author_email);\n-\t\tstrbuf_addstr(&git_author_email, value);\n-\t\tauthor_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n-\t\tident_config_given |= IDENT_MAIL_GIVEN;\n-\t\treturn 0;\n-\t}\n-\n-\tif (!strcmp(var, \"committer.name\")) {\n-\t\tif (!value)\n-\t\t\treturn config_error_nonbool(var);\n-\t\tstrbuf_reset(&git_committer_name);\n-\t\tstrbuf_addstr(&git_committer_name, value);\n-\t\tcommitter_ident_explicitly_given |= IDENT_NAME_GIVEN;\n-\t\tident_config_given |= IDENT_NAME_GIVEN;\n-\t\treturn 0;\n-\t}\n-\n-\tif (!strcmp(var, \"committer.email\")) {\n-\t\tif (!value)\n-\t\t\treturn config_error_nonbool(var);\n-\t\tstrbuf_reset(&git_committer_email);\n-\t\tstrbuf_addstr(&git_committer_email, value);\n-\t\tcommitter_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n-\t\tident_config_given |= IDENT_MAIL_GIVEN;\n-\t\treturn 0;\n-\t}\n-\n-\tif (!strcmp(var, \"user.name\")) {\n-\t\tif (!value)\n-\t\t\treturn config_error_nonbool(var);\n-\t\tstrbuf_reset(&git_default_name);\n-\t\tstrbuf_addstr(&git_default_name, value);\n-\t\tcommitter_ident_explicitly_given |= IDENT_NAME_GIVEN;\n-\t\tauthor_ident_explicitly_given |= IDENT_NAME_GIVEN;\n-\t\tident_config_given |= IDENT_NAME_GIVEN;\n-\t\treturn 0;\n-\t}\n-\n-\tif (!strcmp(var, \"user.email\")) {\n-\t\tif (!value)\n-\t\t\treturn config_error_nonbool(var);\n-\t\tstrbuf_reset(&git_default_email);\n-\t\tstrbuf_addstr(&git_default_email, value);\n-\t\tcommitter_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n-\t\tauthor_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n-\t\tident_config_given |= IDENT_MAIL_GIVEN;\n-\t\treturn 0;\n-\t}\n+\tif (!value)\n+\t\treturn config_error_nonbool(var);\n+\tstrbuf_reset(sb);\n+\tstrbuf_addstr(sb, value);\n+\tauthor_ident_explicitly_given |= flag;\n+\tident_config_given |= flag;\n+\treturn 0;\n+}\n \n+static int set_ident(const char *var, const char *value)\n+{\n+\tif (!strcmp(var, \"author.name\"))\n+\t\treturn set_ident_internal(var, value, &git_author_name,\n+\t\t\t\t\t  IDENT_NAME_GIVEN);\n+\telse if (!strcmp(var, \"author.email\"))\n+\t\treturn set_ident_internal(var, value, &git_author_email,\n+\t\t\t\t\t  IDENT_MAIL_GIVEN);\n+\telse if (!strcmp(var, \"committer.name\"))\n+\t\treturn set_ident_internal(var, value, &git_committer_name,\n+\t\t\t\t\t  IDENT_NAME_GIVEN);\n+\telse if (!strcmp(var, \"committer.email\"))\n+\t\treturn set_ident_internal(var, value, &git_committer_email,\n+\t\t\t\t\t  IDENT_MAIL_GIVEN);\n+\telse if (!strcmp(var, \"user.name\"))\n+\t\treturn set_ident_internal(var, value, &git_default_name,\n+\t\t\t\t\t  IDENT_NAME_GIVEN);\n+\telse if (!strcmp(var, \"user.email\"))\n+\t\treturn set_ident_internal(var, value, &git_default_email,\n+\t\t\t\t\t  IDENT_MAIL_GIVEN);\n \treturn 0;\n }\n \ndiff --git a/sequencer.c b/sequencer.c\nindex 3505d52bb9..98ba2106f6 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -836,7 +836,8 @@ static const char *read_author_ident(struct strbuf *buf)\n \t}\n \n \tstrbuf_reset(&out);\n-\tstrbuf_addstr(&out, fmt_ident(name, email, WANT_AUTHOR_IDENT, date, 0));\n+\tstrbuf_addstr(&out, fmt_ident(name, email, WANT_AUTHOR_IDENT, date,\n+\t\t\t\t      0));\n \tstrbuf_swap(buf, &out);\n \tstrbuf_release(&out);\n \tfree(name);\ndiff --git a/t/t7517-per-repo-email.sh b/t/t7517-per-repo-email.sh\nindex b2401cec3e..e0182779ed 100755\n--- a/t/t7517-per-repo-email.sh\n+++ b/t/t7517-per-repo-email.sh\n@@ -85,15 +85,49 @@ test_expect_success REBASE_P \\\n \ttest_must_fail git rebase -p master\n '\n \n+test_expect_success 'fallbacks for GIT_* and {user,author,committer}.{name,email}' '\n+\t# We must have committer in the object\n+\ttest_must_fail test_env \\\n+\t\tGIT_AUTHOR_NAME=author.name \\\n+\t\tGIT_AUTHOR_EMAIL=author@email \\\n+\t\tGIT_COMMITTER_NAME= \\\n+\t\tGIT_COMMITTER_EMAIL= \\\n+\t\ttest_commit A 2>stderr &&\n+\ttest_i18ngrep \"empty ident name.*not allowed\" stderr &&\n+\n+\t# With no committer E-Mail we will have an empty field\n+\ttest_env \\\n+\t\tGIT_AUTHOR_NAME=author.name \\\n+\t\tGIT_AUTHOR_EMAIL=author@email \\\n+\t\tGIT_COMMITTER_NAME=committer.name \\\n+\t\tGIT_COMMITTER_EMAIL= \\\n+\t\ttest_commit B 2>stderr &&\n+\techo \"author.name author@email committer.name \" >expected &&\n+\tgit log --format=\"%an %ae %cn %ce\" -1 >actual &&\n+\ttest_cmp expected actual &&\n+\n+\t# Environment overrides config\n+\ttest_config user.name author.config.name &&\n+\ttest_env \\\n+\t\tGIT_AUTHOR_NAME=author.name \\\n+\t\tGIT_AUTHOR_EMAIL=author@email \\\n+\t\tGIT_COMMITTER_NAME=committer.name \\\n+\t\tGIT_COMMITTER_EMAIL= \\\n+\t\ttest_commit C 2>stderr &&\n+\techo \"author.name author@email committer.name \" >expected &&\n+\tgit log --format=\"%an %ae %cn %ce\" -1 >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_expect_success 'author.name overrides user.name' '\n \ttest_config user.name user &&\n \ttest_config user.email user@example.com &&\n \ttest_config author.name author &&\n \ttest_commit author-name-override-user &&\n-\techo author user@example.com > expected-author &&\n-\techo user user@example.com > expected-committer &&\n-\tgit log --format=\"%an %ae\" -1 > actual-author &&\n-\tgit log --format=\"%cn %ce\" -1 > actual-committer &&\n+\techo author user@example.com >expected-author &&\n+\techo user user@example.com >expected-committer &&\n+\tgit log --format=\"%an %ae\" -1 >actual-author &&\n+\tgit log --format=\"%cn %ce\" -1 >actual-committer &&\n \ttest_cmp expected-author actual-author &&\n \ttest_cmp expected-committer actual-committer\n '\n@@ -103,10 +137,10 @@ test_expect_success 'author.email overrides user.email' '\n \ttest_config user.email user@example.com &&\n \ttest_config author.email author@example.com &&\n \ttest_commit author-email-override-user &&\n-\techo user author@example.com > expected-author &&\n-\techo user user@example.com > expected-committer &&\n-\tgit log --format=\"%an %ae\" -1 > actual-author &&\n-\tgit log --format=\"%cn %ce\" -1 > actual-committer &&\n+\techo user author@example.com >expected-author &&\n+\techo user user@example.com >expected-committer &&\n+\tgit log --format=\"%an %ae\" -1 >actual-author &&\n+\tgit log --format=\"%cn %ce\" -1 >actual-committer &&\n \ttest_cmp expected-author actual-author &&\n \ttest_cmp expected-committer actual-committer\n '\n@@ -116,10 +150,10 @@ test_expect_success 'committer.name overrides user.name' '\n \ttest_config user.email user@example.com &&\n \ttest_config committer.name committer &&\n \ttest_commit committer-name-override-user &&\n-\techo user user@example.com > expected-author &&\n-\techo committer user@example.com > expected-committer &&\n-\tgit log --format=\"%an %ae\" -1 > actual-author &&\n-\tgit log --format=\"%cn %ce\" -1 > actual-committer &&\n+\techo user user@example.com >expected-author &&\n+\techo committer user@example.com >expected-committer &&\n+\tgit log --format=\"%an %ae\" -1 >actual-author &&\n+\tgit log --format=\"%cn %ce\" -1 >actual-committer &&\n \ttest_cmp expected-author actual-author &&\n \ttest_cmp expected-committer actual-committer\n '\n@@ -129,10 +163,10 @@ test_expect_success 'committer.email overrides user.email' '\n \ttest_config user.email user@example.com &&\n \ttest_config committer.email committer@example.com &&\n \ttest_commit committer-email-override-user &&\n-\techo user user@example.com > expected-author &&\n-\techo user committer@example.com > expected-committer &&\n-\tgit log --format=\"%an %ae\" -1 > actual-author &&\n-\tgit log --format=\"%cn %ce\" -1 > actual-committer &&\n+\techo user user@example.com >expected-author &&\n+\techo user committer@example.com >expected-committer &&\n+\tgit log --format=\"%an %ae\" -1 >actual-author &&\n+\tgit log --format=\"%cn %ce\" -1 >actual-committer &&\n \ttest_cmp expected-author actual-author &&\n \ttest_cmp expected-committer actual-committer\n '\n@@ -144,17 +178,17 @@ test_expect_success 'author and committer environment variables override config\n \ttest_config author.email author@example.com &&\n \ttest_config committer.name committer &&\n \ttest_config committer.email committer@example.com &&\n-\tGIT_AUTHOR_NAME=env_author && export GIT_AUTHOR_NAME &&\n-\tGIT_AUTHOR_EMAIL=env_author@example.com && export GIT_AUTHOR_EMAIL &&\n-\tGIT_COMMITTER_NAME=env_commit && export GIT_COMMITTER_NAME &&\n-\tGIT_COMMITTER_EMAIL=env_commit@example.com && export GIT_COMMITTER_EMAIL &&\n-\ttest_commit env-override-conf &&\n-\techo env_author env_author@example.com > expected-author &&\n-\techo env_commit env_commit@example.com > expected-committer &&\n-\tgit log --format=\"%an %ae\" -1 > actual-author &&\n-\tgit log --format=\"%cn %ce\" -1 > actual-committer &&\n-\tsane_unset GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL &&\n-\tsane_unset GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL &&\n+\n+\ttest_env \\\n+\t\tGIT_AUTHOR_NAME=env_author \\\n+\t\tGIT_AUTHOR_EMAIL=env_author@example.com \\\n+\t\tGIT_COMMITTER_NAME=env_commit \\\n+\t\tGIT_COMMITTER_EMAIL=env_commit@example.com \\\n+\t\ttest_commit env-override-conf &&\n+\techo env_author env_author@example.com >expected-author &&\n+\techo env_commit env_commit@example.com >expected-committer &&\n+\tgit log --format=\"%an %ae\" -1 >actual-author &&\n+\tgit log --format=\"%cn %ce\" -1 >actual-committer &&\n \ttest_cmp expected-author actual-author &&\n \ttest_cmp expected-committer actual-committer\n '\n\n"},{"id":"368567","messageId":"87imxxl2cv.fsf@evledraar.gmail.com","threadId":"50396","inReplyTo":"20190206000413.GA734@whubbs1.gaikai.biz","subject":"Re: [PATCH v6 2/2] config: allow giving separate author and committer idents","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-02-06T08:58:56Z","receivedAt":"2019-02-06T08:59:02Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Wed, Feb 06 2019, William Hubbs wrote:\n\n> On Tue, Feb 05, 2019 at 10:14:37PM +0100, Ævar Arnfjörð Bjarmason wrote:\n>>\n>> On Tue, Feb 05 2019, Junio C Hamano wrote:\n>>\n>> > Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>> >\n>> >> +static int set_ident_internal(const char *var, const char *value,\n>> >> +\t\t\t    struct strbuf *sb, const int flag)\n>> >> +{\n>> >> +\tif (!value)\n>> >> +\t\treturn config_error_nonbool(var);\n>> >> +\tstrbuf_reset(sb);\n>> >> +\tstrbuf_addstr(sb, value);\n>> >> +\tauthor_ident_explicitly_given |= flag;\n>> >> +\tident_config_given |= flag;\n>> >> +\treturn 0;\n>> >> +}\n>> >> +\n>> >> +static int set_ident(const char *var, const char *value)\n>> >> +{\n>> >> +\tif (!strcmp(var, \"author.name\"))\n>> >> +\t\treturn set_ident_internal(var, value, &git_author_name,\n>> >> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n>> >> +\telse if (!strcmp(var, \"author.email\"))\n>> >> +\t\treturn set_ident_internal(var, value, &git_author_email,\n>> >> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n>> >> +\telse if (!strcmp(var, \"committer.name\"))\n>> >> +\t\treturn set_ident_internal(var, value, &git_committer_name,\n>> >> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n>> >> +\telse if (!strcmp(var, \"committer.email\"))\n>> >> +\t\treturn set_ident_internal(var, value, &git_committer_email,\n>> >> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n>> >> +\telse if (!strcmp(var, \"user.name\"))\n>> >> +\t\treturn set_ident_internal(var, value, &git_default_name,\n>> >> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n>> >> +\telse if (!strcmp(var, \"user.email\"))\n>> >> +\t\treturn set_ident_internal(var, value, &git_default_email,\n>> >> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n>> >> +\treturn 0;\n>> >> +}\n>> >\n>> > In the v5 patch from William, author_ident_explicitly_given and\n>> > committer_ident_explicitly_given were set separately depending on\n>> > what variable was given (e.g. user.name marked both, author.name\n>> > marked only author but not committer_ident_explicitly_given).  In\n>> > the original before the addition of this feature with v6, giving\n>> > user.name would have set both, as we can see below.\n>> >\n>> > Is this change intended?\n>> >\n>> > Or did you find that committer_ident_explicitly_given is no longer\n>> > useful and the variable is not used anymore?\n>>\n>> No, that's a mistake of mine when porting this over, but also clearly a\n>> blindspot in our tests since they all pass with this.\n>>\n>> I haven't dug (don't have time right now) to check what the effect of\n>> that is. William?\n>\n> I attempted to save your patches to apply them, but didn't have any luck\n\nOn top of current master you can do e.g.:\n\n    vm git (master $=) $ wget -q -O- https://public-inbox.org/git/20190205195212.25550-2-avarab@gmail.com/raw | git am\n    Applying: ident: test how GIT_* and user.{name,email} interact\n    vm git (master $>) $ wget -q -O- https://public-inbox.org/git/20190205195212.25550-3-avarab@gmail.com/raw | git am\n    Applying: config: allow giving separate author and committer idents\n\nI also push these to https://github.com/avar/git.git although not always\nin a timely manner...\n"},{"id":"368568","messageId":"87h8dhl0zh.fsf@evledraar.gmail.com","threadId":"50396","inReplyTo":"87k1iekkea.fsf@evledraar.gmail.com","subject":"Re: [PATCH v6 2/2] config: allow giving separate author and committer idents","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-02-06T09:28:34Z","receivedAt":"2019-02-06T09:28:41Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Feb 05 2019, Ævar Arnfjörð Bjarmason wrote:\n\n> On Tue, Feb 05 2019, Junio C Hamano wrote:\n>\n>> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>>\n>>> +static int set_ident_internal(const char *var, const char *value,\n>>> +\t\t\t    struct strbuf *sb, const int flag)\n>>> +{\n>>> +\tif (!value)\n>>> +\t\treturn config_error_nonbool(var);\n>>> +\tstrbuf_reset(sb);\n>>> +\tstrbuf_addstr(sb, value);\n>>> +\tauthor_ident_explicitly_given |= flag;\n>>> +\tident_config_given |= flag;\n>>> +\treturn 0;\n>>> +}\n>>> +\n>>> +static int set_ident(const char *var, const char *value)\n>>> +{\n>>> +\tif (!strcmp(var, \"author.name\"))\n>>> +\t\treturn set_ident_internal(var, value, &git_author_name,\n>>> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n>>> +\telse if (!strcmp(var, \"author.email\"))\n>>> +\t\treturn set_ident_internal(var, value, &git_author_email,\n>>> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n>>> +\telse if (!strcmp(var, \"committer.name\"))\n>>> +\t\treturn set_ident_internal(var, value, &git_committer_name,\n>>> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n>>> +\telse if (!strcmp(var, \"committer.email\"))\n>>> +\t\treturn set_ident_internal(var, value, &git_committer_email,\n>>> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n>>> +\telse if (!strcmp(var, \"user.name\"))\n>>> +\t\treturn set_ident_internal(var, value, &git_default_name,\n>>> +\t\t\t\t\t  IDENT_NAME_GIVEN);\n>>> +\telse if (!strcmp(var, \"user.email\"))\n>>> +\t\treturn set_ident_internal(var, value, &git_default_email,\n>>> +\t\t\t\t\t  IDENT_MAIL_GIVEN);\n>>> +\treturn 0;\n>>> +}\n>>\n>> In the v5 patch from William, author_ident_explicitly_given and\n>> committer_ident_explicitly_given were set separately depending on\n>> what variable was given (e.g. user.name marked both, author.name\n>> marked only author but not committer_ident_explicitly_given).  In\n>> the original before the addition of this feature with v6, giving\n>> user.name would have set both, as we can see below.\n>>\n>> Is this change intended?\n>>\n>> Or did you find that committer_ident_explicitly_given is no longer\n>> useful and the variable is not used anymore?\n>\n> No, that's a mistake of mine when porting this over, but also clearly a\n> blindspot in our tests since they all pass with this.\n>\n> I haven't dug (don't have time right now) to check what the effect of\n> that is. William?\n\nI did some further digging. One of the confusing things is that we've\nbeen carrying dead code since 2012 to set this\nauthor_ident_explicitly_given variable. We can just apply this on top of\nmaster:\n\n     cache.h |  1 -\n     ident.c | 13 -------------\n     2 files changed, 14 deletions(-)\n\n    diff --git a/cache.h b/cache.h\n    index 038e3764a9..52308bd5e4 100644\n    --- a/cache.h\n    +++ b/cache.h\n    @@ -1631,3 +1631,2 @@ extern int ignore_untracked_cache_config;\n     extern int committer_ident_sufficiently_given(void);\n    -extern int author_ident_sufficiently_given(void);\n\n    diff --git a/ident.c b/ident.c\n    index 33bcf40644..95fa2370e5 100644\n    --- a/ident.c\n    +++ b/ident.c\n    @@ -22,3 +22,2 @@ static int ident_use_config_only;\n     static int committer_ident_explicitly_given;\n    -static int author_ident_explicitly_given;\n     static int ident_config_given;\n    @@ -169,3 +168,2 @@ const char *ident_default_email(void)\n     \t\t\tcommitter_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n    -\t\t\tauthor_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n     \t\t} else if ((email = query_user_email()) && email[0]) {\n    @@ -434,6 +432,2 @@ const char *git_author_info(int flag)\n     {\n    -\tif (getenv(\"GIT_AUTHOR_NAME\"))\n    -\t\tauthor_ident_explicitly_given |= IDENT_NAME_GIVEN;\n    -\tif (getenv(\"GIT_AUTHOR_EMAIL\"))\n    -\t\tauthor_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n     \treturn fmt_ident(getenv(\"GIT_AUTHOR_NAME\"),\n    @@ -470,7 +464,2 @@ int committer_ident_sufficiently_given(void)\n\n    -int author_ident_sufficiently_given(void)\n    -{\n    -\treturn ident_is_sufficient(author_ident_explicitly_given);\n    -}\n    -\n     int git_ident_config(const char *var, const char *value, void *data)\n    @@ -488,3 +477,2 @@ int git_ident_config(const char *var, const char *value, void *data)\n     \t\tcommitter_ident_explicitly_given |= IDENT_NAME_GIVEN;\n    -\t\tauthor_ident_explicitly_given |= IDENT_NAME_GIVEN;\n     \t\tident_config_given |= IDENT_NAME_GIVEN;\n    @@ -499,3 +487,2 @@ int git_ident_config(const char *var, const char *value, void *data)\n     \t\tcommitter_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n    -\t\tauthor_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n     \t\tident_config_given |= IDENT_MAIL_GIVEN;\n\nA more complete \"fix\" is to entirely revert Jeff's d6991ceedc (\"ident:\nkeep separate \"explicit\" flags for author and committer\",\n2012-11-14). As he noted in 2012\n(https://public-inbox.org/git/20121128182534.GA21020@sigill.intra.peff.net/):\n\n    I do not know if anybody will ever care about the corner cases it\n    fixes, so it is really just being defensive for future code.\n\nI also found that the bug in my v6 is easily spotted & fixed. We just\ngrep stderr to see if we emit the \"Your name and email were configured\nautomatically...\" message. My patch v6 introduced a bug where we'd start\nemitting that.\n\nSo it seems to me that the best way forward is to produce a series\nwhere:\n\n 1. We revert Jeff's 2012 patch (or not, Jeff?)\n\n 2. Fix the tests so we test that given a combo of env vars & config\n    create the expected commit objects *and* either emit the advice\n    about having set stuff implicitly, or not.\n\n    These need a lot of improvement, e.g. all our tests pass if I apply\n    this:\n\n        diff --git a/ident.c b/ident.c\n        index 33bcf40644..f68e3c32ea 100644\n        --- a/ident.c\n        +++ b/ident.c\n        @@ -167,6 +167,4 @@ const char *ident_default_email(void)\n                        if (email && email[0]) {\n                                strbuf_addstr(&git_default_email, email);\n        -                       committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n        -                       author_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n                        } else if ((email = query_user_email()) && email[0]) {\n                                strbuf_addstr(&git_default_email, email);\n\n 3. This {author,committer}.{name,email} feature on top of that.\n\nWilliam, is that something you're intererested in carrying forward? I\ncan also help if you want. Sorry your first contribution to git has\nturned into this mess of re-rolls, as often happens we find that when\ntrying to tweak something that the existing behavior doesn't have any\ntests.\n\nI think it's worth spending a bit more time here to prove to ourselves\nthat the changes aren't e.g. spamming users with the ident advice in\ncases where we don't want that, but maybe everyone else is tired of this\nand we should just take your v5 and fix the other stuff later. I'll\nleave that up to you / Junio to decide.\n\n>>>  int git_ident_config(const char *var, const char *value, void *data)\n>>>  {\n>>>  \tif (!strcmp(var, \"user.useconfigonly\")) {\n>>> @@ -480,29 +551,7 @@ int git_ident_config(const char *var, const char *value, void *data)\n>>>  \t\treturn 0;\n>>>  \t}\n>>>\n>>> -\tif (!strcmp(var, \"user.name\")) {\n>>> -\t\tif (!value)\n>>> -\t\t\treturn config_error_nonbool(var);\n>>> -\t\tstrbuf_reset(&git_default_name);\n>>> -\t\tstrbuf_addstr(&git_default_name, value);\n>>> -\t\tcommitter_ident_explicitly_given |= IDENT_NAME_GIVEN;\n>>> -\t\tauthor_ident_explicitly_given |= IDENT_NAME_GIVEN;\n>>> -\t\tident_config_given |= IDENT_NAME_GIVEN;\n>>> -\t\treturn 0;\n>>> -\t}\n>>> -\n>>> -\tif (!strcmp(var, \"user.email\")) {\n>>> -\t\tif (!value)\n>>> -\t\t\treturn config_error_nonbool(var);\n>>> -\t\tstrbuf_reset(&git_default_email);\n>>> -\t\tstrbuf_addstr(&git_default_email, value);\n>>> -\t\tcommitter_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n>>> -\t\tauthor_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n>>> -\t\tident_config_given |= IDENT_MAIL_GIVEN;\n>>> -\t\treturn 0;\n>>> -\t}\n>>> -\n>>> -\treturn 0;\n>>> +\treturn set_ident(var, value);\n>>>  }\n"},{"id":"368619","messageId":"20190206182612.GA10231@sigill.intra.peff.net","threadId":"50396","inReplyTo":"87h8dhl0zh.fsf@evledraar.gmail.com","subject":"Re: [PATCH v6 2/2] config: allow giving separate author and committer idents","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-02-06T18:26:12Z","receivedAt":"2019-02-06T18:26:18Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Feb 06, 2019 at 10:28:34AM +0100, Ævar Arnfjörð Bjarmason wrote:\n\n> I did some further digging. One of the confusing things is that we've\n> been carrying dead code since 2012 to set this\n> author_ident_explicitly_given variable. We can just apply this on top of\n> master:\n> [...]\n>     @@ -434,6 +432,2 @@ const char *git_author_info(int flag)\n>      {\n>     -\tif (getenv(\"GIT_AUTHOR_NAME\"))\n>     -\t\tauthor_ident_explicitly_given |= IDENT_NAME_GIVEN;\n>     -\tif (getenv(\"GIT_AUTHOR_EMAIL\"))\n>     -\t\tauthor_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n>      \treturn fmt_ident(getenv(\"GIT_AUTHOR_NAME\"),\n\nYeah, that would be OK with me. It's conceivable somebody ask \"was the author\nident sufficiently given\", but given that 7 years have passed, it seems\nunlikely (and it's easy to resurrect it in the worst case).\n\nBut...\n\n> A more complete \"fix\" is to entirely revert Jeff's d6991ceedc (\"ident:\n> keep separate \"explicit\" flags for author and committer\",\n> 2012-11-14). As he noted in 2012\n> (https://public-inbox.org/git/20121128182534.GA21020@sigill.intra.peff.net/):\n> \n>     I do not know if anybody will ever care about the corner cases it\n>     fixes, so it is really just being defensive for future code.\n\nI think that reintroduces some oddness. E.g., if I don't have any ident\ninformation set in config or the environment, and I do:\n\n  GIT_AUTHOR_NAME=me GIT_AUTHOR_EMAIL=me@example.com git commit ...\n\nthat shouldn't count as \"committer ident sufficiently given\", and should\nstill give a warning. So we wouldn't want to conflate them in a single\nflag (which is what d6991ceedc fixed). Curiously, though, I'm not sure\nyou can trigger the problem through git-commit. It does call\ncommitter_ident_sufficiently_given(), but it never calls\ngit_author_info(), where we set the flags!\n\nInstead, it does its own parse via determine_author_info(), which does\nnot bother to set the \"explicit\" flag at all. I suspect this could be\nrefactored share more code with git_author_info() (which is what the\nplumbing commit-tree uses). But that's all a side note here.\n\nThere is one other call to check that the committer ident is\nsufficiently given, and that's in sequencer.c, when it prints a picked\ncommit's info. That _might_ be triggerable (it doesn't call\ngit_author_info() in that code path, but do_merge() does, so if the two\nhappen in the same process, you'd not see the \"Committer:\" info line\nwhen you should).\n\nSo the bugs are minor and fairly unlikely. But I do think it's worth\nkeeping the flags separate (even if we don't bother carrying an \"author\"\none), just because it's an easy mistake to make.\n\nAn alternative view is that anybody who calls git_author_info() to\ncreate a commit _should_ be checking author_ident_sufficiently_given(),\nand it's a bug that they're not.\n\nI.e., should we be doing something like this (and probably some other\nspots, too):\n\ndiff --git a/commit.c b/commit.c\nindex a5333c7ac6..c99b311a48 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -1419,8 +1419,11 @@ int commit_tree_extended(const char *msg, size_t msg_len,\n \t}\n \n \t/* Person/date information */\n-\tif (!author)\n+\tif (!author) {\n \t\tauthor = git_author_info(IDENT_STRICT);\n+\t\tif (!author_ident_sufficiently_given())\n+\t\t\twarning(\"your author ident was auto-detected, etc...\");\n+\t}\n \tstrbuf_addf(&buffer, \"author %s\\n\", author);\n \tstrbuf_addf(&buffer, \"committer %s\\n\", git_committer_info(IDENT_STRICT));\n \tif (!encoding_is_utf8)\n\nI dunno. It seems pretty low priority, and nobody has even noticed after\nall these years. So I'm not sure if it's worth spending too much time on\nit.\n\n-Peff\n"},{"id":"368621","messageId":"20190206183408.GA10832@whubbs1.gaikai.biz","threadId":"50396","inReplyTo":"87h8dhl0zh.fsf@evledraar.gmail.com","subject":"Re: [PATCH v6 2/2] config: allow giving separate author and committer idents","fromName":"William Hubbs","fromEmail":"williamh@gentoo.org","sentAt":"2019-02-06T18:34:08Z","receivedAt":"2019-02-06T18:34:14Z","isPatch":true,"sender":{"key":"williamh@gentoo.org","avatar":"https://avatars.githubusercontent.com/u/64355?v=4"},"body":"On Wed, Feb 06, 2019 at 10:28:34AM +0100, Ævar Arnfjörð Bjarmason wrote:\n> \n> William, is that something you're intererested in carrying forward? I\n> can also help if you want. Sorry your first contribution to git has\n> turned into this mess of re-rolls, as often happens we find that when\n> trying to tweak something that the existing behavior doesn't have any\n> tests.\n \n I'm open to it, but since we aren't sure about reverting the patch I\n guess we should wait for Jeff to reply?\n\n> I think it's worth spending a bit more time here to prove to ourselves\n> that the changes aren't e.g. spamming users with the ident advice in\n> cases where we don't want that, but maybe everyone else is tired of this\n> and we should just take your v5 and fix the other stuff later. I'll\n> leave that up to you / Junio to decide.\n\nJunio,\n\nI guess it's up to you, should we take my v5 patch then do the other\nfixes later?\n\nWilliam\n\n"},{"id":"368623","messageId":"20190206184149.GB10832@whubbs1.gaikai.biz","threadId":"50396","inReplyTo":"20190206182612.GA10231@sigill.intra.peff.net","subject":"Re: [PATCH v6 2/2] config: allow giving separate author and committer idents","fromName":"William Hubbs","fromEmail":"williamh@gentoo.org","sentAt":"2019-02-06T18:41:49Z","receivedAt":"2019-02-06T18:41:55Z","isPatch":true,"sender":{"key":"williamh@gentoo.org","avatar":"https://avatars.githubusercontent.com/u/64355?v=4"},"body":"On Wed, Feb 06, 2019 at 01:26:12PM -0500, Jeff King wrote:\n> On Wed, Feb 06, 2019 at 10:28:34AM +0100, Ævar Arnfjörð Bjarmason wrote:\n> \n> > I did some further digging. One of the confusing things is that we've\n> > been carrying dead code since 2012 to set this\n> > author_ident_explicitly_given variable. We can just apply this on top of\n> > master:\n> > [...]\n> >     @@ -434,6 +432,2 @@ const char *git_author_info(int flag)\n> >      {\n> >     -\tif (getenv(\"GIT_AUTHOR_NAME\"))\n> >     -\t\tauthor_ident_explicitly_given |= IDENT_NAME_GIVEN;\n> >     -\tif (getenv(\"GIT_AUTHOR_EMAIL\"))\n> >     -\t\tauthor_ident_explicitly_given |= IDENT_MAIL_GIVEN;\n> >      \treturn fmt_ident(getenv(\"GIT_AUTHOR_NAME\"),\n> \n> Yeah, that would be OK with me. It's conceivable somebody ask \"was the author\n> ident sufficiently given\", but given that 7 years have passed, it seems\n> unlikely (and it's easy to resurrect it in the worst case).\n> \n> But...\n> \n> > A more complete \"fix\" is to entirely revert Jeff's d6991ceedc (\"ident:\n> > keep separate \"explicit\" flags for author and committer\",\n> > 2012-11-14). As he noted in 2012\n> > (https://public-inbox.org/git/20121128182534.GA21020@sigill.intra.peff.net/):\n> > \n> >     I do not know if anybody will ever care about the corner cases it\n> >     fixes, so it is really just being defensive for future code.\n> \n> I think that reintroduces some oddness. E.g., if I don't have any ident\n> information set in config or the environment, and I do:\n> \n>   GIT_AUTHOR_NAME=me GIT_AUTHOR_EMAIL=me@example.com git commit ...\n> \n> that shouldn't count as \"committer ident sufficiently given\", and should\n> still give a warning. So we wouldn't want to conflate them in a single\n> flag (which is what d6991ceedc fixed). Curiously, though, I'm not sure\n> you can trigger the problem through git-commit. It does call\n> committer_ident_sufficiently_given(), but it never calls\n> git_author_info(), where we set the flags!\n> \n> Instead, it does its own parse via determine_author_info(), which does\n> not bother to set the \"explicit\" flag at all. I suspect this could be\n> refactored share more code with git_author_info() (which is what the\n> plumbing commit-tree uses). But that's all a side note here.\n> \n> There is one other call to check that the committer ident is\n> sufficiently given, and that's in sequencer.c, when it prints a picked\n> commit's info. That _might_ be triggerable (it doesn't call\n> git_author_info() in that code path, but do_merge() does, so if the two\n> happen in the same process, you'd not see the \"Committer:\" info line\n> when you should).\n> \n> So the bugs are minor and fairly unlikely. But I do think it's worth\n> keeping the flags separate (even if we don't bother carrying an \"author\"\n> one), just because it's an easy mistake to make.\n> \n> An alternative view is that anybody who calls git_author_info() to\n> create a commit _should_ be checking author_ident_sufficiently_given(),\n> and it's a bug that they're not.\n> \n> I.e., should we be doing something like this (and probably some other\n> spots, too):\n> \n> diff --git a/commit.c b/commit.c\n> index a5333c7ac6..c99b311a48 100644\n> --- a/commit.c\n> +++ b/commit.c\n> @@ -1419,8 +1419,11 @@ int commit_tree_extended(const char *msg, size_t msg_len,\n>  \t}\n>  \n>  \t/* Person/date information */\n> -\tif (!author)\n> +\tif (!author) {\n>  \t\tauthor = git_author_info(IDENT_STRICT);\n> +\t\tif (!author_ident_sufficiently_given())\n> +\t\t\twarning(\"your author ident was auto-detected, etc...\");\n> +\t}\n>  \tstrbuf_addf(&buffer, \"author %s\\n\", author);\n>  \tstrbuf_addf(&buffer, \"committer %s\\n\", git_committer_info(IDENT_STRICT));\n>  \tif (!encoding_is_utf8)\n> \n> I dunno. It seems pretty low priority, and nobody has even noticed after\n> all these years. So I'm not sure if it's worth spending too much time on\n> it.\n\nGiven this info (which came in while I was writing my last email), I\nwould rather see my v5 patch get in then we fix everything else later.\n\nJunio, what do you think?\n\nThanks,\n\nWilliam\n\n"},{"id":"368652","messageId":"xmqqo97opmg8.fsf@gitster-ct.c.googlers.com","threadId":"50396","inReplyTo":"20190206182612.GA10231@sigill.intra.peff.net","subject":"Re: [PATCH v6 2/2] config: allow giving separate author and committer idents","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-06T22:43:35Z","receivedAt":"2019-02-06T22:43:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> An alternative view is that anybody who calls git_author_info() to\n> create a commit _should_ be checking author_ident_sufficiently_given(),\n> and it's a bug that they're not.\n>\n> I.e., should we be doing something like this (and probably some other\n> spots, too):\n>\n> diff --git a/commit.c b/commit.c\n> index a5333c7ac6..c99b311a48 100644\n> --- a/commit.c\n> +++ b/commit.c\n> @@ -1419,8 +1419,11 @@ int commit_tree_extended(const char *msg, size_t msg_len,\n>  \t}\n>  \n>  \t/* Person/date information */\n> -\tif (!author)\n> +\tif (!author) {\n>  \t\tauthor = git_author_info(IDENT_STRICT);\n> +\t\tif (!author_ident_sufficiently_given())\n> +\t\t\twarning(\"your author ident was auto-detected, etc...\");\n> +\t}\n>  \tstrbuf_addf(&buffer, \"author %s\\n\", author);\n>  \tstrbuf_addf(&buffer, \"committer %s\\n\", git_committer_info(IDENT_STRICT));\n>  \tif (!encoding_is_utf8)\n>\n> I dunno. It seems pretty low priority, and nobody has even noticed after\n> all these years. So I'm not sure if it's worth spending too much time on\n> it.\n\nThat's quite tempting.  But I agree that this is something we can\nleave for a later clean-up, as the topic to add the config variables\nis pretty much orthogonal to it, and we are not making things that\nmuch worse than the status quo.\n\nThanks.\n"},{"id":"369238","messageId":"20190213164322.GA3625@whubbs1.dev.av1.gaikai.org","threadId":"50396","inReplyTo":"xmqqwomdqzik.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v6 2/2] config: allow giving separate author and committer idents","fromName":"William Hubbs","fromEmail":"williamh@gentoo.org","sentAt":"2019-02-13T16:43:22Z","receivedAt":"2019-02-13T16:43:27Z","isPatch":true,"sender":{"key":"williamh@gentoo.org","avatar":"https://avatars.githubusercontent.com/u/64355?v=4"},"body":"Hi Junio,\n\nI am writing back onn this thread because I'm not quite sure of the\nstatus. v5 of the patch seemed ok, but there were some changes discussed\nthat would have created a v6. The v6 changes though were never really\nclear. I'm not sure whether I am supposed to be doing something more or\nwhether I'm waiting for you. ;-)\n\nCan you write back and let me know?\n\nThanks,\n\nWilliam\n\n"},{"id":"369264","messageId":"xmqqwom39uwz.fsf@gitster-ct.c.googlers.com","threadId":"50396","inReplyTo":"20190213164322.GA3625@whubbs1.dev.av1.gaikai.org","subject":"Re: [PATCH v6 2/2] config: allow giving separate author and committer idents","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-13T22:37:48Z","receivedAt":"2019-02-13T22:37:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"William Hubbs <williamh@gentoo.org> writes:\n\n> I am writing back onn this thread because I'm not quite sure of the\n> status. v5 of the patch seemed ok, but there were some changes discussed\n> that would have created a v6. The v6 changes though were never really\n> clear. I'm not sure whether I am supposed to be doing something more or\n> whether I'm waiting for you. ;-)\n>\n> Can you write back and let me know?\n\nIn general, unless I ask you to wait, a contributor would almost\nnever be waiting for me.\n\nI think Ævar's v6 was not up to par, but I thought that v5 from you\n(which is in 'next') was good enough to cook in 'next'.  The topic\nwill not be moving out of 'next' until the final 2.21 is released\nanyway, so if anything, I'd say the ball is in his court to update\nhis version after the release, when your v5 may have a chance to be\nkicked out of 'next' and replaced _if_ there is a better version by\nthen.\n\n"},{"id":"369320","messageId":"20190214181745.GA15584@whubbs1.dev.av1.gaikai.org","threadId":"50396","inReplyTo":"xmqqwom39uwz.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v6 2/2] config: allow giving separate author and committer idents","fromName":"William Hubbs","fromEmail":"williamh@gentoo.org","sentAt":"2019-02-14T18:17:45Z","receivedAt":"2019-02-14T18:17:51Z","isPatch":true,"sender":{"key":"williamh@gentoo.org","avatar":"https://avatars.githubusercontent.com/u/64355?v=4"},"body":"On Wed, Feb 13, 2019 at 02:37:48PM -0800, Junio C Hamano wrote:\n> William Hubbs <williamh@gentoo.org> writes:\n> \n> > I am writing back onn this thread because I'm not quite sure of the\n> > status. v5 of the patch seemed ok, but there were some changes discussed\n> > that would have created a v6. The v6 changes though were never really\n> > clear. I'm not sure whether I am supposed to be doing something more or\n> > whether I'm waiting for you. ;-)\n> >\n> > Can you write back and let me know?\n> \n> In general, unless I ask you to wait, a contributor would almost\n> never be waiting for me.\n> \n> I think Ævar's v6 was not up to par, but I thought that v5 from you\n> (which is in 'next') was good enough to cook in 'next'.  The topic\n> will not be moving out of 'next' until the final 2.21 is released\n> anyway, so if anything, I'd say the ball is in his court to update\n> his version after the release, when your v5 may have a chance to be\n> kicked out of 'next' and replaced _if_ there is a better version by\n> then.\n\nThanks much for the update. I didn't realize that v5 was in next.\n\nWilliam\n\n"},{"id":"373876","messageId":"15f17152-fcec-ee9a-acd3-f36cf2c98030@gmail.com","threadId":"50396","inReplyTo":"20190205195212.25550-3-avarab@gmail.com","subject":"Re: [PATCH v6 2/2] config: allow giving separate author and committer idents","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2019-04-15T14:24:04Z","receivedAt":"2019-04-15T14:24:09Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 2/5/2019 2:52 PM, Ævar Arnfjörð Bjarmason wrote:\n> From: William Hubbs <williamh@gentoo.org>\n> -const char *fmt_name(const char *name, const char *email)\n> +const char *fmt_name(enum want_ident whose_ident)\n>  {\n> -\treturn fmt_ident(name, email, NULL, IDENT_STRICT | IDENT_NO_DATE);\n> +\tchar *name = NULL;\n> +\tchar *email = NULL;\n> +\n> +\tswitch (whose_ident) {\n> +\tcase WANT_BLANK_IDENT:\n> +\t\tbreak;\n> +\tcase WANT_AUTHOR_IDENT:\n> +\t\tname = getenv(\"GIT_AUTHOR_NAME\");\n> +\t\temail = getenv(\"GIT_AUTHOR_EMAIL\");\n> +\t\tbreak;\n> +\tcase WANT_COMMITTER_IDENT:\n> +\t\tname = getenv(\"GIT_COMMITTER_NAME\");\n> +\t\temail = getenv(\"GIT_COMMITTER_EMAIL\");\n> +\t\tbreak;\n> +\t}\n> +\treturn fmt_ident(name, email, whose_ident, NULL,\n> +\t\t\tIDENT_STRICT | IDENT_NO_DATE);\n>  }\n\nWilliam and Ævar,\n\nThe \"WANT_AUTHOR_IDENT\" block of this switch statement does not\nappear to be hit by any tests, despite the tests included in this\npatch. My guess is that it is ignored because we have the following\ncode in builtin/commit.c:\n\nstatic void determine_author_info(struct strbuf *author_ident)\n{\n\tchar *name, *email, *date;\n\tstruct ident_split author;\n\n\tname = xstrdup_or_null(getenv(\"GIT_AUTHOR_NAME\"));\n\temail = xstrdup_or_null(getenv(\"GIT_AUTHOR_EMAIL\"));\n\tdate = xstrdup_or_null(getenv(\"GIT_AUTHOR_DATE\"));\n...\n\n\nThis is likely overriding the need to use fmt_name. Should we\nde-duplicate this use of the environment variable by using your\nnew method at this spot in builtin/commit.c?\n\nThanks,\n-Stolee\n"}]}