git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Make author and committer available to pre-commit hook

From
Gisle Aas <gisle@aas.no>
Date
Jul 5, 2010, 18:04 UTC
Message-ID
<AANLkTinlGBt3nBa7Ge5ytjisTeDu3As4wCkF8M1iz5JV@mail.gmail.com>
In-Reply-To
<20100705114619.GA21146@sigill.intra.peff.net>
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
Previous: Jeff KingNext: Ævar Arnfjörð Bjarmason
Message 3 of 8 in “Make author and committer available to pre-commit hook”
  1. Gisle AasJul 5, 2010
  2. Jeff KingJul 5, 2010
  3. Gisle AasJul 5, 2010
  4. Ævar Arnfjörð BjarmasonJul 5, 2010
  5. Junio C HamanoJul 6, 2010
  6. Jeff KingJul 6, 2010
  7. Gisle AasJul 6, 2010
  8. Junio C HamanoJul 6, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.