@@ -224,6 +224,11 @@ the working tree.
spending extra time to avoid mistakes based on incorrectly matching
context lines.
+HOOKS
+-----
+This command can run `post-cherry-pick` hook. See linkgit:githooks[5]
+for more information.
+
SEE ALSO
--------
linkgit:git-revert[1]
@@ -290,6 +290,11 @@ fetched, making it impossible to check out that submodule later without
having to do a fetch again. This is expected to be fixed in a future Git
version.
+HOOKS
+-----
+This command can run `post-fetch` hook. See linkgit:githooks[5]
+for more information.
+
SEE ALSO
--------
linkgit:git-pull[1]
@@ -149,6 +149,14 @@ invoked after a commit is made.
This hook is meant primarily for notification, and cannot affect
the outcome of `git commit`.
+post-cherry-pick
+~~~~~~~~~~~~~~~~
+
+This hook is invoked by linkgit:git-cherry-pick[1]. This hook is
+called with two parameters. The first is `<old sha1>` and the second
+`<new sha1>`, where `<old sha1>..<new sha1>` describes all new
+cherry-picked commits.
+
pre-rebase
~~~~~~~~~~
@@ -191,6 +199,21 @@ save and restore any form of metadata associated with the working tree
(e.g.: permissions/ownership, ACLS, etc). See contrib/hooks/setgitperms.perl
for an example of how to do this.
+post-fetch
+~~~~~~~~~~
+This hook is called by linkgit:git-fetch[1] and can be used to process
+newly fetched commits and tags.
+
+Information about what was fetched is provided on the hook's standard
+input with lines of the form:
+
+ <local ref> SP <old sha1> SP <remote ref> SP <new sha1> LF
+
+where `<local ref>` got updated from `<old sha1>` to `<new sha1>` as a
+result of fetching `<remote ref>`. If a branch or tag was created,
+`<old_sha1>` will be 40 `0`. If a tag was pruned, `<remote_ref>` will
+be `(delete)` and <new sha1> will be 40 `0`.
+
pre-push
~~~~~~~~
@@ -66,6 +66,7 @@ static struct refspec refmap = REFSPEC_INIT_FETCH;
static struct list_objects_filter_options filter_options;
static struct string_list server_options = STRING_LIST_INIT_DUP;
static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
+static struct strbuf post_fetch_sb = STRBUF_INIT;
static int git_fetch_config(const char *k, const char *v, void *cb)
{
@@ -510,10 +511,24 @@ static struct ref *get_ref_map(struct remote *remote,
return ref_map;
}
+static void record_post_fetch(const char *name,
+ const struct object_id *old_oid,
+ const char *remote,
+ const struct object_id *new_oid)
+{
+ char old_hex[GIT_MAX_HEXSZ + 1], new_hex[GIT_MAX_HEXSZ + 1];
+
+ oid_to_hex_r(old_hex, old_oid);
+ oid_to_hex_r(new_hex, new_oid);
+ strbuf_addf(&post_fetch_sb, "%s %s %s %s\n",
+ name, old_hex, remote ?: "(delete)", new_hex);
+}
+
#define STORE_REF_ERROR_OTHER 1
#define STORE_REF_ERROR_DF_CONFLICT 2
static int s_update_ref(const char *action,
+ const char *remote,
struct ref *ref,
int check_old)
{
@@ -546,6 +561,7 @@ static int s_update_ref(const char *action,
ref_transaction_free(transaction);
strbuf_release(&err);
free(msg);
+ record_post_fetch(ref->name, &ref->old_oid, remote, &ref->new_oid);
return 0;
fail:
ref_transaction_free(transaction);
@@ -726,7 +742,7 @@ static int update_local_ref(struct ref *ref,
starts_with(ref->name, "refs/tags/")) {
if (force || ref->force) {
int r;
- r = s_update_ref("updating tag", ref, 0);
+ r = s_update_ref("updating tag", remote, ref, 0);
format_display(display, r ? '!' : 't', _("[tag update]"),
r ? _("unable to update local ref") : NULL,
remote, pretty_ref, summary_width);
@@ -766,7 +782,7 @@ static int update_local_ref(struct ref *ref,
if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
(recurse_submodules != RECURSE_SUBMODULES_ON))
check_for_new_submodule_commits(&ref->new_oid);
- r = s_update_ref(msg, ref, 0);
+ r = s_update_ref(msg, remote, ref, 0);
format_display(display, r ? '!' : '*', what,
r ? _("unable to update local ref") : NULL,
remote, pretty_ref, summary_width);
@@ -782,7 +798,7 @@ static int update_local_ref(struct ref *ref,
if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
(recurse_submodules != RECURSE_SUBMODULES_ON))
check_for_new_submodule_commits(&ref->new_oid);
- r = s_update_ref("fast-forward", ref, 1);
+ r = s_update_ref("fast-forward", remote, ref, 1);
format_display(display, r ? '!' : ' ', quickref.buf,
r ? _("unable to update local ref") : NULL,
remote, pretty_ref, summary_width);
@@ -797,7 +813,7 @@ static int update_local_ref(struct ref *ref,
if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
(recurse_submodules != RECURSE_SUBMODULES_ON))
check_for_new_submodule_commits(&ref->new_oid);
- r = s_update_ref("forced-update", ref, 1);
+ r = s_update_ref("forced-update", remote, ref, 1);
format_display(display, r ? '!' : '+', quickref.buf,
r ? _("unable to update local ref") : _("forced update"),
remote, pretty_ref, summary_width);
@@ -1071,8 +1087,11 @@ static int prune_refs(struct refspec *rs, struct ref *ref_map,
if (!dry_run) {
struct string_list refnames = STRING_LIST_INIT_NODUP;
- for (ref = stale_refs; ref; ref = ref->next)
+ for (ref = stale_refs; ref; ref = ref->next) {
string_list_append(&refnames, ref->name);
+ record_post_fetch(ref->name, &ref->old_oid,
+ NULL, &null_oid);
+ }
result = delete_refs("fetch: prune", &refnames, 0);
string_list_clear(&refnames, 0);
@@ -1561,6 +1580,47 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru
return exit_code;
}
+static int run_post_fetch_hook(void)
+{
+ int ret = 0, x;
+ struct child_process proc = CHILD_PROCESS_INIT;
+ const char *argv[2];
+
+ if (!(argv[0] = find_hook("post-fetch")))
+ return 0;
+ argv[1] = NULL;
+
+ proc.argv = argv;
+ proc.in = -1;
+
+ if (start_command(&proc)) {
+ finish_command(&proc);
+ return -1;
+ }
+
+ sigchain_push(SIGPIPE, SIG_IGN);
+
+ if (write_in_full(proc.in, post_fetch_sb.buf, post_fetch_sb.len) < 0) {
+ /* We do not mind if a hook does not read all refs. */
+ if (errno != EPIPE)
+ ret = -1;
+ }
+
+ strbuf_release(&post_fetch_sb);
+
+ x = close(proc.in);
+ if (!ret)
+ ret = x;
+
+ sigchain_pop(SIGPIPE);
+
+ x = finish_command(&proc);
+ if (!ret)
+ ret = x;
+
+ return ret;
+}
+
int cmd_fetch(int argc, const char **argv, const char *prefix)
{
int i;
@@ -1669,6 +1729,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
close_all_packs(the_repository->objects);
+ run_post_fetch_hook();
+
argv_array_pushl(&argv_gc_auto, "gc", "--auto", NULL);
if (verbosity < 0)
argv_array_push(&argv_gc_auto, "--quiet");
@@ -8,6 +8,8 @@
#include "dir.h"
#include "sequencer.h"
#include "branch.h"
+#include "refs.h"
+#include "run-command.h"
/*
* This implements the builtins revert and cherry-pick.
@@ -223,12 +225,24 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
{
struct replay_opts opts = REPLAY_OPTS_INIT;
+ struct object_id old_oid, new_oid;
+ char old_hex[GIT_MAX_HEXSZ + 1], new_hex[GIT_MAX_HEXSZ + 1];
int res;
+ if (read_ref("HEAD", &old_oid))
+ die(_("failed to read HEAD, cherry-pick failed"));
+
opts.action = REPLAY_PICK;
sequencer_init_config(&opts);
res = run_sequencer(argc, argv, &opts);
if (res < 0)
die(_("cherry-pick failed"));
+
+ if (read_ref("HEAD", &new_oid))
+ die(_("failed to read HEAD after cherry-pick"));
+
+ oid_to_hex_r(old_hex, &old_oid);
+ oid_to_hex_r(new_hex, &new_oid);
+ run_hook_le(0, "post-cherry-pick", old_hex, new_hex, NULL);
return res;
}