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';
+