From: Gisle Aas Date: Mon, 05 Jul 2010 18:04:11 GMT Subject: Re: Make author and committer available to pre-commit hook Message-ID: In-Reply-To: <20100705114619.GA21146@sigill.intra.peff.net> On Mon, Jul 5, 2010 at 13:46, Jeff King wrote: > On Mon, Jul 05, 2010 at 01:30:46PM +0200, Gisle Aas wrote: > >> I would like to implement a pre-commit hook that validates the >> --author set for the commit.  Our use case is a shared repository of >> configuration info where different persons all commit as root; but we >> want to make sure they override the --author to something sensible. >> >> What would be the preferred mechanism to pass on this information?  It >> could for instance be arguments to the hook script or via environment >> variables. > > It would make sense to me for it to be passed in through the environment > using GIT_{AUTHOR,COMMITTER}_{NAME,EMAIL}. You could even pass > GIT_AUTHOR_DATE to detect if somebody is using "git commit -c" to get > the date from a previous commit. I agree that would be a more natural interface. Attached is a patch that sets these environment variables before the hooks are invoked. The patch also updates the documentation and adds some tests. Regards, Gisle From c352cfdda7dbd3f9185d4c0b1b4472c69cd64399 Mon Sep 17 00:00:00 2001 From: Gisle Aas Date: Mon, 5 Jul 2010 17:45:30 +0200 Subject: [PATCH] Set ident environment variables for the commit hooks to observe The GIT_{AUTHOR,COMMITTER}_{NAME,EMAIL} environment variables are set to reflect the values about to be committed. --- Documentation/githooks.txt | 4 ++- builtin/commit.c | 9 ++++--- cache.h | 2 + ident.c | 46 ++++++++++++++++++++++++++++++------------- t/t7503-pre-commit-hook.sh | 26 ++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 19 deletions(-) diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt index 7183aa9..a330a67 100644 --- a/Documentation/githooks.txt +++ b/Documentation/githooks.txt @@ -84,7 +84,9 @@ such a line is found. All the 'git commit' hooks are invoked with the environment variable `GIT_EDITOR=:` if the command will not bring up an editor -to modify the commit message. +to modify the commit message. The 'GIT_AUTHOR_NAME', 'GIT_AUTHOR_EMAIL', +'GIT_COMMITTER_NAME', 'GIT_COMMITTER_EMAIL' environment variables +will also be set. prepare-commit-msg ~~~~~~~~~~~~~~~~~~ diff --git a/builtin/commit.c b/builtin/commit.c index c101f00..06e9342 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -557,6 +557,11 @@ static int prepare_to_commit(const char *index_file, const char *prefix, const char *hook_arg2 = NULL; int ident_shown = 0; + determine_author_info(); + git_committer_info(0); /* This checks if committer ident is explicitly given */ + git_setenv_ident(author_name, author_email, + getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL")); + if (!no_verify && run_hook(index_file, "pre-commit", NULL)) return 0; @@ -632,10 +637,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix, strbuf_release(&sb); - determine_author_info(); - - /* This checks if committer ident is explicitly given */ - git_committer_info(0); if (use_editor && include_status) { char *author_ident; const char *committer_ident; diff --git a/cache.h b/cache.h index c9fa3df..2e70ff7 100644 --- a/cache.h +++ b/cache.h @@ -822,6 +822,8 @@ enum date_mode parse_date_format(const char *format); #define IDENT_NO_DATE 4 extern const char *git_author_info(int); extern const char *git_committer_info(int); +extern void git_setenv_ident(const char *author_name, const char *author_email, + const char *committer_name, const char *committer_email); extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int); extern const char *fmt_name(const char *name, const char *email); extern const char *git_editor(void); diff --git a/ident.c b/ident.c index 9e24388..190e4a0 100644 --- a/ident.c +++ b/ident.c @@ -182,39 +182,45 @@ static const char *env_hint = "Omit --global to set the identity only in this repository.\n" "\n"; -const char *fmt_ident(const char *name, const char *email, - const char *date_str, int flag) +static void get_ident(const char **name, const char **email, int flag) { - static char buffer[1000]; - char date[50]; - int i; int error_on_no_name = (flag & IDENT_ERROR_ON_NO_NAME); int warn_on_no_name = (flag & IDENT_WARN_ON_NO_NAME); - int name_addr_only = (flag & IDENT_NO_DATE); setup_ident(); - if (!name) - name = git_default_name; - if (!email) - email = git_default_email; + if (!*name) + *name = git_default_name; + if (!*email) + *email = git_default_email; - if (!*name) { + if (!**name) { struct passwd *pw; if ((warn_on_no_name || error_on_no_name) && - name == git_default_name && env_hint) { + *name == git_default_name && env_hint) { fputs(env_hint, stderr); env_hint = NULL; /* warn only once */ } if (error_on_no_name) - die("empty ident %s <%s> not allowed", name, email); + die("empty ident %s <%s> not allowed", *name, *email); pw = getpwuid(getuid()); if (!pw) die("You don't exist. Go away!"); strlcpy(git_default_name, pw->pw_name, sizeof(git_default_name)); - name = git_default_name; + *name = git_default_name; } +} + +const char *fmt_ident(const char *name, const char *email, + const char *date_str, int flag) +{ + static char buffer[1000]; + char date[50]; + int i; + int name_addr_only = (flag & IDENT_NO_DATE); + + get_ident(&name, &email, flag); strcpy(date, git_default_date); if (!name_addr_only && date_str) @@ -240,6 +246,18 @@ const char *fmt_name(const char *name, const char *email) return fmt_ident(name, email, NULL, IDENT_ERROR_ON_NO_NAME | IDENT_NO_DATE); } +void git_setenv_ident(const char *author_name, const char *author_email, + const char *committer_name, const char *committer_email) +{ + get_ident(&author_name, &author_email, IDENT_ERROR_ON_NO_NAME); + setenv("GIT_AUTHOR_NAME", author_name, 1); + setenv("GIT_AUTHOR_EMAIL", author_email, 1); + + get_ident(&committer_name, &committer_email, IDENT_ERROR_ON_NO_NAME); + setenv("GIT_COMMITTER_NAME", committer_name, 1); + setenv("GIT_COMMITTER_EMAIL", committer_email, 1); +} + const char *git_author_info(int flag) { return fmt_ident(getenv("GIT_AUTHOR_NAME"), diff --git a/t/t7503-pre-commit-hook.sh b/t/t7503-pre-commit-hook.sh index 8528f64..21ac57d 100755 --- a/t/t7503-pre-commit-hook.sh +++ b/t/t7503-pre-commit-hook.sh @@ -85,4 +85,30 @@ test_expect_success POSIXPERM '--no-verify with non-executable hook' ' ' +# a hook that test author +cat > "$HOOK" <> file && + git add file && + test_must_fail git commit -m "another" + +' + +test_expect_success 'with non-failing hook' ' + + echo "another" >> file && + git add file && + git commit -m "another" --author "Superman " + +' + test_done -- 1.6.6.rc1.31.g1a56b