receive-pack hooks updates.

The earlier one conflated update and post-update hooks for no
good reason.  Correct that ugly hack.  Now post-update hooks
will take the list of successfully updated refs.

Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
Junio C Hamano 2005-08-02 14:24:22 -07:00
parent 0bc3cdfc82
commit 19614330dd
4 changed files with 71 additions and 37 deletions

View file

@ -43,35 +43,35 @@ The hook should exit with non-zero status if it wants to
disallow updating the named ref. Otherwise it should exit with
zero.
The same hook is also called with an empty string as refname and
no other arguments just before git-receive-pack exits. This can
be used to implement repository wide cleanup task if needed.
The exit code from this hook invocation is ignored; the only
thing left for git-receive-pack to do at that point is to exit
itself anyway.
Using this hook, it is easy to generate mails on updates to
the local repository. This example script sends a mail with
the commits pushed to the repository:
#!/bin/sh
case "$#,$1" in
1,) # help packed repository pulled via dumb protocol.
git-update-server-info
;;
*) # mail out commit update information.
if expr "$2" : '0*$' >/dev/null
then
echo "Created now ref."
# mail out commit update information.
if expr "$2" : '0*$' >/dev/null
then
echo "Created a new ref, with the following commits:"
git-rev-list --pretty "$2"
else
echo "New commits"
else
echo "New commits:"
git-rev-list --pretty "$3" "^$2"
fi |
mail -s "Changes to ref $1" commit-list@mydomain
esac
fi |
mail -s "Changes to ref $1" commit-list@mydomain
exit 0
Another hook $GIT_DIR/hooks/post-update, if exists and
executable, is called with the list of refs that have been
updated. This can be used to implement repository wide cleanup
task if needed. The exit code from this hook invocation is
ignored; the only thing left for git-receive-pack to do at that
point is to exit itself anyway. This hook can be used, for
example, to run "git-update-server-info" if the repository is
packed and is served via a dumb transport.
#!/bin/sh
exec git-update-server-info
OPTIONS
-------
<directory>::

View file

@ -21,6 +21,7 @@ static void write_head_info(void)
struct command {
struct command *next;
unsigned char updated;
unsigned char old_sha1[20];
unsigned char new_sha1[20];
char ref_name[0];
@ -88,7 +89,8 @@ static int run_update_hook(const char *refname,
}
}
static void update(const char *name, unsigned char *old_sha1, unsigned char *new_sha1)
static int update(const char *name,
unsigned char *old_sha1, unsigned char *new_sha1)
{
char new_hex[60], *old_hex, *lock_name;
int newfd, namelen, written;
@ -101,11 +103,13 @@ static void update(const char *name, unsigned char *old_sha1, unsigned char *new
strcpy(new_hex, sha1_to_hex(new_sha1));
old_hex = sha1_to_hex(old_sha1);
if (!has_sha1_file(new_sha1))
die("unpack should have generated %s, but I can't find it!", new_hex);
return error("unpack should have generated %s, "
"but I can't find it!", new_hex);
newfd = open(lock_name, O_CREAT | O_EXCL | O_WRONLY, 0666);
if (newfd < 0)
die("unable to create %s (%s)", lock_name, strerror(errno));
return error("unable to create %s (%s)",
lock_name, strerror(errno));
/* Write the ref with an ending '\n' */
new_hex[40] = '\n';
@ -117,24 +121,54 @@ static void update(const char *name, unsigned char *old_sha1, unsigned char *new
close(newfd);
if (written != 41) {
unlink(lock_name);
die("unable to write %s", lock_name);
return error("unable to write %s", lock_name);
}
if (verify_old_ref(name, old_hex) < 0) {
unlink(lock_name);
die("%s changed during push", name);
return error("%s changed during push", name);
}
if (run_update_hook(name, old_hex, new_hex)) {
unlink(lock_name);
fprintf(stderr, "hook declined to update %s\n", name);
return error("hook declined to update %s\n", name);
}
else if (rename(lock_name, name) < 0) {
unlink(lock_name);
die("unable to replace %s", name);
return error("unable to replace %s", name);
}
else
else {
fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex);
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;
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->updated)
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) {
if (!cmd_p->updated)
continue;
argv[argc] = xmalloc(strlen(cmd_p->ref_name) + 1);
strcpy(argv[argc], cmd_p->ref_name);
argc++;
}
argv[argc] = NULL;
run_command_v(argc, argv);
}
/*
* This gets called after(if) we've successfully
@ -145,10 +179,11 @@ static void execute_commands(void)
struct command *cmd = commands;
while (cmd) {
update(cmd->ref_name, cmd->old_sha1, cmd->new_sha1);
cmd->updated = !update(cmd->ref_name,
cmd->old_sha1, cmd->new_sha1);
cmd = cmd->next;
}
run_update_hook("", NULL, NULL);
run_update_post_hook(commands);
}
static void read_head_info(void)

View file

@ -2,7 +2,7 @@
#include "run-command.h"
#include <sys/wait.h>
static int run_external_command(int argc, const char **argv)
int run_command_v(int argc, char **argv)
{
pid_t pid = fork();
@ -10,7 +10,7 @@ static int run_external_command(int argc, const char **argv)
return -ERR_RUN_COMMAND_FORK;
if (!pid) {
execvp(argv[0], (char *const*) argv);
return -ERR_RUN_COMMAND_EXEC;
die("exec %s failed.", argv[0]);
}
for (;;) {
int status, code;
@ -39,14 +39,12 @@ static int run_external_command(int argc, const char **argv)
int run_command(const char *cmd, ...)
{
int argc;
const char *argv[MAX_RUN_COMMAND_ARGS];
char *argv[MAX_RUN_COMMAND_ARGS];
const char *arg;
va_list param;
fprintf(stderr, "run-command %s (%d)\n", cmd, ERR_RUN_COMMAND_EXEC);
va_start(param, cmd);
argv[0] = cmd;
argv[0] = (char*) cmd;
argc = 1;
while (argc < MAX_RUN_COMMAND_ARGS) {
arg = argv[argc++] = va_arg(param, char *);
@ -56,5 +54,5 @@ int run_command(const char *cmd, ...)
va_end(param);
if (MAX_RUN_COMMAND_ARGS <= argc)
return error("too many args to run %s", cmd);
return run_external_command(argc, argv);
return run_command_v(argc, argv);
}

View file

@ -11,6 +11,7 @@ enum {
ERR_RUN_COMMAND_WAITPID_NOEXIT,
};
int run_command_v(int argc, char **argv);
int run_command(const char *cmd, ...);
#endif