git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] [RFC] Make git-update-ref invoke the update and post-update hooks
@ 2006-10-08  0:08 Petr Baudis
  2006-10-08  5:00 ` Junio C Hamano
  0 siblings, 1 reply; 7+ messages in thread
From: Petr Baudis @ 2006-10-08  0:08 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Someone raised a concern that the update and post-update hooks are not
invoked at fetch time in the similar way as they are invoked at push
time, and the idea sort of makes sense. But this patch goes further - it
makes Git invoke those hooks each time a ref is updated in a repository
using the git-update-ref command, which I believe makes a lot of sense as
well - the behaviour is consistent with the current pushing behaviour
and you suddenly finally get a hook where you can properly notify even
about fast-forwards etc.

Signed-off-by: Petr Baudis <pasky@suse.cz>
---

 Documentation/git-update-ref.txt |    3 ++
 Documentation/hooks.txt          |   12 ++++--
 Makefile                         |    2 +
 builtin-update-ref.c             |   12 ++++++
 hooks.c                          |   68 ++++++++++++++++++++++++++++++++++++
 hooks.h                          |   15 ++++++++
 receive-pack.c                   |   71 +-------------------------------------
 7 files changed, 106 insertions(+), 77 deletions(-)

diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt
index 71bcb79..bd20d05 100644
--- a/Documentation/git-update-ref.txt
+++ b/Documentation/git-update-ref.txt
@@ -51,6 +51,9 @@ for reading but not for writing (so we'l
 ref symlink to some other tree, if you have copied a whole
 archive by creating a symlink tree).
 
+Just before updating the reference, the update hook is invoked.
+After updating the reference, the post-update hook is invoked.
+
 With `-d` flag, it deletes the named <ref> after verifying it
 still contains <oldvalue>.
 
diff --git a/Documentation/hooks.txt b/Documentation/hooks.txt
index 517f49b..53fa270 100644
--- a/Documentation/hooks.txt
+++ b/Documentation/hooks.txt
@@ -99,8 +99,9 @@ update
 This hook is invoked by `git-receive-pack` on the remote repository,
 which happens when a `git push` is done on a local repository.
 Just before updating the ref on the remote repository, the update hook
-is invoked.  Its exit status determines the success or failure of
-the ref update.
+is invoked.  It is also invoked on the local repository anytime a ref
+value is updated (that includes mainly fetches, merges, commits).
+Its exit status determines the success or failure of the ref update.
 
 The hook executes once for each ref to be updated, and takes
 three parameters:
@@ -135,9 +136,10 @@ post-update
 -----------
 
 This hook is invoked by `git-receive-pack` on the remote repository,
-which happens when a `git push` is done on a local repository.
-It executes on the remote repository once after all the refs have
-been updated.
+which happens when a `git push` is done on a local repository
+It is also invoked on the local repository anytime a ref value is
+updated (that includes mainly fetches, merges, commits).  It executes
+on the repository once after all the refs have been updated.
 
 It takes a variable number of parameters, each of which is the
 name of ref that was actually updated.
diff --git a/Makefile b/Makefile
index 2962c2e..8e58585 100644
--- a/Makefile
+++ b/Makefile
@@ -263,7 +263,7 @@ LIB_OBJS = \
 	fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
 	write_or_die.o trace.o list-objects.o grep.o \
 	alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
-	color.o wt-status.o archive-zip.o archive-tar.o
+	color.o wt-status.o archive-zip.o archive-tar.o hooks.o
 
 BUILTIN_OBJS = \
 	builtin-add.o \
diff --git a/builtin-update-ref.c b/builtin-update-ref.c
index b34e598..546cbb1 100644
--- a/builtin-update-ref.c
+++ b/builtin-update-ref.c
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "refs.h"
 #include "builtin.h"
+#include "hooks.h"
 
 static const char git_update_ref_usage[] =
 "git-update-ref [-m <reason>] (-d <refname> <value> | <refname> <value> [<oldval>])";
@@ -11,6 +12,7 @@ int cmd_update_ref(int argc, const char 
 	struct ref_lock *lock;
 	unsigned char sha1[20], oldsha1[20];
 	int i, delete;
+	struct command *cmd;
 
 	delete = 0;
 	setup_ident();
@@ -63,9 +65,17 @@ int cmd_update_ref(int argc, const char 
 	lock = lock_any_ref_for_update(refname, oldval ? oldsha1 : NULL);
 	if (!lock)
 		return 1;
+	if (run_update_hook(refname, oldval, value)) {
+		unlock_ref(lock);
+		return 1;
+	}
 	if (write_ref_sha1(lock, sha1, msg) < 0)
 		return 1;
-
 	/* write_ref_sha1 always unlocks the ref, no need to do it explicitly */
+
+	cmd = xmalloc(sizeof(struct command) + strlen(refname) + 1);
+	strcpy(cmd->ref_name, refname);
+	run_update_post_hook(cmd);
+
 	return 0;
 }
diff --git a/hooks.c b/hooks.c
new file mode 100644
index 0000000..efade2b
--- /dev/null
+++ b/hooks.c
@@ -0,0 +1,68 @@
+#include "cache.h"
+#include "run-command.h"
+#include "hooks.h"
+
+
+static char update_hook[] = "hooks/update";
+
+int run_update_hook(const char *refname, const char *old_hex, const char *new_hex)
+{
+	char *update_hook_p = git_path("%s", update_hook);
+	int code;
+
+	if (access(update_hook_p, X_OK) < 0)
+		return 0;
+	code = run_command(update_hook_p, refname, old_hex, new_hex, NULL);
+	switch (code) {
+	case 0:
+		return 0;
+	case -ERR_RUN_COMMAND_FORK:
+		return error("hook fork failed");
+	case -ERR_RUN_COMMAND_EXEC:
+		return error("hook execute failed");
+	case -ERR_RUN_COMMAND_WAITPID:
+		return error("waitpid failed");
+	case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
+		return error("waitpid is confused");
+	case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
+		return error("%s died of signal", update_hook);
+	case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
+		return error("%s died strangely", update_hook);
+	default:
+		error("%s exited with error code %d", update_hook, -code);
+		return -code;
+	}
+}
+
+
+static char update_post_hook[] = "hooks/post-update";
+
+void run_update_post_hook(struct command *cmd)
+{
+	char *update_post_hook_p = git_path("%s", update_post_hook);
+	struct command *cmd_p;
+	int argc;
+	const char **argv;
+
+	if (access(update_post_hook_p, X_OK) < 0)
+		return;
+	for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
+		if (cmd_p->error_string)
+			continue;
+		argc++;
+	}
+	argv = xmalloc(sizeof(*argv) * (1 + argc));
+	argv[0] = update_post_hook_p;
+
+	for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
+		char *p;
+		if (cmd_p->error_string)
+			continue;
+		p = xmalloc(strlen(cmd_p->ref_name) + 1);
+		strcpy(p, cmd_p->ref_name);
+		argv[argc] = p;
+		argc++;
+	}
+	argv[argc] = NULL;
+	run_command_v_opt(argc, argv, RUN_COMMAND_NO_STDIO);
+}
diff --git a/hooks.h b/hooks.h
new file mode 100644
index 0000000..8ddeca3
--- /dev/null
+++ b/hooks.h
@@ -0,0 +1,15 @@
+#ifndef HOOKS_H
+#define HOOKS_H
+
+int run_update_hook(const char *refname, const char *old_hex, const char *new_hex);
+
+struct command {
+	struct command *next;
+	const char *error_string;
+	unsigned char old_sha1[20];
+	unsigned char new_sha1[20];
+	char ref_name[FLEX_ARRAY]; /* more */
+};
+void run_update_post_hook(struct command *cmd);
+
+#endif
diff --git a/receive-pack.c b/receive-pack.c
index 1fcf3a9..9d5ece6 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -4,6 +4,7 @@ #include "pkt-line.h"
 #include "run-command.h"
 #include "commit.h"
 #include "object.h"
+#include "hooks.h"
 
 static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
 
@@ -33,47 +34,8 @@ static void write_head_info(void)
 
 }
 
-struct command {
-	struct command *next;
-	const char *error_string;
-	unsigned char old_sha1[20];
-	unsigned char new_sha1[20];
-	char ref_name[FLEX_ARRAY]; /* more */
-};
-
 static struct command *commands;
 
-static char update_hook[] = "hooks/update";
-
-static int run_update_hook(const char *refname,
-			   char *old_hex, char *new_hex)
-{
-	int code;
-
-	if (access(update_hook, X_OK) < 0)
-		return 0;
-	code = run_command(update_hook, refname, old_hex, new_hex, NULL);
-	switch (code) {
-	case 0:
-		return 0;
-	case -ERR_RUN_COMMAND_FORK:
-		return error("hook fork failed");
-	case -ERR_RUN_COMMAND_EXEC:
-		return error("hook execute failed");
-	case -ERR_RUN_COMMAND_WAITPID:
-		return error("waitpid failed");
-	case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
-		return error("waitpid is confused");
-	case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
-		return error("%s died of signal", update_hook);
-	case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
-		return error("%s died strangely", update_hook);
-	default:
-		error("%s exited with error code %d", update_hook, -code);
-		return -code;
-	}
-}
-
 static int update(struct command *cmd)
 {
 	const char *name = cmd->ref_name;
@@ -127,37 +89,6 @@ static int update(struct command *cmd)
 	return 0;
 }
 
-static char update_post_hook[] = "hooks/post-update";
-
-static void run_update_post_hook(struct command *cmd)
-{
-	struct command *cmd_p;
-	int argc;
-	const char **argv;
-
-	if (access(update_post_hook, X_OK) < 0)
-		return;
-	for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
-		if (cmd_p->error_string)
-			continue;
-		argc++;
-	}
-	argv = xmalloc(sizeof(*argv) * (1 + argc));
-	argv[0] = update_post_hook;
-
-	for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
-		char *p;
-		if (cmd_p->error_string)
-			continue;
-		p = xmalloc(strlen(cmd_p->ref_name) + 1);
-		strcpy(p, cmd_p->ref_name);
-		argv[argc] = p;
-		argc++;
-	}
-	argv[argc] = NULL;
-	run_command_v_opt(argc, argv, RUN_COMMAND_NO_STDIO);
-}
-
 /*
  * This gets called after(if) we've successfully
  * unpacked the data payload.

^ permalink raw reply related	[flat|nested] 7+ messages in thread
* Re: [PATCH] [RFC] Make git-update-ref invoke the update and post-update hooks
@ 2015-06-15 19:49 Brian Vandenberg
  2015-06-15 20:22 ` Junio C Hamano
  0 siblings, 1 reply; 7+ messages in thread
From: Brian Vandenberg @ 2015-06-15 19:49 UTC (permalink / raw)
  To: git

From: Junio C Hamano <junkio@cox.net>
Date: 2006-10-08 15:00:32
Petr Baudis <pasky@suse.cz> writes:

>> Someone raised a concern that the update and post-update hooks are not
>> invoked at fetch time in the similar way as they are invoked at push
>> time, and the idea sort of makes sense. But this patch goes further - it
>> makes Git invoke those hooks each time a ref is updated in a repository
>> using the git-update-ref command, which I believe makes a lot of sense as
>> well - the behaviour is consistent with the current pushing behaviour
>> and you suddenly finally get a hook where you can properly notify even
>> about fast-forwards etc.

>In principle I do not have problem with this approach per-se,
>but I wonder if we were to do this we might want to make
>receive-pack.c::update() and cmd_update_ref() call the same
>underlying function, and make that underlying function implement
>this "ask the hook if updating is ok" dance.  It might even make
>sense to have update-ref honor deny_non_fast_forwards for that
>matter (I am mildly doubtful of this last point, though).

Was this rejected?

I'm tweaking the configuration on our master repo; among other things:
I've enabled reflog and disabled altering history or deleting branches
through receive-pack, instead requiring that someone make history
alterations directly (using update-ref).

update-ref can optionally accept a comment explaining why the history
needed to be altered, but we would prefer to make it mandatory.  Hooks
seem like a natural place to do that, but after running update-ref
under strace/truss & looking through builtin/update-ref.c, it looks as
though it doesn't make use of hooks.

-Brian

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2015-06-16 14:31 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-10-08  0:08 [PATCH] [RFC] Make git-update-ref invoke the update and post-update hooks Petr Baudis
2006-10-08  5:00 ` Junio C Hamano
  -- strict thread matches above, loose matches on Subject: below --
2015-06-15 19:49 Brian Vandenberg
2015-06-15 20:22 ` Junio C Hamano
2015-06-15 20:58   ` Brian Vandenberg
2015-06-15 21:45     ` Junio C Hamano
2015-06-16 14:31       ` Brian Vandenberg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).