The post-fetch hook is fed on its stdin all refs that were newly fetched. It is not allowed to abort the fetch (or pull), but can modify what was fetched or take other actions. One example use of this hook is to automatically merge certain remote branches into a local branch. Another is to update a local cache (such as a search index) with the fetched refs. No other hook is run near fetch time, except for post-merge, which doesn't always run after a fetch, which is why this additional hook is useful. Signed-off-by: Joey Hess <joey@xxxxxxxxxxx> --- The #1 point of confusion for git-annex users is the need to run "git annex merge" after fetching. That does a union merge of newly fetched remote git-annex branches into the local git-annex branch. If a user does a "git pull; ... ; git push" and forgets to git annex merge in between, their push often fails as the git-annex branches have diverged. With this hook, that confusing step can be eliminated. Since git annex merge could be run at any point between fetch and push, I considered several different hooks, including this one, a pre-push hook, and a variant of this hook that does not feed the hook any information on stdin. I chose this one, with the information on stdin because it seems the most generally useful, and will let me make git annex merge slightly more optimal than it would be without the stdin. Documentation/githooks.txt | 12 ++++++++++ builtin/fetch.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 0 deletions(-) diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt index 28edefa..96a588c 100644 --- a/Documentation/githooks.txt +++ b/Documentation/githooks.txt @@ -162,6 +162,18 @@ This hook can be used to perform repository validity checks, auto-display differences from the previous HEAD if different, or set working dir metadata properties. +post-fetch +~~~~~~~~~~ + +This hook is invoked by 'git fetch' (commonly called by 'git pull'), after +refs have been fetched from the remote repository. It takes no arguments, +but is fed a list of new or updated refs on its standard input. This hook +cannot affect the outcome of 'git fetch' and is not executed, if nothing +was fetched. + +This hook can make modifications to the fetched refs, or take other +actions. + post-merge ~~~~~~~~~~ diff --git a/builtin/fetch.c b/builtin/fetch.c index 33ad3aa..d813b8e 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -89,6 +89,52 @@ static struct option builtin_fetch_options[] = { OPT_END() }; +static const char post_fetch_hook[] = "post-fetch"; +struct ref *fetched_refs = NULL; +void run_post_fetch_hook (void) { + struct ref *ref; + struct child_process proc; + const char *argv[2]; + FILE *f; + + if (! fetched_refs) + return; + + argv[0] = git_path("hooks/%s", post_fetch_hook); + if (access(argv[0], X_OK) < 0) + return; + argv[1] = NULL; + + memset(&proc, 0, sizeof(proc)); + proc.argv = argv; + proc.in = -1; + proc.stdout_to_stderr = 1; + if (start_command(&proc) != 0) + return; + + f = fdopen(proc.in, "w"); + if (f == NULL) { + close(proc.in); + goto cleanup; + } + for (ref = fetched_refs; ref; ref = ref->next) + fprintf(f, "%s\n", ref->name); + fclose(f); + +cleanup: + free_refs(fetched_refs); + fetched_refs = NULL; + + finish_command(&proc); + close(proc.in); +} + +void post_fetch_hook_observe (const struct ref *fetched_ref) { + struct ref *ref = copy_ref(fetched_ref); + ref->next = fetched_refs; + fetched_refs = ref; +} + static void unlock_pack(void) { if (transport) @@ -233,6 +279,7 @@ static int s_update_ref(const char *action, if (write_ref_sha1(lock, ref->new_sha1, msg) < 0) return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT : STORE_REF_ERROR_OTHER; + post_fetch_hook_observe(ref); return 0; } @@ -755,6 +802,9 @@ static int do_fetch(struct transport *transport, free_refs(ref_map); } + /* Run hook only after fetching all refs. */ + run_post_fetch_hook(); + return 0; } -- 1.7.7.3
Attachment:
signature.asc
Description: Digital signature