{"thread":{"id":"28620","subject":"[PATCH] fmt-merge-msg: use branch.$name.description","startedAt":"2011-10-07T06:57:51Z","lastAt":"2011-10-08T00:01:35Z","messageCount":12,"participants":["Junio C Hamano","Michael J Gruber","Jonathan Nieder","Jakub Narebski"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"177137","messageId":"7vobxtwaog.fsf@alter.siamese.dyndns.org","threadId":"28620","inReplyTo":null,"subject":"[PATCH] fmt-merge-msg: use branch.$name.description","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-10-07T06:57:51Z","receivedAt":"2011-10-07T06:57:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This teaches \"merge --log\" and fmt-merge-msg to use branch description\ninformation when merging a local topic branch into the mainline. The\ndescription goes between the branch name label and the list of commit\ntitles.\n\nThe refactoring to share the common configuration parsing between\nmerge and fmt-merge-msg needs to be made into a separate patch.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n * This is a follow-up to the branch.$name.description series that has\n   been queued in 'pu' (jc/request-pull-show-head-4). The two commands\n   join the family of commands that are aware of the branch description,\n   i.e. format-patch (cover letter), request-pull.\n\n Makefile                |    1 +\n builtin/fmt-merge-msg.c |   63 ++++++++++++++++++++++++++++++++++++++--------\n builtin/merge.c         |   16 +++++------\n fmt-merge-msg.h         |    6 ++++\n 4 files changed, 66 insertions(+), 20 deletions(-)\n create mode 100644 fmt-merge-msg.h\n\ndiff --git a/Makefile b/Makefile\nindex 8d6d451..b499049 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -527,6 +527,7 @@ LIB_H += diffcore.h\n LIB_H += diff.h\n LIB_H += dir.h\n LIB_H += exec_cmd.h\n+LIB_H += fmt-merge-msg.h\n LIB_H += fsck.h\n LIB_H += gettext.h\n LIB_H += git-compat-util.h\ndiff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c\nindex 7581632..21efd25 100644\n--- a/builtin/fmt-merge-msg.c\n+++ b/builtin/fmt-merge-msg.c\n@@ -5,6 +5,8 @@\n #include \"revision.h\"\n #include \"tag.h\"\n #include \"string-list.h\"\n+#include \"branch.h\"\n+#include \"fmt-merge-msg.h\"\n \n static const char * const fmt_merge_msg_usage[] = {\n \t\"git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]\",\n@@ -12,8 +14,9 @@ static const char * const fmt_merge_msg_usage[] = {\n };\n \n static int shortlog_len;\n+static int use_branch_desc;\n \n-static int fmt_merge_msg_config(const char *key, const char *value, void *cb)\n+int fmt_merge_msg_config(const char *key, const char *value, void *cb)\n {\n \tif (!strcmp(key, \"merge.log\") || !strcmp(key, \"merge.summary\")) {\n \t\tint is_bool;\n@@ -22,6 +25,8 @@ static int fmt_merge_msg_config(const char *key, const char *value, void *cb)\n \t\t\treturn error(\"%s: negative length %s\", key, value);\n \t\tif (is_bool && shortlog_len)\n \t\t\tshortlog_len = DEFAULT_MERGE_LOG_LEN;\n+\t} else if (!strcmp(key, \"merge.branchdesc\")) {\n+\t\tuse_branch_desc = git_config_bool(key, value);\n \t}\n \treturn 0;\n }\n@@ -31,6 +36,11 @@ struct src_data {\n \tint head_status;\n };\n \n+struct origin_data {\n+\tunsigned char sha1[20];\n+\tint is_local_branch:1;\n+};\n+\n static void init_src_data(struct src_data *data)\n {\n \tdata->branch.strdup_strings = 1;\n@@ -45,7 +55,7 @@ static struct string_list origins = STRING_LIST_INIT_DUP;\n static int handle_line(char *line)\n {\n \tint i, len = strlen(line);\n-\tunsigned char *sha1;\n+\tstruct origin_data *origin_data;\n \tchar *src, *origin;\n \tstruct src_data *src_data;\n \tstruct string_list_item *item;\n@@ -61,11 +71,13 @@ static int handle_line(char *line)\n \t\treturn 2;\n \n \tline[40] = 0;\n-\tsha1 = xmalloc(20);\n-\ti = get_sha1(line, sha1);\n+\torigin_data = xcalloc(1, sizeof(struct origin_data));\n+\ti = get_sha1(line, origin_data->sha1);\n \tline[40] = '\\t';\n-\tif (i)\n+\tif (i) {\n+\t\tfree(origin_data);\n \t\treturn 3;\n+\t}\n \n \tif (line[len - 1] == '\\n')\n \t\tline[len - 1] = 0;\n@@ -93,6 +105,7 @@ static int handle_line(char *line)\n \t\torigin = src;\n \t\tsrc_data->head_status |= 1;\n \t} else if (!prefixcmp(line, \"branch \")) {\n+\t\torigin_data->is_local_branch = 1;\n \t\torigin = line + 7;\n \t\tstring_list_append(&src_data->branch, origin);\n \t\tsrc_data->head_status |= 2;\n@@ -119,7 +132,9 @@ static int handle_line(char *line)\n \t\tsprintf(new_origin, \"%s of %s\", origin, src);\n \t\torigin = new_origin;\n \t}\n-\tstring_list_append(&origins, origin)->util = sha1;\n+\tif (strcmp(\".\", src))\n+\t\torigin_data->is_local_branch = 0;\n+\tstring_list_append(&origins, origin)->util = origin_data;\n \treturn 0;\n }\n \n@@ -140,9 +155,30 @@ static void print_joined(const char *singular, const char *plural,\n \t}\n }\n \n-static void shortlog(const char *name, unsigned char *sha1,\n-\t\tstruct commit *head, struct rev_info *rev, int limit,\n-\t\tstruct strbuf *out)\n+static void add_branch_desc(struct strbuf *out, const char *name)\n+{\n+\tstruct strbuf desc = STRBUF_INIT;\n+\n+\tif (!read_branch_desc(&desc, name)) {\n+\t\tconst char *bp = desc.buf;\n+\t\twhile (*bp) {\n+\t\t\tconst char *ep = strchrnul(bp, '\\n');\n+\t\t\tif (*ep)\n+\t\t\t\tep++;\n+\t\t\tstrbuf_addf(out, \"  : %.*s\", (int)(ep - bp), bp);\n+\t\t\tbp = ep;\n+\t\t}\n+\t\tif (out->buf[out->len - 1] != '\\n')\n+\t\t\tstrbuf_addch(out, '\\n');\n+\t}\n+\tstrbuf_release(&desc);\n+}\n+\n+static void shortlog(const char *name,\n+\t\t     struct origin_data *origin_data,\n+\t\t     struct commit *head,\n+\t\t     struct rev_info *rev, int limit,\n+\t\t     struct strbuf *out)\n {\n \tint i, count = 0;\n \tstruct commit *commit;\n@@ -150,6 +186,7 @@ static void shortlog(const char *name, unsigned char *sha1,\n \tstruct string_list subjects = STRING_LIST_INIT_DUP;\n \tint flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;\n \tstruct strbuf sb = STRBUF_INIT;\n+\tconst unsigned char *sha1 = origin_data->sha1;\n \n \tbranch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);\n \tif (!branch || branch->type != OBJ_COMMIT)\n@@ -188,6 +225,9 @@ static void shortlog(const char *name, unsigned char *sha1,\n \telse\n \t\tstrbuf_addf(out, \"\\n* %s:\\n\", name);\n \n+\tif (origin_data->is_local_branch && use_branch_desc)\n+\t\tadd_branch_desc(out, name);\n+\n \tfor (i = 0; i < subjects.nr; i++)\n \t\tif (i >= limit)\n \t\t\tstrbuf_addf(out, \"  ...\\n\");\n@@ -303,8 +343,9 @@ static int do_fmt_merge_msg(int merge_title, struct strbuf *in,\n \t\t\tstrbuf_addch(out, '\\n');\n \n \t\tfor (i = 0; i < origins.nr; i++)\n-\t\t\tshortlog(origins.items[i].string, origins.items[i].util,\n-\t\t\t\t\thead, &rev, shortlog_len, out);\n+\t\t\tshortlog(origins.items[i].string,\n+\t\t\t\t origins.items[i].util,\n+\t\t\t\t head, &rev, shortlog_len, out);\n \t}\n \treturn 0;\n }\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex ab4077f..fe56aad 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -26,6 +26,7 @@\n #include \"merge-recursive.h\"\n #include \"resolve-undo.h\"\n #include \"remote.h\"\n+#include \"fmt-merge-msg.h\"\n \n #define DEFAULT_TWOHEAD (1<<0)\n #define DEFAULT_OCTOPUS (1<<1)\n@@ -525,6 +526,8 @@ static void parse_branch_merge_options(char *bmo)\n \n static int git_merge_config(const char *k, const char *v, void *cb)\n {\n+\tint status;\n+\n \tif (branch && !prefixcmp(k, \"branch.\") &&\n \t\t!prefixcmp(k + 7, branch) &&\n \t\t!strcmp(k + 7 + strlen(branch), \".mergeoptions\")) {\n@@ -541,15 +544,7 @@ static int git_merge_config(const char *k, const char *v, void *cb)\n \t\treturn git_config_string(&pull_octopus, k, v);\n \telse if (!strcmp(k, \"merge.renormalize\"))\n \t\toption_renormalize = git_config_bool(k, v);\n-\telse if (!strcmp(k, \"merge.log\") || !strcmp(k, \"merge.summary\")) {\n-\t\tint is_bool;\n-\t\tshortlog_len = git_config_bool_or_int(k, v, &is_bool);\n-\t\tif (!is_bool && shortlog_len < 0)\n-\t\t\treturn error(_(\"%s: negative length %s\"), k, v);\n-\t\tif (is_bool && shortlog_len)\n-\t\t\tshortlog_len = DEFAULT_MERGE_LOG_LEN;\n-\t\treturn 0;\n-\t} else if (!strcmp(k, \"merge.ff\")) {\n+\telse if (!strcmp(k, \"merge.ff\")) {\n \t\tint boolval = git_config_maybe_bool(k, v);\n \t\tif (0 <= boolval) {\n \t\t\tallow_fast_forward = boolval;\n@@ -562,6 +557,9 @@ static int git_merge_config(const char *k, const char *v, void *cb)\n \t\tdefault_to_upstream = git_config_bool(k, v);\n \t\treturn 0;\n \t}\n+\tstatus = fmt_merge_msg_config(k, v, cb);\n+\tif (status)\n+\t\treturn status;\n \treturn git_diff_ui_config(k, v, cb);\n }\n \ndiff --git a/fmt-merge-msg.h b/fmt-merge-msg.h\nnew file mode 100644\nindex 0000000..9217fdb\n--- /dev/null\n+++ b/fmt-merge-msg.h\n@@ -0,0 +1,6 @@\n+#ifndef FMT_MERGE_MSG_H\n+#define FMT_MERGE_MSG_H\n+\n+extern int fmt_merge_msg_config(const char *key, const char *value, void *cb);\n+\n+#endif /* FMT_MERGE_MSG_H */\n-- \n1.7.7.138.g7f41b6\n"},{"id":"177143","messageId":"4E8EBDA7.2040007@drmicha.warpmail.net","threadId":"28620","inReplyTo":"7vobxtwaog.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] fmt-merge-msg: use branch.$name.description","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-10-07T08:51:51Z","receivedAt":"2011-10-07T08:51:51Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Junio C Hamano venit, vidit, dixit 07.10.2011 08:57:\n> This teaches \"merge --log\" and fmt-merge-msg to use branch description\n> information when merging a local topic branch into the mainline. The\n> description goes between the branch name label and the list of commit\n> titles.\n> \n> The refactoring to share the common configuration parsing between\n> merge and fmt-merge-msg needs to be made into a separate patch.\n> \n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  * This is a follow-up to the branch.$name.description series that has\n>    been queued in 'pu' (jc/request-pull-show-head-4). The two commands\n>    join the family of commands that are aware of the branch description,\n>    i.e. format-patch (cover letter), request-pull.\n\n\nUhm, I tried to start a discussion there about whether we really want\nconfig based branch descriptions, together with suggestions and actual\nseries for notes based descriptions, notes based format-patch\ncover-letter, notes based branch output. Making fmt-merge-msg use that\nis a no-brainer.\n\nDo we want an implementation race, or could we please reach some\nconsensus about the direction first? (Not many have spoken up yet.)\n\nconfig based is so non-distributed, local in nature.\n\n>  Makefile                |    1 +\n>  builtin/fmt-merge-msg.c |   63 ++++++++++++++++++++++++++++++++++++++--------\n>  builtin/merge.c         |   16 +++++------\n>  fmt-merge-msg.h         |    6 ++++\n>  4 files changed, 66 insertions(+), 20 deletions(-)\n>  create mode 100644 fmt-merge-msg.h\n> \n> diff --git a/Makefile b/Makefile\n> index 8d6d451..b499049 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -527,6 +527,7 @@ LIB_H += diffcore.h\n>  LIB_H += diff.h\n>  LIB_H += dir.h\n>  LIB_H += exec_cmd.h\n> +LIB_H += fmt-merge-msg.h\n>  LIB_H += fsck.h\n>  LIB_H += gettext.h\n>  LIB_H += git-compat-util.h\n> diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c\n> index 7581632..21efd25 100644\n> --- a/builtin/fmt-merge-msg.c\n> +++ b/builtin/fmt-merge-msg.c\n> @@ -5,6 +5,8 @@\n>  #include \"revision.h\"\n>  #include \"tag.h\"\n>  #include \"string-list.h\"\n> +#include \"branch.h\"\n> +#include \"fmt-merge-msg.h\"\n>  \n>  static const char * const fmt_merge_msg_usage[] = {\n>  \t\"git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]\",\n> @@ -12,8 +14,9 @@ static const char * const fmt_merge_msg_usage[] = {\n>  };\n>  \n>  static int shortlog_len;\n> +static int use_branch_desc;\n>  \n> -static int fmt_merge_msg_config(const char *key, const char *value, void *cb)\n> +int fmt_merge_msg_config(const char *key, const char *value, void *cb)\n>  {\n>  \tif (!strcmp(key, \"merge.log\") || !strcmp(key, \"merge.summary\")) {\n>  \t\tint is_bool;\n> @@ -22,6 +25,8 @@ static int fmt_merge_msg_config(const char *key, const char *value, void *cb)\n>  \t\t\treturn error(\"%s: negative length %s\", key, value);\n>  \t\tif (is_bool && shortlog_len)\n>  \t\t\tshortlog_len = DEFAULT_MERGE_LOG_LEN;\n> +\t} else if (!strcmp(key, \"merge.branchdesc\")) {\n> +\t\tuse_branch_desc = git_config_bool(key, value);\n>  \t}\n>  \treturn 0;\n>  }\n> @@ -31,6 +36,11 @@ struct src_data {\n>  \tint head_status;\n>  };\n>  \n> +struct origin_data {\n> +\tunsigned char sha1[20];\n> +\tint is_local_branch:1;\n> +};\n> +\n>  static void init_src_data(struct src_data *data)\n>  {\n>  \tdata->branch.strdup_strings = 1;\n> @@ -45,7 +55,7 @@ static struct string_list origins = STRING_LIST_INIT_DUP;\n>  static int handle_line(char *line)\n>  {\n>  \tint i, len = strlen(line);\n> -\tunsigned char *sha1;\n> +\tstruct origin_data *origin_data;\n>  \tchar *src, *origin;\n>  \tstruct src_data *src_data;\n>  \tstruct string_list_item *item;\n> @@ -61,11 +71,13 @@ static int handle_line(char *line)\n>  \t\treturn 2;\n>  \n>  \tline[40] = 0;\n> -\tsha1 = xmalloc(20);\n> -\ti = get_sha1(line, sha1);\n> +\torigin_data = xcalloc(1, sizeof(struct origin_data));\n> +\ti = get_sha1(line, origin_data->sha1);\n>  \tline[40] = '\\t';\n> -\tif (i)\n> +\tif (i) {\n> +\t\tfree(origin_data);\n>  \t\treturn 3;\n> +\t}\n>  \n>  \tif (line[len - 1] == '\\n')\n>  \t\tline[len - 1] = 0;\n> @@ -93,6 +105,7 @@ static int handle_line(char *line)\n>  \t\torigin = src;\n>  \t\tsrc_data->head_status |= 1;\n>  \t} else if (!prefixcmp(line, \"branch \")) {\n> +\t\torigin_data->is_local_branch = 1;\n>  \t\torigin = line + 7;\n>  \t\tstring_list_append(&src_data->branch, origin);\n>  \t\tsrc_data->head_status |= 2;\n> @@ -119,7 +132,9 @@ static int handle_line(char *line)\n>  \t\tsprintf(new_origin, \"%s of %s\", origin, src);\n>  \t\torigin = new_origin;\n>  \t}\n> -\tstring_list_append(&origins, origin)->util = sha1;\n> +\tif (strcmp(\".\", src))\n> +\t\torigin_data->is_local_branch = 0;\n> +\tstring_list_append(&origins, origin)->util = origin_data;\n>  \treturn 0;\n>  }\n>  \n> @@ -140,9 +155,30 @@ static void print_joined(const char *singular, const char *plural,\n>  \t}\n>  }\n>  \n> -static void shortlog(const char *name, unsigned char *sha1,\n> -\t\tstruct commit *head, struct rev_info *rev, int limit,\n> -\t\tstruct strbuf *out)\n> +static void add_branch_desc(struct strbuf *out, const char *name)\n> +{\n> +\tstruct strbuf desc = STRBUF_INIT;\n> +\n> +\tif (!read_branch_desc(&desc, name)) {\n> +\t\tconst char *bp = desc.buf;\n> +\t\twhile (*bp) {\n> +\t\t\tconst char *ep = strchrnul(bp, '\\n');\n> +\t\t\tif (*ep)\n> +\t\t\t\tep++;\n> +\t\t\tstrbuf_addf(out, \"  : %.*s\", (int)(ep - bp), bp);\n> +\t\t\tbp = ep;\n> +\t\t}\n> +\t\tif (out->buf[out->len - 1] != '\\n')\n> +\t\t\tstrbuf_addch(out, '\\n');\n> +\t}\n> +\tstrbuf_release(&desc);\n> +}\n> +\n> +static void shortlog(const char *name,\n> +\t\t     struct origin_data *origin_data,\n> +\t\t     struct commit *head,\n> +\t\t     struct rev_info *rev, int limit,\n> +\t\t     struct strbuf *out)\n>  {\n>  \tint i, count = 0;\n>  \tstruct commit *commit;\n> @@ -150,6 +186,7 @@ static void shortlog(const char *name, unsigned char *sha1,\n>  \tstruct string_list subjects = STRING_LIST_INIT_DUP;\n>  \tint flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;\n>  \tstruct strbuf sb = STRBUF_INIT;\n> +\tconst unsigned char *sha1 = origin_data->sha1;\n>  \n>  \tbranch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);\n>  \tif (!branch || branch->type != OBJ_COMMIT)\n> @@ -188,6 +225,9 @@ static void shortlog(const char *name, unsigned char *sha1,\n>  \telse\n>  \t\tstrbuf_addf(out, \"\\n* %s:\\n\", name);\n>  \n> +\tif (origin_data->is_local_branch && use_branch_desc)\n> +\t\tadd_branch_desc(out, name);\n> +\n>  \tfor (i = 0; i < subjects.nr; i++)\n>  \t\tif (i >= limit)\n>  \t\t\tstrbuf_addf(out, \"  ...\\n\");\n> @@ -303,8 +343,9 @@ static int do_fmt_merge_msg(int merge_title, struct strbuf *in,\n>  \t\t\tstrbuf_addch(out, '\\n');\n>  \n>  \t\tfor (i = 0; i < origins.nr; i++)\n> -\t\t\tshortlog(origins.items[i].string, origins.items[i].util,\n> -\t\t\t\t\thead, &rev, shortlog_len, out);\n> +\t\t\tshortlog(origins.items[i].string,\n> +\t\t\t\t origins.items[i].util,\n> +\t\t\t\t head, &rev, shortlog_len, out);\n>  \t}\n>  \treturn 0;\n>  }\n> diff --git a/builtin/merge.c b/builtin/merge.c\n> index ab4077f..fe56aad 100644\n> --- a/builtin/merge.c\n> +++ b/builtin/merge.c\n> @@ -26,6 +26,7 @@\n>  #include \"merge-recursive.h\"\n>  #include \"resolve-undo.h\"\n>  #include \"remote.h\"\n> +#include \"fmt-merge-msg.h\"\n>  \n>  #define DEFAULT_TWOHEAD (1<<0)\n>  #define DEFAULT_OCTOPUS (1<<1)\n> @@ -525,6 +526,8 @@ static void parse_branch_merge_options(char *bmo)\n>  \n>  static int git_merge_config(const char *k, const char *v, void *cb)\n>  {\n> +\tint status;\n> +\n>  \tif (branch && !prefixcmp(k, \"branch.\") &&\n>  \t\t!prefixcmp(k + 7, branch) &&\n>  \t\t!strcmp(k + 7 + strlen(branch), \".mergeoptions\")) {\n> @@ -541,15 +544,7 @@ static int git_merge_config(const char *k, const char *v, void *cb)\n>  \t\treturn git_config_string(&pull_octopus, k, v);\n>  \telse if (!strcmp(k, \"merge.renormalize\"))\n>  \t\toption_renormalize = git_config_bool(k, v);\n> -\telse if (!strcmp(k, \"merge.log\") || !strcmp(k, \"merge.summary\")) {\n> -\t\tint is_bool;\n> -\t\tshortlog_len = git_config_bool_or_int(k, v, &is_bool);\n> -\t\tif (!is_bool && shortlog_len < 0)\n> -\t\t\treturn error(_(\"%s: negative length %s\"), k, v);\n> -\t\tif (is_bool && shortlog_len)\n> -\t\t\tshortlog_len = DEFAULT_MERGE_LOG_LEN;\n> -\t\treturn 0;\n> -\t} else if (!strcmp(k, \"merge.ff\")) {\n> +\telse if (!strcmp(k, \"merge.ff\")) {\n>  \t\tint boolval = git_config_maybe_bool(k, v);\n>  \t\tif (0 <= boolval) {\n>  \t\t\tallow_fast_forward = boolval;\n> @@ -562,6 +557,9 @@ static int git_merge_config(const char *k, const char *v, void *cb)\n>  \t\tdefault_to_upstream = git_config_bool(k, v);\n>  \t\treturn 0;\n>  \t}\n> +\tstatus = fmt_merge_msg_config(k, v, cb);\n> +\tif (status)\n> +\t\treturn status;\n>  \treturn git_diff_ui_config(k, v, cb);\n>  }\n>  \n> diff --git a/fmt-merge-msg.h b/fmt-merge-msg.h\n> new file mode 100644\n> index 0000000..9217fdb\n> --- /dev/null\n> +++ b/fmt-merge-msg.h\n> @@ -0,0 +1,6 @@\n> +#ifndef FMT_MERGE_MSG_H\n> +#define FMT_MERGE_MSG_H\n> +\n> +extern int fmt_merge_msg_config(const char *key, const char *value, void *cb);\n> +\n> +#endif /* FMT_MERGE_MSG_H */\n"},{"id":"177147","messageId":"20111007091636.GA22822@elie.hsd1.il.comcast.net","threadId":"28620","inReplyTo":"4E8EBDA7.2040007@drmicha.warpmail.net","subject":"Re: [PATCH] fmt-merge-msg: use branch.$name.description","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-10-07T09:16:36Z","receivedAt":"2011-10-07T09:16:36Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Michael J Gruber wrote:\n\n> config based is so non-distributed, local in nature.\n\nI don't follow.  Wouldn't a protocol change be enough to fix that, by\nsharing branch descriptions analagously to how refs themselves are\nshared?\n"},{"id":"177148","messageId":"4E8ECA25.205@drmicha.warpmail.net","threadId":"28620","inReplyTo":"20111007091636.GA22822@elie.hsd1.il.comcast.net","subject":"Re: [PATCH] fmt-merge-msg: use branch.$name.description","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-10-07T09:45:09Z","receivedAt":"2011-10-07T09:45:09Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Jonathan Nieder venit, vidit, dixit 07.10.2011 11:16:\n> Michael J Gruber wrote:\n> \n>> config based is so non-distributed, local in nature.\n> \n> I don't follow.  Wouldn't a protocol change be enough to fix that, by\n> sharing branch descriptions analagously to how refs themselves are\n> shared?\n\nI'd be surprised if we changed the protocol just to be able to share\nsome descriptions, when we have everything we need for sharing refs.\nAlso note that config is non-versioned etc.\n\nBut my main point here is that we should discuss the pros and cons of\neach approach in context (the context of the original thread), and I\nhaven't heard many pros and cons for either.\n\nMichael\n"},{"id":"177149","messageId":"20111007100646.GA23193@elie.hsd1.il.comcast.net","threadId":"28620","inReplyTo":"4E8ECA25.205@drmicha.warpmail.net","subject":"Re: [PATCH] fmt-merge-msg: use branch.$name.description","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-10-07T10:06:46Z","receivedAt":"2011-10-07T10:06:46Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Michael J Gruber wrote:\n\n> But my main point here is that we should discuss the pros and cons of\n> each approach in context (the context of the original thread), and I\n> haven't heard many pros and cons for either.\n\nOk, here are some thoughts (you can file them under the \"pro\" or \"con\"\ncolumn according to your taste):\n\nBranch names are local.\n\nThe same tip commit can belong to multiple branches, which would make\nusing the tip commit as a key for the branch description problematic.\nI don't think git notes are a good fit for this purpose.\n\nI personally would prefer my branch descriptions to be non-versioned,\nthough I realize that is a matter of taste.\n\nSome other information about a branch (such as which upstream branch\nit pulls from) is stored in the [branch \"<branchname>\"] section of the\ngit configuration, so it makes a certain kind of sense to put the\nbranch description there, too.  On the other hand, the possibility of\na [branch \"<branchname>\"] section in ~/.gitconfig has always been\nstrange, and this is no exception.\n\n> I'd be surprised if we changed the protocol just to be able to share\n> some descriptions, when we have everything we need for sharing refs.\n\nThe impact of such a protocol change would not have to be as dramatic\nas you seem to be suggesting.  Virtual hosts and peeled ref values\nwere added as backward-compatible extensions to the reference\ndiscovery protocol (see Documentation/technical/pack-protocol.txt)\nwhich can be taken as examples for inspiration.\n\nHere's some discussion of the implementation based on branchname-keyed\nnotes that you mentioned [1].  It is nice to have multiple designs\navailable for trying out, and I hope experience using each reveals\npotential improvements in the other.\n\n[1] http://thread.gmane.org/gmane.comp.version-control.git/181953/focus=182000\n"},{"id":"177151","messageId":"4E8EED39.1060607@drmicha.warpmail.net","threadId":"28620","inReplyTo":"20111007100646.GA23193@elie.hsd1.il.comcast.net","subject":"Re: [PATCH] fmt-merge-msg: use branch.$name.description","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-10-07T12:14:49Z","receivedAt":"2011-10-07T12:14:49Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Jonathan Nieder venit, vidit, dixit 07.10.2011 12:06:\n> Michael J Gruber wrote:\n> \n>> But my main point here is that we should discuss the pros and cons of\n>> each approach in context (the context of the original thread), and I\n>> haven't heard many pros and cons for either.\n> \n> Ok, here are some thoughts (you can file them under the \"pro\" or \"con\"\n> column according to your taste):\n> \n> Branch names are local.\n\nYou can pull a branch only if you know its name, or using a wildcard\nrefspec. In both cases you know the translation from what is local on\nthe other side to your side. In the vast majority it will be the simple\nrefs/heads/foo -> refs/remotes/bar/foo mapping.\n\n> The same tip commit can belong to multiple branches, which would make\n> using the tip commit as a key for the branch description problematic.\n\nSure, tip commit is a no-go.\n\nThat's why I propose notes tacked onto refnames.\n\n> I don't think git notes are a good fit for this purpose.\n\nWhy not?\n\nI really haven't seen any convincing argument against yet. The details\n(note attached to refname object, or literal refanmes in the notes tree\nas per Jeff) should be discussed further, of course, but if branch\ndescriptions aren't \"notesy\" then I don't know what is.\n\nAlternatively, one could store the description in a blob and refer to\nthat directly, of course. I.e., have\n\nrefs/description/foo\n\npoint to a blob whose content is the description of the ref\n\nref/foo\n\nThat would be unversioned, and one could decide more easily which\ndescriptions to share. (A notes tree you either push or don't.)\n\nBut it still has the advantage of being easily pushable and shareable.\nHeck, config is config and not metadata ;)\n\n> I personally would prefer my branch descriptions to be non-versioned,\n> though I realize that is a matter of taste.\n\nDo you prefer you commit notes to be non-versioned? Probably, but still\nthey are, and you don't need to care. Just don't run log on your notes ref.\n\n> Some other information about a branch (such as which upstream branch\n> it pulls from) is stored in the [branch \"<branchname>\"] section of the\n> git configuration, so it makes a certain kind of sense to put the\n> branch description there, too.  On the other hand, the possibility of\n> a [branch \"<branchname>\"] section in ~/.gitconfig has always been\n> strange, and this is no exception.\n\nNote that most use cases for branch descriptions that have been\ndescribed so far (format-patch cover-letter, merge-msg, pull-request\nmessage) are about distributing that information. Not very local.\n\n>> I'd be surprised if we changed the protocol just to be able to share\n>> some descriptions, when we have everything we need for sharing refs.\n> \n> The impact of such a protocol change would not have to be as dramatic\n> as you seem to be suggesting.  Virtual hosts and peeled ref values\n> were added as backward-compatible extensions to the reference\n> discovery protocol (see Documentation/technical/pack-protocol.txt)\n> which can be taken as examples for inspiration.\n\nI don't see how a protocol change could solve the perceived issue with\nlocalality of name, and indeed what it could solve that can't be solved\nwith existing methods.\n\n> Here's some discussion of the implementation based on branchname-keyed\n> notes that you mentioned [1].  It is nice to have multiple designs\n> available for trying out, and I hope experience using each reveals\n> potential improvements in the other.\n> \n> [1] http://thread.gmane.org/gmane.comp.version-control.git/181953/focus=182000\n\nFunny to point me at a thread I participated in, when I'm saying this\nthread should have continued there ;)\n\nMichael\n"},{"id":"177177","messageId":"20111007195023.GA29712@elie.hsd1.il.comcast.net","threadId":"28620","inReplyTo":"4E8EED39.1060607@drmicha.warpmail.net","subject":"Re: [PATCH] fmt-merge-msg: use branch.$name.description","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-10-07T19:50:23Z","receivedAt":"2011-10-07T19:50:23Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Michael J Gruber wrote:\n> Jonathan Nieder venit, vidit, dixit 07.10.2011 12:06:\n\n>> [1] http://thread.gmane.org/gmane.comp.version-control.git/181953/focus=182000\n>\n> Funny to point me at a thread I participated in, when I'm saying this\n> thread should have continued there ;)\n\nAh, sorry, I wasn't trying to initiate a debate.  I provided the\npointer to save time for others who haven't looked up the thread\nyou were referring to yet.\n\nI am surprised that you seem to have missed what I meant by \"branch\nnames are local\".  I meant that what I call \"master\" is likely to be\nvery different from what you call \"master\".  Yes, we share commits and\nfetch them from each other, and I might even _decide_ that what I call\n\"master\" will be similar to what you call \"master\".  Luckily, in\npractice people don't seem to feel constrained to decide so, and there\nare many workflows where my \"master\" is not your \"master\" and does not\neven contain commits that would be acceptable for your \"master\".\n\nThis matters, a lot, because there is no easy way to partition a\nnamespace of names descriptive for humans without a central authority\nto negotiate conflicts.\n"},{"id":"177178","messageId":"7v1uuovahm.fsf@alter.siamese.dyndns.org","threadId":"28620","inReplyTo":"20111007195023.GA29712@elie.hsd1.il.comcast.net","subject":"Re: [PATCH] fmt-merge-msg: use branch.$name.description","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-10-07T19:59:33Z","receivedAt":"2011-10-07T19:59:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> I am surprised that you seem to have missed what I meant by \"branch\n> names are local\"....\n> This matters, a lot, because there is no easy way to partition a\n> namespace of names descriptive for humans without a central authority\n> to negotiate conflicts.\n\nI think we are in total agreement.  The branch names are local, but the\nusers may want to annotate to describe _the history_ they intend to build\non it.\n\nVarious ways to convey the description when the end product (i.e. the\nhistory built on it) is shiped were outlined in the series, so that the\nshipper can help the receiver understand the history. The information in\nthe annotation (i.e. the _value_ of branch.$name.description) is something\nthe shipper wants to share with the receiver, but the mapping between the\nlocal name of the branch the shipper used to build that history (i.e. the\nkey \"$name\" in branch.$name.description) is immaterial in the end result.\n\nI do not think there is much more for me to add to this topic, as I think\nyou covered all the important bases already.\n"},{"id":"177180","messageId":"20111007201244.GB29712@elie.hsd1.il.comcast.net","threadId":"28620","inReplyTo":"4E8EED39.1060607@drmicha.warpmail.net","subject":"Re: [PATCH] fmt-merge-msg: use branch.$name.description","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-10-07T20:12:44Z","receivedAt":"2011-10-07T20:12:44Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi again,\n\nMichael J Gruber wrote:\n\n> I really haven't seen any convincing argument against yet. The details\n> (note attached to refname object, or literal refanmes in the notes tree\n> as per Jeff) should be discussed further, of course, but if branch\n> descriptions aren't \"notesy\" then I don't know what is.\n\nAs mentioned before, I don't want to debate how Junio should spend his\ntime (better for each person to provide relevant information and\nimprovements to help out or to spend time on the alternatives one is\ninterested in), but as a general question, this statement looked\ninteresting to me.\n\n\"git notes\" has a funny name, but deep down, as you know, it's about\nattaching additional versioned text to commit objects without changing\ntheir names.  Branch descriptions are not per commit object (and as a\nmapping, the _keys_ are not shared), and personally I don't think they\nshould be versioned any more than the branch names are.\n\nI wanted to emphasize this because\n\n\t\"git notes\" is not the best tool for all annotations!\n\nThis ends this public service announcement.\n\n> Alternatively, one could store the description in a blob and refer to\n> that directly, of course. I.e., have\n>\n> refs/description/foo\n>\n> point to a blob whose content is the description of the ref\n>\n> ref/foo\n\nSure, that would be a sane alternative design.  It has the advantage\nof having the pumbing for fetching and pulling already set up, as you\nmention.  The only disadvantages I know of are\n\n - \"git branch -m\" and \"git remote rename\" don't know about it yet\n - there's not one flat file you can edit to run a search/replace on\n   all branch descriptions\n\nand those aren't very serious problems.\n\n>> I personally would prefer my branch descriptions to be non-versioned,\n>> though I realize that is a matter of taste.\n>\n> Do you prefer you commit notes to be non-versioned?\n\nNo, I like them versioned.  If I didn't, why wouldn't I have sent a\npatch to change that?  Maybe some day there will be a \"git notes log\"\ntool to track the history of a note, taking changes in fanout into\naccount.\n\nHope that clarifies a little.\n"},{"id":"177185","messageId":"4E8F63BC.1060401@drmicha.warpmail.net","threadId":"28620","inReplyTo":"7v1uuovahm.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] fmt-merge-msg: use branch.$name.description","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-10-07T20:40:28Z","receivedAt":"2011-10-07T20:40:28Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Junio C Hamano venit, vidit, dixit 07.10.2011 21:59:\n> Jonathan Nieder <jrnieder@gmail.com> writes:\n> \n>> I am surprised that you seem to have missed what I meant by \"branch\n>> names are local\"....\n>> This matters, a lot, because there is no easy way to partition a\n>> namespace of names descriptive for humans without a central authority\n>> to negotiate conflicts.\n> \n> I think we are in total agreement.  The branch names are local, but the\n> users may want to annotate to describe _the history_ they intend to build\n> on it.\n> \n> Various ways to convey the description when the end product (i.e. the\n> history built on it) is shiped were outlined in the series, so that the\n> shipper can help the receiver understand the history. The information in\n> the annotation (i.e. the _value_ of branch.$name.description) is something\n> the shipper wants to share with the receiver, but the mapping between the\n> local name of the branch the shipper used to build that history (i.e. the\n> key \"$name\" in branch.$name.description) is immaterial in the end result.\n\nIt just seems we judge the \"local\" aspect completely differently. The\npoint that I don't get is: How to share a branch without sharing a\nbranch name? You cannot. Of course you may \"change the name\" during the\npush, or during a fetch, and at that point you know both and can map the\ndescription.\n\nNote that I'm not tied to the notes implementation. But versioned branch\ndescriptions would be nice for several purposes, for example series\ncover letters, or descriptions on long lived feature branches. And I\ndon't see how else to have versioned descriptions.\n\nAlso, for transporting descriptions via config, you have to have an\nupdated git on the server side, whereas anything object/ref based would\nwork now, right?\n\nMichael\n"},{"id":"177186","messageId":"7vobxstt4w.fsf@alter.siamese.dyndns.org","threadId":"28620","inReplyTo":"4E8EED39.1060607@drmicha.warpmail.net","subject":"Re: [PATCH] fmt-merge-msg: use branch.$name.description","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-10-07T20:59:43Z","receivedAt":"2011-10-07T20:59:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael J Gruber <git@drmicha.warpmail.net> writes:\n\n> Alternatively, one could store the description in a blob and refer to\n> that directly, of course. I.e., have\n>\n> refs/description/foo\n>\n> point to a blob whose content is the description of the ref\n>\n> ref/foo\n>\n> That would be unversioned, and one could decide more easily which\n> descriptions to share. (A notes tree you either push or don't.)\n\nIf refs/descriptions/foo were to point at a commit object and its commit\nlog message is used to store the description you could make it versioned.\n\nA history that records forest of descriptions where its commit contains a\ntree whose leaves are branch names is slightly better than notes based\napproach in that it does not have to violate \"notes are for objects\"\ndesign principle, but it shares the same \"branch names are local\" issue as\nyour \"lone refs/description/foo describes 'foo' and 'foo' only\".\n\nIn addition, it shares with the notes based approach that exchanging a\ndescription on a single branch will inevitably pull in descriptions of all\nthe other branches you happen to have in the forest, which was one of the\nreasons that recording \"push -s\" certificates in notes tree failed whether\nthe v2 or v3 approach was used.\n\nYou should be able to make a few changes to jc/request-pull-show-head-4 to\nmove the description to such a \"refs/desc/$name\" from completely local\n\"branch.$name.description\". The machinery to edit the description is\nlocalized to edit_branch_description() introduced in b7200e8 (branch:\nteach --edit-description option, 2011-09-20), and the machinery to read\nthe description is localized to read_branch_desc() in 6f9a332 (branch: add\nread_branch_desc() helper function, 2011-09-21); the remainder of the\nseries could be used unmodified.\n\nBut it remains that any of these approaches assume branch names are\nuniversal. Unlike other systems, what we call branches do not have their\nown identity, so if you really want to go that route (and we _might_ need\nto in the longer term, but I am not convinced at this point yet), you\nwould first need to define how that local namespace would look like, how\npeople interact with it, etc. It might be just the matter of declaring a\nconvention e.g. \"Among people who meet at this central repository,\neverybody must map the branches identically to their local branch\nnamespace, and all sharing must go through the central repository\", and\ncalling a tuple <central repository URL, branch name in that repository>\nwith a name that cannot be confused with \"branch\" (so \"remote branch\" is\nout), such as \"(development) track\".\n"},{"id":"177205","messageId":"m3mxdc1hek.fsf@localhost.localdomain","threadId":"28620","inReplyTo":"7vobxstt4w.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] fmt-merge-msg: use branch.$name.description","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2011-10-08T00:01:35Z","receivedAt":"2011-10-08T00:01:35Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n> Michael J Gruber <git@drmicha.warpmail.net> writes:\n> \n> > Alternatively, one could store the description in a blob and refer to\n> > that directly, of course. I.e., have\n> >\n> > refs/description/foo\n> >\n> > point to a blob whose content is the description of the ref\n> >\n> > ref/foo\n> >\n> > That would be unversioned, and one could decide more easily which\n> > descriptions to share. (A notes tree you either push or don't.)\n[...]\n\n> But it remains that any of these approaches assume branch names are\n> universal. Unlike other systems, what we call branches do not have their\n> own identity, so if you really want to go that route (and we _might_ need\n> to in the longer term, but I am not convinced at this point yet), you\n> would first need to define how that local namespace would look like, how\n> people interact with it, etc. It might be just the matter of declaring a\n> convention e.g. \"Among people who meet at this central repository,\n> everybody must map the branches identically to their local branch\n> namespace, and all sharing must go through the central repository\", and\n> calling a tuple <central repository URL, branch name in that repository>\n> with a name that cannot be confused with \"branch\" (so \"remote branch\" is\n> out), such as \"(development) track\".\n\nWell, git could by default imply that 'refs/heads/*:refs/remotes/foo/*'\nimplies 'refs/description/*:refs/remote-descriptions/foo/*'...\n\n...one more argument for hierarchical remote-tracking refs namespace,\ni.e. 'refs/remotes/foo/refs/heads/*', and not current 'refs/remotes/foo/*'\n\nJust my 3 eurocents^W groszy.\n-- \nJakub Narębski\n"}]}