All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tejun Heo <tj@kernel.org>
To: git@vger.kernel.org, Junio C Hamano <jch2355@gmail.com>,
	Jeff King <peff@peff.net>
Cc: kernel-team@fb.com, Tejun Heo <htejun@fb.com>
Subject: [PATCH 4/5] githooks: Add post-cherry-pick and post-fetch hooks
Date: Tue, 11 Dec 2018 15:49:08 -0800	[thread overview]
Message-ID: <20181211234909.2855638-5-tj@kernel.org> (raw)
In-Reply-To: <20181211234909.2855638-1-tj@kernel.org>

From: Tejun Heo <htejun@fb.com>

* post-cherry-pick: Called after a cherry-pick and given parameters so
  that it can tell which are the new cherry-picks.

* post-fetch: Called after a fetch.  Each updated ref and sha1 are fed
  on stdin.

These two hooks will be used to keep refs/notes/xref-cherry-picks
up-to-date.

Signed-off-by: Tejun Heo <htejun@fb.com>
---
 Documentation/git-cherry-pick.txt |  5 +++
 Documentation/git-fetch.txt       |  5 +++
 Documentation/githooks.txt        | 23 ++++++++++
 builtin/fetch.c                   | 72 ++++++++++++++++++++++++++++---
 builtin/revert.c                  | 14 ++++++
 5 files changed, 114 insertions(+), 5 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index d35d771fc..527cb9fea 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -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]
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index e31993559..a04c6079a 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -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]
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index 959044347..24c122343 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -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
 ~~~~~~~~
 
diff --git a/builtin/fetch.c b/builtin/fetch.c
index e0140327a..eac792a33 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -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");
diff --git a/builtin/revert.c b/builtin/revert.c
index c93393c89..0b7e578cc 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -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;
 }
-- 
2.17.1


  parent reply	other threads:[~2018-12-11 23:49 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-11 23:49 [PATCHSET] git-reverse-trailer-xrefs: Reverse map cherry-picks and other cross-references Tejun Heo
2018-12-11 23:49 ` [PATCH 1/5] trailer: Implement a helper to reverse-map trailer xrefs Tejun Heo
2018-12-11 23:49 ` [PATCH 2/5] notes: Implement special handlings for refs/notes/xref- Tejun Heo
2018-12-11 23:49 ` [PATCH 3/5] notes: Implement git-reverse-trailer-xrefs Tejun Heo
2018-12-11 23:49 ` Tejun Heo [this message]
2018-12-11 23:49 ` [PATCH 5/5] notes: Implement xref-cherry-picks hooks and tests Tejun Heo
2018-12-12  7:26 ` [PATCHSET] git-reverse-trailer-xrefs: Reverse map cherry-picks and other cross-references Junio C Hamano
2018-12-12 14:54   ` Tejun Heo
2018-12-13  3:01     ` Junio C Hamano
2018-12-13  3:09       ` Junio C Hamano
2018-12-13  3:46         ` Tejun Heo
2018-12-18 14:40           ` Stefan Xenos
2018-12-18 16:48             ` Stefan Xenos
2018-12-18 16:51               ` Tejun Heo
2018-12-13  3:40       ` Tejun Heo
2018-12-13  5:47         ` Junio C Hamano
2018-12-13 16:15           ` Tejun Heo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181211234909.2855638-5-tj@kernel.org \
    --to=tj@kernel.org \
    --cc=git@vger.kernel.org \
    --cc=htejun@fb.com \
    --cc=jch2355@gmail.com \
    --cc=kernel-team@fb.com \
    --cc=peff@peff.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.