Re: [PATCH 2/2] fetch: add tweak-fetch hook

2018-02-09 Thread Junio C Hamano
Leo Gaspard  writes:

> +tweak-fetch
> +~~~
> +
> +This hook is invoked by 'git fetch' (commonly called by 'git pull'), after 
> refs
> +have been fetched from the remote repository. It is not executed, if nothing 
> was
> +fetched.

Need to tighten explanation of "nothing was fetched".  If the only
change I made to my repository is that I created a new branch that
points at an existing object since last time you fetched, you would
obtain no new object when you fetch from me.  Would that count as
"nothing was fetched"?  Or would it be still fetching something
(i.e. your remote-tracking hierarchy will record the fact that I now
have this new branch)?

> +   SP not-for-merge|merge|ignore SP  SP 
>  LF
> + ...
> +The `` is the remote's name for the ref that was fetched, and
> +`` is a name of a remote-tracking branch, like
> +"refs/remotes/origin/master". `` can be undefined if the 
> fetched
> +ref is not being stored in a local refname. In this case, it will be set to 
> `@`,

Don't use "@"; leave it empty instead.

> +TODO: Add documentation for the “ignore” parameter. Unfortunately, I'm not
> +really sure I get what this does or what invariants it is supposed to 
> maintain
> +(eg. all “ignore” updates at the end of the refs list?), so this may also
> +require code changes.

If you are not using the feature, wouldn't it make more sense not to
add it in the first place?



[PATCH 2/2] fetch: add tweak-fetch hook

2018-02-09 Thread Leo Gaspard
From: Léo Gaspard 

The tweak-fetch hook is fed lines on stdin for all refs that were
fetched, and outputs on stdout possibly modified lines. Its output is
then parsed and used when `git fetch` updates the remote tracking refs,
records the entries in FETCH_HEAD, and produces its report.

The modifications here are heavily based on prior work by Joey Hess.

Based-on-patch-by: Joey Hess 
Signed-off-by: Leo Gaspard 
---
 Documentation/githooks.txt  |  37 +++
 builtin/fetch.c | 210 +++-
 t/t5574-fetch-tweak-fetch-hook.sh   |  90 
 templates/hooks--tweak-fetch.sample |  24 +
 4 files changed, 359 insertions(+), 2 deletions(-)
 create mode 100755 t/t5574-fetch-tweak-fetch-hook.sh
 create mode 100755 templates/hooks--tweak-fetch.sample

diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index f877f7b7c..1b4a18bf0 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -177,6 +177,43 @@ 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.
 
+tweak-fetch
+~~~
+
+This hook is invoked by 'git fetch' (commonly called by 'git pull'), after refs
+have been fetched from the remote repository. It is not executed, if nothing 
was
+fetched.
+
+The output of the hook is used to update the remote-tracking branches, and
+`.git/FETCH_HEAD`, in preparation for a later merge operation done by 'git
+merge'.
+
+It takes no arguments, but is fed a line of the following format on its 
standard
+input for each ref that was fetched.
+
+   SP not-for-merge|merge|ignore SP  SP  
LF
+
+Where the "not-for-merge" flag indicates the ref is not to be merged into the
+current branch, and the "merge" flag indicates that 'git merge' should later
+merge it.
+
+The `` is the remote's name for the ref that was fetched, and
+`` is a name of a remote-tracking branch, like
+"refs/remotes/origin/master". `` can be undefined if the fetched
+ref is not being stored in a local refname. In this case, it will be set to 
`@`,
+an invalide refspec, so that scripts can be written more easily.
+
+TODO: Add documentation for the “ignore” parameter. Unfortunately, I'm not
+really sure I get what this does or what invariants it is supposed to maintain
+(eg. all “ignore” updates at the end of the refs list?), so this may also
+require code changes.
+
+The hook must consume all of its standard input, and output back lines of the
+same format. It can modify its input as desired, including adding or removing
+lines, updating the sha1 (i.e. re-point the remote-tracking branch), changing
+the merge flag, and changing the `` (i.e. use different
+remote-tracking branch).
+
 post-merge
 ~~
 
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 76dc05f61..1bb394530 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -28,6 +28,8 @@ static const char * const builtin_fetch_usage[] = {
NULL
 };
 
+static const char tweak_fetch_hook[] = "tweak-fetch";
+
 enum {
TAGS_UNSET = 0,
TAGS_DEFAULT = 1,
@@ -181,6 +183,206 @@ static struct option builtin_fetch_options[] = {
OPT_END()
 };
 
+static int feed_tweak_fetch_hook(int in, int out, void *data)
+{
+   struct ref *ref;
+   struct strbuf buf = STRBUF_INIT;
+   const char *kw, *peer_ref;
+   char oid_buf[GIT_SHA1_HEXSZ + 1];
+   int ret;
+
+   for (ref = data; ref; ref = ref->next) {
+   if (ref->fetch_head_status == FETCH_HEAD_MERGE)
+   kw = "merge";
+   else if (ref->fetch_head_status == FETCH_HEAD_IGNORE)
+   kw = "ignore";
+   else
+   kw = "not-for-merge";
+   if (!ref->name)
+   die("trying to fetch an inexistant ref");
+   if (ref->peer_ref && ref->peer_ref->name)
+   peer_ref = ref->peer_ref->name;
+   else
+   peer_ref = "@";
+   strbuf_addf(, "%s %s %s %s\n",
+   oid_to_hex_r(oid_buf, >old_oid), kw,
+   ref->name, peer_ref);
+   }
+
+   ret = write_in_full(out, buf.buf, buf.len) != buf.len;
+   if (ret)
+   warning("%s hook failed to consume all its input",
+   tweak_fetch_hook);
+   close(out);
+   strbuf_release();
+   return ret;
+}
+
+static struct ref *parse_tweak_fetch_hook_line(char *l,
+   struct string_list *existing_refs)
+{
+   struct ref *ref = NULL, *peer_ref = NULL;
+   struct string_list_item *peer_item = NULL;
+   char *words[4];
+   int i, word = 0;
+   char *problem;
+
+   for (i = 0; l[i]; i++) {
+   if (isspace(l[i])) {
+   l[i] = '\0';
+