{"thread":{"id":"50355","subject":"[PATCH v3 0/1] config: allow giving different author and committer idents","startedAt":"2019-01-29T23:08:22Z","lastAt":"2019-02-04T18:57:09Z","messageCount":5,"participants":["William Hubbs","Junio C Hamano","Johannes Schindelin"],"isPatch":true,"patchVersion":3,"patchTotal":1},"messages":[{"id":"368066","messageId":"20190129230806.5295-1-williamh@gentoo.org","threadId":"50355","inReplyTo":null,"subject":"[PATCH v3 0/1] config: allow giving different author and committer idents","fromName":"William Hubbs","fromEmail":"williamh@gentoo.org","sentAt":"2019-01-29T23:08:05Z","receivedAt":"2019-01-29T23:08:22Z","isPatch":true,"sender":{"key":"williamh@gentoo.org","avatar":"https://avatars.githubusercontent.com/u/64355?v=4"},"body":"All,\n\nthis version of the patch adds more test cases, combines the tests into\nthe main patch, creates the static set_ident function, updates the\ndocumentation and fixes some formatting.\n\nIt also applies against master.\n\nPlease review.\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                      |  6 +++\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, 200 insertions(+), 23 deletions(-)\n\n-- \n2.19.2\n\n"},{"id":"368067","messageId":"20190129230806.5295-2-williamh@gentoo.org","threadId":"50355","inReplyTo":"20190129230806.5295-1-williamh@gentoo.org","subject":"[PATCH v3 1/1] config: allow giving separate author and committer idents","fromName":"William Hubbs","fromEmail":"williamh@gentoo.org","sentAt":"2019-01-29T23:08:06Z","receivedAt":"2019-01-29T23:08:28Z","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                      |  6 +++\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, 200 insertions(+), 23 deletions(-)\n\ndiff --git a/Documentation/config/user.txt b/Documentation/config/user.txt\nindex b5b2ba1199..8b31b5fa31 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` and\n+\t`GIT_COMMITTER_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..375be1f68b 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..4bd5920dea 100644\n--- a/config.c\n+++ b/config.c\n@@ -1484,6 +1484,12 @@ int git_default_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \n+\tif (starts_with(var, \"author.\"))\n+\t\treturn git_ident_config(var, value, cb);\n+\n+\tif (starts_with(var, \"committer.\"))\n+\t\treturn git_ident_config(var, value, cb);\n+\n \t/* Add other config variables here and to Documentation/config.txt. */\n \treturn 0;\n }\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":"368072","messageId":"xmqqfttb599s.fsf@gitster-ct.c.googlers.com","threadId":"50355","inReplyTo":"20190129230806.5295-2-williamh@gentoo.org","subject":"Re: [PATCH v3 1/1] config: allow giving separate author and committer idents","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-29T23:33:35Z","receivedAt":"2019-01-29T23:33:41Z","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> diff --git a/cache.h b/cache.h\n> index 009e8b3b15..375be1f68b 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\nI do not recall we crossed the bridge to allow trailing comma here\nat the end of enum definition.\n\n> +};\n\n\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\nNice interface.\n\n> diff --git a/config.c b/config.c\n> index ff521eb27a..4bd5920dea 100644\n> --- a/config.c\n> +++ b/config.c\n> @@ -1484,6 +1484,12 @@ int git_default_config(const char *var, const char *value, void *cb)\n>  \t\treturn 0;\n>  \t}\n>  \n> +\tif (starts_with(var, \"author.\"))\n> +\t\treturn git_ident_config(var, value, cb);\n> +\n> +\tif (starts_with(var, \"committer.\"))\n> +\t\treturn git_ident_config(var, value, cb);\n> +\n\nI'd rather see this done close to where \"user.\" is already handled,\nperhaps like\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                        return git_ident_config(...);\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\nSo, when we see \"committer.phone\", git_default_config() would call\ngit_ident_config() which in turn would call this, and the unknown\nvariable is silently ignored, which is good.\n\n> diff --git a/log-tree.c b/log-tree.c\n> index 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\nVery nice.\n"},{"id":"368455","messageId":"nycvar.QRO.7.76.6.1902041314160.41@tvgsbejvaqbjf.bet","threadId":"50355","inReplyTo":"xmqqfttb599s.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v3 1/1] config: allow giving separate author and committer idents","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2019-02-04T12:17:35Z","receivedAt":"2019-02-04T12:18:04Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 29 Jan 2019, Junio C Hamano wrote:\n\n> William Hubbs <williamh@gentoo.org> writes:\n> \n> > diff --git a/cache.h b/cache.h\n> > index 009e8b3b15..375be1f68b 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> I do not recall we crossed the bridge to allow trailing comma here\n> at the end of enum definition.\n\nIn advice.c:\n\n\tenum color_advice {\n\t\tADVICE_COLOR_RESET = 0,\n\t\tADVICE_COLOR_HINT = 1,\n\t};\n\nIn builtin/pack-objects.c:\n\n\tenum missing_action {\n\t\tMA_ERROR = 0,      /* fail if any missing objects are encountered */\n\t\tMA_ALLOW_ANY,      /* silently allow ALL missing objects */\n\t\tMA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */\n\t};\n\nIn builtin/rev-list.c:\n\n\tenum missing_action {\n\t\tMA_ERROR = 0,    /* fail if any missing objects are encountered */\n\t\tMA_ALLOW_ANY,    /* silently allow ALL missing objects */\n\t\tMA_PRINT,        /* print ALL missing objects in special section */\n\t\tMA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */\n\t};\n\n... and I will stop here. You are correct that the majority of our enums\ndoes not let its last item end in a comma. But we did cross that bridge.\n\nCiao,\nDscho\n\n"},{"id":"368472","messageId":"xmqqbm3rv0u7.fsf@gitster-ct.c.googlers.com","threadId":"50355","inReplyTo":"nycvar.QRO.7.76.6.1902041314160.41@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v3 1/1] config: allow giving separate author and committer idents","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-04T18:57:04Z","receivedAt":"2019-02-04T18:57:09Z","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>> I do not recall we crossed the bridge to allow trailing comma here\n>> at the end of enum definition.\n>\n> In advice.c:\n>\n> \tenum color_advice {\n> \t\tADVICE_COLOR_RESET = 0,\n> \t\tADVICE_COLOR_HINT = 1,\n> \t};\n>\n> In builtin/pack-objects.c:\n>\n> \tenum missing_action {\n> \t\tMA_ERROR = 0,      /* fail if any missing objects are encountered */\n> \t\tMA_ALLOW_ANY,      /* silently allow ALL missing objects */\n> \t\tMA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */\n> \t};\n>\n> In builtin/rev-list.c:\n>\n> \tenum missing_action {\n> \t\tMA_ERROR = 0,    /* fail if any missing objects are encountered */\n> \t\tMA_ALLOW_ANY,    /* silently allow ALL missing objects */\n> \t\tMA_PRINT,        /* print ALL missing objects in special section */\n> \t\tMA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */\n> \t};\n>\n> ... and I will stop here. You are correct that the majority of our enums\n> does not let its last item end in a comma. But we did cross that bridge.\n\nGood.  Thanks for eyeballing.\n\nI do not think any of these can be compiled out on a platform with a\npicker compiler, and the one in rev-list.c is from late 2017, so it\nprobably be a safe assumption that nobody would mind the trailing\ncomma.\n\n"}]}