Re: Make author and committer available to pre-commit hook
On Mon, Jul 5, 2010 at 13:46, Jeff King <peff@peff.net> wrote:
Show 15 quoted lines
> 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 <gisle@aas.no>
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" <<EOT
+#!/bin/sh
+case "\$GIT_AUTHOR_NAME" in Superman) exit 0;; esac
+echo "Only patches from Superman is accepted now"
+exit 1
+EOT
+cat "$HOOK"
+chmod +x "$HOOK"
+
+test_expect_success 'with failing hook' '
+
+ echo "another" >> 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 <root@example.com>"
+
+'
+
test_done
--
1.6.6.rc1.31.g1a56b