{"thread":{"id":"24081","subject":"[WIP PATCH 2/3] add missing && to submodule-merge testcase","startedAt":"2010-06-11T12:23:30Z","lastAt":"2010-06-23T07:38:28Z","messageCount":32,"participants":["Heiko Voigt","Johan Herland","Jens Lehmann","Junio C Hamano","Finn Arne Gangstad"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"143503","messageId":"cover.1276059473.git.hvoigt@hvoigt.net","threadId":"24081","inReplyTo":null,"subject":"[WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Heiko Voigt","fromEmail":"hvoigt@hvoigt.net","sentAt":"2010-06-11T12:23:30Z","receivedAt":"2010-06-11T12:23:30Z","isPatch":true,"sender":{"key":"hvoigt@hvoigt.net","avatar":"https://avatars.githubusercontent.com/u/184958?v=4"},"body":"The following patch series is a work in progress. The idea is whenever\nyou need to merge two SHA1's of a submodule we search for a ref in the\nsubmodule which already contains both. If one such ref exists the\nresulting SHA1 is the one pointed at by that ref.\n\nThe implementation currently searches through all refs and if one (and\nonly one) ref exists which contains both sides it merges. In all other\ncases it fails.\n\nFuture Plans:\n\n  * Only search stable branches. E.g. by default only master and\n    */master. The stable branch list will be configurable.\n\n  * Use read_gitfile_gently for submodule .git handling\n\n  * Use strbuf in git_path_submodule\n\nFurther comments or ideas?\n\nThe series can also be found on github:\n\nhttp://github.com/hvoigt/git/tree/hv/submodule_merge\n\ncheers Heiko\n\nHeiko Voigt (3):\n  extend ref iteration for submodules\n  add missing && to submodule-merge testcase\n  implement automatic fast forward merge for submodules\n\n cache.h                    |    3 +\n merge-recursive.c          |    9 ++-\n path.c                     |   21 ++++++++\n refs.c                     |   89 +++++++++++++++++++++++---------\n refs.h                     |    2 +\n submodule.c                |  121 ++++++++++++++++++++++++++++++++++++++++++++\n submodule.h                |    2 +\n t/t7405-submodule-merge.sh |  117 ++++++++++++++++++++++++++++++++++++++++---\n 8 files changed, 328 insertions(+), 36 deletions(-)\n"},{"id":"143502","messageId":"7990743852d1482e0f42daaa69a0a1a98a73402a.1276059473.git.hvoigt@hvoigt.net","threadId":"24081","inReplyTo":"cover.1276059473.git.hvoigt@hvoigt.net","subject":"[WIP PATCH 1/3] extend ref iteration for submodules","fromName":"Heiko Voigt","fromEmail":"hvoigt@hvoigt.net","sentAt":"2010-06-11T12:23:31Z","receivedAt":"2010-06-11T12:23:31Z","isPatch":true,"sender":{"key":"hvoigt@hvoigt.net","avatar":"https://avatars.githubusercontent.com/u/184958?v=4"},"body":"This is useful to interrogate a submodule from the main repository.\n\nSigned-off-by: Heiko Voigt <hvoigt@hvoigt.net>\n---\n cache.h |    3 ++\n path.c  |   21 +++++++++++++++\n refs.c  |   89 ++++++++++++++++++++++++++++++++++++++++++++------------------\n refs.h  |    2 +\n 4 files changed, 89 insertions(+), 26 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex c966023..daae839 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -621,6 +621,9 @@ extern char *git_pathdup(const char *fmt, ...)\n /* Return a statically allocated filename matching the sha1 signature */\n extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\n extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\n+extern char *git_path_submodule(const char *path, const char *fmt, ...)\n+\t__attribute__((format (printf, 2, 3)));\n+\n extern char *sha1_file_name(const unsigned char *sha1);\n extern char *sha1_pack_name(const unsigned char *sha1);\n extern char *sha1_pack_index_name(const unsigned char *sha1);\ndiff --git a/path.c b/path.c\nindex b4c8d91..47118bc 100644\n--- a/path.c\n+++ b/path.c\n@@ -122,6 +122,27 @@ char *git_path(const char *fmt, ...)\n \treturn cleanup_path(pathname);\n }\n \n+char *git_path_submodule(const char *path, const char *fmt, ...)\n+{\n+\tchar *pathname = get_pathname();\n+\tva_list args;\n+\tunsigned len;\n+\n+\tlen = strlen(path);\n+\tif (len > PATH_MAX-100)\n+\t\treturn bad_path;\n+\tmemcpy(pathname, path, len);\n+\tif (len && path[len-1] != '/')\n+\t\tpathname[len++] = '/';\n+\tmemcpy(pathname + len, \".git/\", 5);\n+\tlen += 5;\n+\tva_start(args, fmt);\n+\tlen += vsnprintf(pathname + len, PATH_MAX - len, fmt, args);\n+\tva_end(args);\n+\tif (len >= PATH_MAX)\n+\t\treturn bad_path;\n+\treturn cleanup_path(pathname);\n+}\n \n /* git_mkstemp() - create tmp file honoring TMPDIR variable */\n int git_mkstemp(char *path, size_t len, const char *template)\ndiff --git a/refs.c b/refs.c\nindex d3db15a..eed8a29 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -157,6 +157,7 @@ static struct cached_refs {\n \tchar did_packed;\n \tstruct ref_list *loose;\n \tstruct ref_list *packed;\n+\tconst char *submodule;\n } cached_refs;\n static struct ref_list *current_ref;\n \n@@ -229,10 +230,17 @@ void clear_extra_refs(void)\n \textra_refs = NULL;\n }\n \n-static struct ref_list *get_packed_refs(void)\n+static struct ref_list *get_packed_refs(const char *submodule)\n {\n+\tconst char *packed_refs_file;\n+\n+\tif (submodule)\n+\t\tpacked_refs_file = git_path_submodule(submodule, \"packed-refs\");\n+\telse\n+\t\tpacked_refs_file = git_path(\"packed-refs\");\n+\n \tif (!cached_refs.did_packed) {\n-\t\tFILE *f = fopen(git_path(\"packed-refs\"), \"r\");\n+\t\tFILE *f = fopen(packed_refs_file, \"r\");\n \t\tcached_refs.packed = NULL;\n \t\tif (f) {\n \t\t\tread_packed_refs(f, &cached_refs);\n@@ -243,9 +251,19 @@ static struct ref_list *get_packed_refs(void)\n \treturn cached_refs.packed;\n }\n \n-static struct ref_list *get_ref_dir(const char *base, struct ref_list *list)\n+static struct ref_list *get_ref_dir(const char *submodule, const char *base,\n+\t\t\t\t    struct ref_list *list)\n {\n-\tDIR *dir = opendir(git_path(\"%s\", base));\n+\tDIR *dir;\n+\tconst char *path;\n+\n+\tif (submodule)\n+\t\tpath = git_path_submodule(submodule, \"%s\", base);\n+\telse\n+\t\tpath = git_path(\"%s\", base);\n+\n+\n+\tdir = opendir(path);\n \n \tif (dir) {\n \t\tstruct dirent *de;\n@@ -261,6 +279,7 @@ static struct ref_list *get_ref_dir(const char *base, struct ref_list *list)\n \t\t\tstruct stat st;\n \t\t\tint flag;\n \t\t\tint namelen;\n+\t\t\tconst char *refdir;\n \n \t\t\tif (de->d_name[0] == '.')\n \t\t\t\tcontinue;\n@@ -270,16 +289,27 @@ static struct ref_list *get_ref_dir(const char *base, struct ref_list *list)\n \t\t\tif (has_extension(de->d_name, \".lock\"))\n \t\t\t\tcontinue;\n \t\t\tmemcpy(ref + baselen, de->d_name, namelen+1);\n-\t\t\tif (stat(git_path(\"%s\", ref), &st) < 0)\n+\t\t\trefdir = submodule\n+\t\t\t\t? git_path_submodule(submodule, \"%s\", ref)\n+\t\t\t\t: git_path(\"%s\", ref);\n+\t\t\tif (stat(refdir, &st) < 0)\n \t\t\t\tcontinue;\n \t\t\tif (S_ISDIR(st.st_mode)) {\n-\t\t\t\tlist = get_ref_dir(ref, list);\n+\t\t\t\tlist = get_ref_dir(submodule, ref, list);\n \t\t\t\tcontinue;\n \t\t\t}\n-\t\t\tif (!resolve_ref(ref, sha1, 1, &flag)) {\n+\t\t\tif (submodule) {\n \t\t\t\thashclr(sha1);\n-\t\t\t\tflag |= REF_BROKEN;\n-\t\t\t}\n+\t\t\t\tflag = 0;\n+\t\t\t\tif (!resolve_gitlink_ref(submodule, ref, sha1)) {\n+\t\t\t\t//\thashclr(sha1);\n+\t\t\t\t\tflag |= REF_BROKEN;\n+\t\t\t\t}\n+\t\t\t} else\n+\t\t\t\tif (!resolve_ref(ref, sha1, 1, &flag)) {\n+\t\t\t\t\thashclr(sha1);\n+\t\t\t\t\tflag |= REF_BROKEN;\n+\t\t\t\t}\n \t\t\tlist = add_ref(ref, sha1, flag, list, NULL);\n \t\t}\n \t\tfree(ref);\n@@ -318,11 +348,12 @@ void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)\n \tfor_each_rawref(warn_if_dangling_symref, &data);\n }\n \n-static struct ref_list *get_loose_refs(void)\n+static struct ref_list *get_loose_refs(const char *submodule)\n {\n-\tif (!cached_refs.did_loose) {\n-\t\tcached_refs.loose = get_ref_dir(\"refs\", NULL);\n+\tif (!cached_refs.did_loose || cached_refs.submodule != submodule) {\n+\t\tcached_refs.loose = get_ref_dir(submodule, \"refs\", NULL);\n \t\tcached_refs.did_loose = 1;\n+\t\tcached_refs.submodule = submodule;\n \t}\n \treturn cached_refs.loose;\n }\n@@ -455,7 +486,7 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *\n \t\tgit_snpath(path, sizeof(path), \"%s\", ref);\n \t\t/* Special case: non-existing file. */\n \t\tif (lstat(path, &st) < 0) {\n-\t\t\tstruct ref_list *list = get_packed_refs();\n+\t\t\tstruct ref_list *list = get_packed_refs(NULL);\n \t\t\twhile (list) {\n \t\t\t\tif (!strcmp(ref, list->name)) {\n \t\t\t\t\thashcpy(sha1, list->sha1);\n@@ -584,7 +615,7 @@ int peel_ref(const char *ref, unsigned char *sha1)\n \t\treturn -1;\n \n \tif ((flag & REF_ISPACKED)) {\n-\t\tstruct ref_list *list = get_packed_refs();\n+\t\tstruct ref_list *list = get_packed_refs(NULL);\n \n \t\twhile (list) {\n \t\t\tif (!strcmp(list->name, ref)) {\n@@ -611,12 +642,12 @@ fallback:\n \treturn -1;\n }\n \n-static int do_for_each_ref(const char *base, each_ref_fn fn, int trim,\n-\t\t\t   int flags, void *cb_data)\n+static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn fn,\n+\t\t\t   int trim, int flags, void *cb_data)\n {\n \tint retval = 0;\n-\tstruct ref_list *packed = get_packed_refs();\n-\tstruct ref_list *loose = get_loose_refs();\n+\tstruct ref_list *packed = get_packed_refs(submodule);\n+\tstruct ref_list *loose = get_loose_refs(submodule);\n \n \tstruct ref_list *extra;\n \n@@ -665,12 +696,12 @@ int head_ref(each_ref_fn fn, void *cb_data)\n \n int for_each_ref(each_ref_fn fn, void *cb_data)\n {\n-\treturn do_for_each_ref(\"refs/\", fn, 0, 0, cb_data);\n+\treturn do_for_each_ref(NULL, \"refs/\", fn, 0, 0, cb_data);\n }\n \n int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)\n {\n-\treturn do_for_each_ref(prefix, fn, strlen(prefix), 0, cb_data);\n+\treturn do_for_each_ref(NULL, prefix, fn, strlen(prefix), 0, cb_data);\n }\n \n int for_each_tag_ref(each_ref_fn fn, void *cb_data)\n@@ -690,7 +721,7 @@ int for_each_remote_ref(each_ref_fn fn, void *cb_data)\n \n int for_each_replace_ref(each_ref_fn fn, void *cb_data)\n {\n-\treturn do_for_each_ref(\"refs/replace/\", fn, 13, 0, cb_data);\n+\treturn do_for_each_ref(NULL, \"refs/replace/\", fn, 13, 0, cb_data);\n }\n \n int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,\n@@ -730,7 +761,13 @@ int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data)\n \n int for_each_rawref(each_ref_fn fn, void *cb_data)\n {\n-\treturn do_for_each_ref(\"refs/\", fn, 0,\n+\treturn do_for_each_ref(NULL, \"refs/\", fn, 0,\n+\t\t\t       DO_FOR_EACH_INCLUDE_BROKEN, cb_data);\n+}\n+\n+int for_each_rawref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n+{\n+\treturn do_for_each_ref(submodule, \"refs/\", fn, 0,\n \t\t\t       DO_FOR_EACH_INCLUDE_BROKEN, cb_data);\n }\n \n@@ -954,7 +991,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char\n \t * name is a proper prefix of our refname.\n \t */\n \tif (missing &&\n-\t     !is_refname_available(ref, NULL, get_packed_refs(), 0)) {\n+\t     !is_refname_available(ref, NULL, get_packed_refs(NULL), 0)) {\n \t\tlast_errno = ENOTDIR;\n \t\tgoto error_return;\n \t}\n@@ -1017,7 +1054,7 @@ static int repack_without_ref(const char *refname)\n \tint fd;\n \tint found = 0;\n \n-\tpacked_ref_list = get_packed_refs();\n+\tpacked_ref_list = get_packed_refs(NULL);\n \tfor (list = packed_ref_list; list; list = list->next) {\n \t\tif (!strcmp(refname, list->name)) {\n \t\t\tfound = 1;\n@@ -1106,10 +1143,10 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)\n \tif (!symref)\n \t\treturn error(\"refname %s not found\", oldref);\n \n-\tif (!is_refname_available(newref, oldref, get_packed_refs(), 0))\n+\tif (!is_refname_available(newref, oldref, get_packed_refs(NULL), 0))\n \t\treturn 1;\n \n-\tif (!is_refname_available(newref, oldref, get_loose_refs(), 0))\n+\tif (!is_refname_available(newref, oldref, get_loose_refs(NULL), 0))\n \t\treturn 1;\n \n \tlock = lock_ref_sha1_basic(renamed_ref, NULL, 0, NULL);\ndiff --git a/refs.h b/refs.h\nindex 4a18b08..384e311 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -35,6 +35,8 @@ static inline const char *has_glob_specials(const char *pattern)\n \n /* can be used to learn about broken ref and symref */\n extern int for_each_rawref(each_ref_fn, void *);\n+extern int for_each_rawref_submodule(const char *path, each_ref_fn fn, void *cb_data);\n+\n \n extern void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname);\n \n-- \n1.7.1\n"},{"id":"143501","messageId":"640d97ddba4b842f9f268cabf92e0220e641f23f.1276059473.git.hvoigt@hvoigt.net","threadId":"24081","inReplyTo":"cover.1276059473.git.hvoigt@hvoigt.net","subject":"[WIP PATCH 2/3] add missing && to submodule-merge testcase","fromName":"Heiko Voigt","fromEmail":"hvoigt@hvoigt.net","sentAt":"2010-06-11T12:23:32Z","receivedAt":"2010-06-11T12:23:32Z","isPatch":true,"sender":{"key":"hvoigt@hvoigt.net","avatar":"https://avatars.githubusercontent.com/u/184958?v=4"},"body":"Signed-off-by: Heiko Voigt <hvoigt@hvoigt.net>\n---\n t/t7405-submodule-merge.sh |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/t/t7405-submodule-merge.sh b/t/t7405-submodule-merge.sh\nindex 9a21f78..4a7b893 100755\n--- a/t/t7405-submodule-merge.sh\n+++ b/t/t7405-submodule-merge.sh\n@@ -45,7 +45,7 @@ test_expect_success setup '\n \t git commit -m sub-b) &&\n \tgit add sub &&\n \ttest_tick &&\n-\tgit commit -m b\n+\tgit commit -m b &&\n \n \tgit checkout -b c a &&\n \tgit merge -s ours b &&\n-- \n1.7.1\n"},{"id":"143504","messageId":"20859813382fcffe61d783fe561fae65998c1603.1276059473.git.hvoigt@hvoigt.net","threadId":"24081","inReplyTo":"cover.1276059473.git.hvoigt@hvoigt.net","subject":"[WIP PATCH 3/3] implement automatic fast forward merge for submodules","fromName":"Heiko Voigt","fromEmail":"hvoigt@hvoigt.net","sentAt":"2010-06-11T12:23:33Z","receivedAt":"2010-06-11T12:23:33Z","isPatch":true,"sender":{"key":"hvoigt@hvoigt.net","avatar":"https://avatars.githubusercontent.com/u/184958?v=4"},"body":"This implements a simple merge strategy for submodule hashes. We look\nwhether a single ref that contains both hashes exist. In case it does\nand the changes on both sides point forward in the direction of that\nref we return the refs revision as the merge result.\n\nIt is useful for a workflow in which the developers can publish topic\nbranches in submodules. Once the topic branch has been merged\ninto a stable branch the developer can simply merge his branch\nin the main repository even when other developers have merged their\nsubmodule changes before them.\n\nSigned-off-by: Heiko Voigt <hvoigt@hvoigt.net>\n---\n merge-recursive.c          |    9 ++-\n submodule.c                |  121 ++++++++++++++++++++++++++++++++++++++++++++\n submodule.h                |    2 +\n t/t7405-submodule-merge.sh |  115 +++++++++++++++++++++++++++++++++++++++--\n 4 files changed, 238 insertions(+), 9 deletions(-)\n\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 206c103..a032a8b 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -20,6 +20,7 @@\n #include \"attr.h\"\n #include \"merge-recursive.h\"\n #include \"dir.h\"\n+#include \"submodule.h\"\n \n static struct tree *shift_tree_object(struct tree *one, struct tree *two,\n \t\t\t\t      const char *subtree_shift)\n@@ -525,13 +526,15 @@ static void update_file_flags(struct merge_options *o,\n \t\tvoid *buf;\n \t\tunsigned long size;\n \n-\t\tif (S_ISGITLINK(mode))\n+\t\tif (S_ISGITLINK(mode)) {\n \t\t\t/*\n \t\t\t * We may later decide to recursively descend into\n \t\t\t * the submodule directory and update its index\n \t\t\t * and/or work tree, but we do not do that now.\n \t\t\t */\n+\t\t\tupdate_wd = 0;\n \t\t\tgoto update_index;\n+\t\t}\n \n \t\tbuf = read_sha1_file(sha, &type, &size);\n \t\tif (!buf)\n@@ -716,8 +719,8 @@ static struct merge_file_info merge_file(struct merge_options *o,\n \t\t\tfree(result_buf.ptr);\n \t\t\tresult.clean = (merge_status == 0);\n \t\t} else if (S_ISGITLINK(a->mode)) {\n-\t\t\tresult.clean = 0;\n-\t\t\thashcpy(result.sha, a->sha1);\n+\t\t\tresult.clean = merge_submodule(result.sha, one->path, one->sha1,\n+\t\t\t\t\t\t       a->sha1, b->sha1);\n \t\t} else if (S_ISLNK(a->mode)) {\n \t\t\thashcpy(result.sha, a->sha1);\n \ndiff --git a/submodule.c b/submodule.c\nindex 676d48f..5b0313f 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -6,6 +6,7 @@\n #include \"revision.h\"\n #include \"run-command.h\"\n #include \"diffcore.h\"\n+#include \"refs.h\"\n \n static int add_submodule_odb(const char *path)\n {\n@@ -205,3 +206,123 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)\n \tstrbuf_release(&buf);\n \treturn dirty_submodule;\n }\n+\n+struct parent_data {\n+\tstruct rev_info common_parents;\n+\tstruct commit *a;\n+\tstruct commit *b;\n+};\n+\n+static int add_common_parents(const char *refname, const unsigned char *sha1,\n+\t\t\t     int flags, void *cb_data)\n+{\n+\tstruct parent_data *args = (struct parent_data *) cb_data;\n+\tstruct commit *commit;\n+\n+\tcommit = lookup_commit_reference_gently(sha1, 1);\n+\tif (!commit)\n+\t\treturn error(\"branch '%s' does not point at a commit\", refname);\n+\n+\tif (!in_merge_bases(args->a, &commit, 1))\n+\t\treturn 0;\n+\tif (!in_merge_bases(args->b, &commit, 1))\n+\t\treturn 0;\n+\n+\tadd_pending_object(&args->common_parents,\n+\t\t\t(struct object *)commit, refname);\n+\n+\treturn 0;\n+}\n+\n+static int find_common_parent(unsigned char result[20], const char *path,\n+\t\t\t      struct commit *a, struct commit *b)\n+{\n+\tstruct parent_data parent_args;\n+\tstruct commit *commit;\n+\tunsigned char sha1[20];\n+\tint i, ret = 0;\n+\tstatic const char *format = \" %h: %m %s\";\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t/* search for parent revs of a and b */\n+\tinit_revisions(&parent_args.common_parents, NULL);\n+\tparent_args.common_parents.no_walk = 1;\n+\tparent_args.a = a;\n+\tparent_args.b = b;\n+\tfor_each_rawref_submodule(path, add_common_parents, &parent_args);\n+\n+\tif (prepare_revision_walk(&parent_args.common_parents))\n+\t\treturn 0;\n+\n+\ti = 0;\n+\twhile ((commit = get_revision(&parent_args.common_parents))) {\n+\t\tstruct pretty_print_context ctx = {0};\n+\t\tctx.date_mode = parent_args.common_parents.date_mode;\n+\t\tformat_commit_message(commit, format, &sb, &ctx);\n+\t\tstrbuf_addstr(&sb, \"\\n\");\n+\t\tif (i == 0)\n+\t\t\thashcpy(sha1, commit->object.sha1);\n+\t\ti++;\n+\t}\n+\n+\t/* we found exactly one revision */\n+\tif (i == 1) {\n+\t\thashcpy(result, sha1);\n+\t\tret = 1;\n+\t\tgoto finish;\n+\t}\n+\n+\twarning(\"Found multiple possible merge resolutions for submodule '%s':\", path);\n+\tfprintf(stderr, \"%s\", sb.buf);\n+\n+finish:\n+\tstrbuf_release(&sb);\n+\treturn ret;\n+}\n+\n+int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20],\n+\t\t    const unsigned char a[20], const unsigned char b[20])\n+{\n+\tstruct commit *commit_base, *commit_a, *commit_b;\n+\tint parent_exists;\n+\n+\t/* store a in result in case we fail */\n+\thashcpy(result, a);\n+\n+\t/* we can not handle deletion conflicts */\n+\tif (is_null_sha1(base))\n+\t\treturn 0;\n+\tif (is_null_sha1(a))\n+\t\treturn 0;\n+\tif (is_null_sha1(b))\n+\t\treturn 0;\n+\n+\tif (add_submodule_odb(path)) {\n+\t\twarning(\"Failed to merge submodule %s (not checked out)\", path);\n+\t\treturn 0;\n+\t}\n+\n+\tif (!(commit_base = lookup_commit_reference(base)) ||\n+\t    !(commit_a = lookup_commit_reference(a)) ||\n+\t    !(commit_b = lookup_commit_reference(b)))\n+\t{\n+\t\twarning(\"Failed to merge submodule %s (commits not present)\", path);\n+\t\treturn 0;\n+\t}\n+\n+\t/* are both changes forward */\n+\tif (!in_merge_bases(commit_base, &commit_a, 1) ||\n+\t    !in_merge_bases(commit_base, &commit_b, 1))\n+\t{\n+\t\twarning(\"Submodule rewound can not merge\");\n+\t\treturn 0;\n+\t}\n+\n+\t/* find commit which merges them */\n+\tparent_exists = find_common_parent(result, path, commit_a, commit_b);\n+\tif (!parent_exists) {\n+\t\twarning(\"Failed to merge submodule %s (merge not found)\", path);\n+\t\treturn 0;\n+\t}\n+\treturn 1;\n+}\ndiff --git a/submodule.h b/submodule.h\nindex dbda270..b75a704 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -6,5 +6,7 @@ void show_submodule_summary(FILE *f, const char *path,\n \t\tunsigned dirty_submodule,\n \t\tconst char *del, const char *add, const char *reset);\n unsigned is_submodule_modified(const char *path, int ignore_untracked);\n+int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20],\n+\t\t    const unsigned char a[20], const unsigned char b[20]);\n \n #endif\ndiff --git a/t/t7405-submodule-merge.sh b/t/t7405-submodule-merge.sh\nindex 4a7b893..04dc371 100755\n--- a/t/t7405-submodule-merge.sh\n+++ b/t/t7405-submodule-merge.sh\n@@ -54,13 +54,116 @@ test_expect_success setup '\n \tgit merge -s ours a\n '\n \n-test_expect_success 'merging with modify/modify conflict' '\n+# History setup\n+#\n+#      b\n+#    /   \\\n+#   a     d\n+#    \\   /\n+#      c\n+#\n+# a in the main repository records to sub-a in the submodule and\n+# analogous b and c. d should be automatically found by merging c into\n+# b in the main repository.\n+test_expect_success 'setup for merge search' '\n+\tmkdir merge-search &&\n+\tcd merge-search &&\n+\tgit init &&\n+\tmkdir sub &&\n+\t(cd sub &&\n+\t git init &&\n+\t echo \"file-a\" > file-a &&\n+\t git add file-a &&\n+\t git commit -m \"sub-a\" &&\n+\t git checkout -b sub-a) &&\n+\tgit add sub &&\n+\tgit commit -m \"a\" &&\n+\tgit checkout -b a &&\n+\n+\tgit checkout -b b &&\n+\t(cd sub &&\n+\t git checkout -b sub-b &&\n+\t echo \"file-b\" > file-b &&\n+\t git add file-b &&\n+\t git commit -m \"sub-b\") &&\n+\tgit commit -a -m \"b\" &&\n+\n+\tgit checkout -b c a &&\n+\t(cd sub &&\n+\t git checkout -b sub-c sub-a &&\n+\t echo \"file-c\" > file-c &&\n+\t git add file-c &&\n+\t git commit -m \"sub-c\") &&\n+\tgit commit -a -m \"c\" &&\n+\n+\t(cd sub &&\n+\t git checkout -b sub-d sub-b &&\n+\t git merge sub-c &&\n+\t git checkout sub-b) &&\n+\tgit checkout -b test b &&\n+\tcd ..\n+'\n+\n+test_expect_success 'merging with common parent search' '\n+\tcd merge-search &&\n+\tgit checkout -b test-parent b &&\n+\tgit merge c &&\n+\tgit ls-tree test-parent | grep sub | cut -f1 | cut -f3 -d\" \" > actual &&\n+\t(cd sub &&\n+\t git rev-parse sub-d > ../expect) &&\n+\ttest_cmp actual expect &&\n+\tcd ..\n+'\n+\n+test_expect_success 'merging should fail for ambigous common parent' '\n+\tcd merge-search &&\n+\tgit checkout -b test-ambigous b &&\n+\t(cd sub &&\n+\t git checkout -b ambigous sub-d &&\n+\t echo \"ambigous-file\" > ambigous-file &&\n+\t git add ambigous-file &&\n+\t git commit -m \"ambigous\") &&\n+\ttest_must_fail git merge c &&\n+\tgit reset --hard &&\n+\tcd ..\n+'\n+\n+# in a situation like this\n+#\n+# submodule tree:\n+#\n+#    sub-a --- sub-b --- sub-d\n+#\n+# main tree:\n+#\n+#    e (sub-a)\n+#   /\n+#  d (sub-b)\n+#   \\\n+#    f (sub-d)\n+#\n+# A merge should fail because one change points backwards.\n+\n+test_expect_success 'merging should fail for changes that are backwards' '\n+\tcd merge-search &&\n+\tgit checkout -b d a &&\n+\t(cd sub &&\n+\t git checkout sub-b) &&\n+\tgit commit -a -m \"d\" &&\n+\n+\tgit checkout -b e d &&\n+\t(cd sub &&\n+\t git checkout sub-a) &&\n+\tgit commit -a -m \"e\" &&\n+\n+\tgit checkout -b f d &&\n+\t(cd sub &&\n+\t git checkout sub-d) &&\n+\tgit commit -a -m \"f\" &&\n \n-\tgit checkout -b test1 a &&\n-\ttest_must_fail git merge b &&\n-\ttest -f .git/MERGE_MSG &&\n-\tgit diff &&\n-\ttest -n \"$(git ls-files -u)\"\n+\tgit checkout -b test-backward e &&\n+\ttest_must_fail git merge f &&\n+\tcd ..\n '\n \n test_expect_success 'merging with a modify/modify conflict between merge bases' '\n-- \n1.7.1\n"},{"id":"143564","messageId":"201006121212.50545.johan@herland.net","threadId":"24081","inReplyTo":"cover.1276059473.git.hvoigt@hvoigt.net","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-06-12T10:12:50Z","receivedAt":"2010-06-12T10:12:50Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Friday 11 June 2010, Heiko Voigt wrote:\n> The following patch series is a work in progress. The idea is whenever\n> you need to merge two SHA1's of a submodule we search for a ref in the\n> submodule which already contains both. If one such ref exists the\n> resulting SHA1 is the one pointed at by that ref.\n\nI appreciate the effort to improve submodule handling, but I'm not sure I \nlike this approach. Even though you try to apply it as conservatively as \npossible, it still smells a little like trying to make Git too clever for \nits own good.\n\nE.g. say we have the following commit history in the submodule:\n\n  A---B---C---D  <-- master\n\nNow, say that your merge conflict comes from one branch updating the \nsubmodule from B to C, while the other branch reverts the submodule from B \nto A. In your proposed scheme, Git would auto-resolve the conflict to D.\n\nIn this case Git has no way of knowing whether the update from B to C is \n\"better\" than the revert from B to A. Maybe the revert to A happened because \nthere is a showstopper bug in B that has not yet been fixed, and the best \nsolution is to revert to A until a fix can be made. Or maybe C fixes that \nshowstopper bug, so C is safe after all.\n\nIn any case, fast-forwarding to D seems irresponsible, since we have no \nconcept of how well D is tested. Maybe it introduces another showstopper \nbug, and that is why neither branch has upgraded to it yet?\n\nThis whole idea is somewhat similar to branch-tracking submodules (recently \ndiscussed in another thread), except that it only applies on _merge_ in the \nsuperproject, and you don't get to choose _which_ branch it's tracking. \nThat's _way_ too arbitrary for my tastes.\n\n> The implementation currently searches through all refs and if one (and\n> only one) ref exists which contains both sides it merges. In all other\n> cases it fails.\n\nStill doesn't solve the fundamental A---B---C---D problem I demonstrated \nabove.\n\n> Future Plans:\n> \n>   * Only search stable branches. E.g. by default only master and\n>     */master. The stable branch list will be configurable.\n\nWhat is this \"stable\" branch of which you speak? \"Stable\" is a very relative \nconcept, depending on which repo you're working in, and which branch you're \nworking on. In any case, master is often not the most stable branch in a \ngiven repo. In git.git for example, maint is more stable than master. Also, \nI have many repos where master should not be considered \"stable\" at all...\n\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"143566","messageId":"20100612120620.GA13910@book.hvoigt.net","threadId":"24081","inReplyTo":"201006121212.50545.johan@herland.net","subject":"Re: Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Heiko Voigt","fromEmail":"hvoigt@hvoigt.net","sentAt":"2010-06-12T12:06:20Z","receivedAt":"2010-06-12T12:06:20Z","isPatch":true,"sender":{"key":"hvoigt@hvoigt.net","avatar":"https://avatars.githubusercontent.com/u/184958?v=4"},"body":"Hi,\n\nOn Sat, Jun 12, 2010 at 12:12:50PM +0200, Johan Herland wrote:\n> On Friday 11 June 2010, Heiko Voigt wrote:\n> > The following patch series is a work in progress. The idea is whenever\n> > you need to merge two SHA1's of a submodule we search for a ref in the\n> > submodule which already contains both. If one such ref exists the\n> > resulting SHA1 is the one pointed at by that ref.\n> \n> I appreciate the effort to improve submodule handling, but I'm not sure I \n> like this approach. Even though you try to apply it as conservatively as \n> possible, it still smells a little like trying to make Git too clever for \n> its own good.\n> \n> E.g. say we have the following commit history in the submodule:\n> \n>   A---B---C---D  <-- master\n> \n> Now, say that your merge conflict comes from one branch updating the \n> submodule from B to C, while the other branch reverts the submodule from B \n> to A. In your proposed scheme, Git would auto-resolve the conflict to D.\n\nYou are right. I did forget to mention this in my topic letter: Both\nchanges need to point forward. This exact case is also tested in the\ntestcases and results in a merge conflict which needs to be resolved by\nhand.\n\n> This whole idea is somewhat similar to branch-tracking submodules (recently \n> discussed in another thread), except that it only applies on _merge_ in the \n> superproject, and you don't get to choose _which_ branch it's tracking. \n> That's _way_ too arbitrary for my tastes.\n\nThe difference to branch-tracking submodules is, if I understand it\ncorrectly, that with a merge you get an explicit SHA1 which is recorded.\nWhereras with branch-tracking you never know on which revision on the\ntracked branch the submodule was.\n\nThats why I only want to search through stable branches further down. I\nmean stable in the git sense that they never get rewound and of course\nshould contain the most stable part of development. To ease the\nconfiguration we would default to master which we could assume as\nstable. But if we want to be on the safe side we could also say that\nautomatic submodule merging only works when the user has configured some\nstable branches.\n\n> > Future Plans:\n> > \n> >   * Only search stable branches. E.g. by default only master and\n> >     */master. The stable branch list will be configurable.\n> \n> What is this \"stable\" branch of which you speak? \"Stable\" is a very relative \n> concept, depending on which repo you're working in, and which branch you're \n> working on. In any case, master is often not the most stable branch in a \n> given repo. In git.git for example, maint is more stable than master. Also, \n> I have many repos where master should not be considered \"stable\" at all...\n\nSee above.\n\ncheers Heiko\n"},{"id":"143617","messageId":"201006131959.43356.johan@herland.net","threadId":"24081","inReplyTo":"20100612120620.GA13910@book.hvoigt.net","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-06-13T17:59:43Z","receivedAt":"2010-06-13T17:59:43Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Saturday 12 June 2010, Heiko Voigt wrote:\n> On Sat, Jun 12, 2010 at 12:12:50PM +0200, Johan Herland wrote:\n> > On Friday 11 June 2010, Heiko Voigt wrote:\n> > > The following patch series is a work in progress. The idea is\n> > > whenever you need to merge two SHA1's of a submodule we search for a\n> > > ref in the submodule which already contains both. If one such ref\n> > > exists the resulting SHA1 is the one pointed at by that ref.\n> > \n> > I appreciate the effort to improve submodule handling, but I'm not sure\n> > I like this approach. Even though you try to apply it as\n> > conservatively as possible, it still smells a little like trying to\n> > make Git too clever for its own good.\n> > \n> > E.g. say we have the following commit history in the submodule:\n> >   A---B---C---D  <-- master\n> > \n> > Now, say that your merge conflict comes from one branch updating the\n> > submodule from B to C, while the other branch reverts the submodule\n> > from B to A. In your proposed scheme, Git would auto-resolve the\n> > conflict to D.\n> \n> You are right. I did forget to mention this in my topic letter: Both\n> changes need to point forward. This exact case is also tested in the\n> testcases and results in a merge conflict which needs to be resolved by\n> hand.\n\nStill doesn't solve one of the cases I gave in the last email: Say one \nbranch updates the submodule from A to B, and the other updates from A to C. \nYour proposal resolves the merge by fast-forwarding to D, which seems \nirresponsible, since we have no concept of how well D is tested. Maybe it \nintroduces another showstopper bug, and that is why neither branch has \nupgraded to it yet?\n\nA better solution would be, to put it generally: Given a submodule being \npart of a superproject conflict, if one of the candidate submodule SHA1s is \nis a descendant of _all_ the other submodule SHA1 candidates, then choose \nthat SHA1 as the proposed resolution (but please leave the index entry \n\"unmerged\", so that the resolution must be confirmed by the user).\n\nThis removes all the \"stable\" branch magic from your patch. All you need to \nlook at are the candidate SHA1s and their relationship in the commit graph. \nNo refs involved.\n\nIn the A->B vs. A->C case above, we would see that C is a descendant of B, \nand we would therefore choose C as a suggested conflict resolution, which \nIMHO is a much better choice than D.\n\nI still don't want to add a lot of auto-resolving cleverness to Git, as it \ninevitably _will_ choose incorrectly sometimes, and in those situations it \nwill be much more confusing than if it didn't choose at all.\n\n> > This whole idea is somewhat similar to branch-tracking submodules\n> > (recently discussed in another thread), except that it only applies on\n> > _merge_ in the superproject, and you don't get to choose _which_\n> > branch it's tracking. That's _way_ too arbitrary for my tastes.\n> \n> The difference to branch-tracking submodules is, if I understand it\n> correctly, that with a merge you get an explicit SHA1 which is recorded.\n> Whereras with branch-tracking you never know on which revision on the\n> tracked branch the submodule was.\n\nTechnically you may be right, but my point is that in your original proposal \nI don't get to _choose_ which submodule SHA1 is explicitly recorded for the \nmerge resolution, but instead your patch chooses whatever SHA1 happens to be \nat the tip of some branch considered \"stable\". Although technically \ndifferent, this is similar in _spirit_ to what branch-tracking submodules is \nabout.\n\n> Thats why I only want to search through stable branches further down. I\n> mean stable in the git sense that they never get rewound and of course\n> should contain the most stable part of development. To ease the\n> configuration we would default to master which we could assume as\n> stable. But if we want to be on the safe side we could also say that\n> automatic submodule merging only works when the user has configured some\n> stable branches.\n\nOk, so you can configure exactly which branch(es) you consider stable. I'd \nstill much rather prefer the approach I outlined above, which does away with \nall the \"stable\" branch magic, and only considers the commit ancestry \ndirectly.\n\n\nHope this helps,\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"143688","messageId":"20100614170222.GB1389@book.hvoigt.net","threadId":"24081","inReplyTo":"201006131959.43356.johan@herland.net","subject":"Re: Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Heiko Voigt","fromEmail":"hvoigt@hvoigt.net","sentAt":"2010-06-14T17:02:23Z","receivedAt":"2010-06-14T17:02:23Z","isPatch":true,"sender":{"key":"hvoigt@hvoigt.net","avatar":"https://avatars.githubusercontent.com/u/184958?v=4"},"body":"Hi,\n\nOn Sun, Jun 13, 2010 at 07:59:43PM +0200, Johan Herland wrote:\n> On Saturday 12 June 2010, Heiko Voigt wrote:\n> > On Sat, Jun 12, 2010 at 12:12:50PM +0200, Johan Herland wrote:\n> > > E.g. say we have the following commit history in the submodule:\n> > >   A---B---C---D  <-- master\n> > > \n> > > Now, say that your merge conflict comes from one branch updating the\n> > > submodule from B to C, while the other branch reverts the submodule\n> > > from B to A. In your proposed scheme, Git would auto-resolve the\n> > > conflict to D.\n> > \n> > You are right. I did forget to mention this in my topic letter: Both\n> > changes need to point forward. This exact case is also tested in the\n> > testcases and results in a merge conflict which needs to be resolved by\n> > hand.\n> \n> Still doesn't solve one of the cases I gave in the last email: Say one \n> branch updates the submodule from A to B, and the other updates from A to C. \n> Your proposal resolves the merge by fast-forwarding to D, which seems \n> irresponsible, since we have no concept of how well D is tested. Maybe it \n> introduces another showstopper bug, and that is why neither branch has \n> upgraded to it yet?\n> \n> A better solution would be, to put it generally: Given a submodule being \n> part of a superproject conflict, if one of the candidate submodule SHA1s is \n> is a descendant of _all_ the other submodule SHA1 candidates, then choose \n> that SHA1 as the proposed resolution (but please leave the index entry \n> \"unmerged\", so that the resolution must be confirmed by the user).\n\nIs there currently any logic to support a \"suggested\" merge resolution\nin git.git? I am not that familiar with code base yet and I do not think\nthat I have seen something like that. Is it done somewhere already?\n\n> This removes all the \"stable\" branch magic from your patch. All you need to \n> look at are the candidate SHA1s and their relationship in the commit graph. \n> No refs involved.\n> \n> In the A->B vs. A->C case above, we would see that C is a descendant of B, \n> and we would therefore choose C as a suggested conflict resolution, which \n> IMHO is a much better choice than D.\n> \n> I still don't want to add a lot of auto-resolving cleverness to Git, as it \n> inevitably _will_ choose incorrectly sometimes, and in those situations it \n> will be much more confusing than if it didn't choose at all.\n\nI see your point. But nevertheless there is a specific workflow I target\nto support which is not supported by your approach:\n\nLets assume Alice creates a feature branch feature_a for her development\nand needs to modify the submodule and creates a branch there as well. At\nthe same time Bob develops feature_b and also needs changes in the\nsubmodule and so he creates a feature branch there as well.\n\nAssume we now have the following history in the submodule:\n\n  B---C---D         [feature_a]\n /         \\\nA---E---F---G---K   [master]\n     \\         /\n      H---I---J     [feature_b]\n\nNow during the development of her branch Alice would link D in the\nsuperproject as it is the tip of her branch. Bob would do the same and\nlink to J as his tip. Now Alice sends out her branch to the reviewers\nand after everybody is happy with it the maintainer merges her branch\nfirst. The superproject links to D. Now Bob does the same and the\nmaintainer wants to merge his branch and gets a merge conflict because D\nand J do not have a parent/children relationship.\n\nI think this is a fairly natural pattern which evolves from the use of\nfeature branches in git. So I would like to make git behave naturally\nfor this workflow and automatically merge.\n\nNow your point is that master could be wrong and you are right, but\nnormal merges can go wrong in a similar way. Just imagine this:\n\nAlice adds a parameter to the static function somefunc() and changes all\ncallsites of it in her branch. Independently Bob writes new code in\nhis branch that uses somefunc() with the old signature. When both\nbranches are merged git has no chance of doing it right and the code\nwill not compile. So even normal merging is always a little heuristic.\nQuestion is: How well does the heuristic perform in practise.\n\n> > Thats why I only want to search through stable branches further down. I\n> > mean stable in the git sense that they never get rewound and of course\n> > should contain the most stable part of development. To ease the\n> > configuration we would default to master which we could assume as\n> > stable. But if we want to be on the safe side we could also say that\n> > automatic submodule merging only works when the user has configured some\n> > stable branches.\n> \n> Ok, so you can configure exactly which branch(es) you consider stable. I'd \n> still much rather prefer the approach I outlined above, which does away with \n> all the \"stable\" branch magic, and only considers the commit ancestry \n> directly.\n\nOk what do you think about combining both approaches: If no stable\nbranches are configured we default to your strategy and if the user\nwants some magic (I mean isn't that what git is all about: magic)\nconfiguring stable branches will enable git to resolve conflicts like\nthe ones I described above.\n\nMy feeling is that in practise automatic merging into stable branches\nwill work well and the cases of failure will be neglectable to not\nhappening at all. So my approach would be to go ahead, implement the\nstrategy and let people play around with it so we can collect some real\nlife data whether it is helping or making matters worse.\n\ncheers Heiko\n"},{"id":"143708","messageId":"201006150159.42680.johan@herland.net","threadId":"24081","inReplyTo":"20100614170222.GB1389@book.hvoigt.net","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-06-14T23:59:42Z","receivedAt":"2010-06-14T23:59:42Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Monday 14 June 2010, Heiko Voigt wrote:\n> On Sun, Jun 13, 2010 at 07:59:43PM +0200, Johan Herland wrote:\n> > On Saturday 12 June 2010, Heiko Voigt wrote:\n> > A better solution would be, to put it generally: Given a submodule\n> > being part of a superproject conflict, if one of the candidate\n> > submodule SHA1s is is a descendant of _all_ the other submodule SHA1\n> > candidates, then choose that SHA1 as the proposed resolution (but\n> > please leave the index entry \"unmerged\", so that the resolution must\n> > be confirmed by the user).\n> \n> Is there currently any logic to support a \"suggested\" merge resolution\n> in git.git? I am not that familiar with code base yet and I do not think\n> that I have seen something like that. Is it done somewhere already?\n\nIn the case of a regular file, you can replace the default working tree \nversion (the one with conflict markers) by a version containing your \nsuggested merge resolution, but NOT add that version to the index, so the \nindex still thinks the file is unmerged. You then 'git add' the file to \nacknowledge the suggested resolution.\n\nIn the case of submodules, you would check out the suggested version of the \nsubmodule, but not add its SHA1 to the superproject index. Again, the user \nacknowledges the suggested resolution by 'git add'ing the submodule.\n\nMy point is that when Git tries to suggest merge resolutions, it should \npurposefully NOT add these to the index, so that the user HAS to acknowledge \nthem. This is similar to the default behaviour of 'git rerere' which \nresolves your conflicts automatically, but does not touch the corresponding \n\"unmerged\" index entries, so that you manually have to 'git add' the result.\n\n> > This removes all the \"stable\" branch magic from your patch. All you\n> > need to look at are the candidate SHA1s and their relationship in the\n> > commit graph. No refs involved.\n> > \n> > In the A->B vs. A->C case above, we would see that C is a descendant of\n> > B, and we would therefore choose C as a suggested conflict resolution,\n> > which IMHO is a much better choice than D.\n> > \n> > I still don't want to add a lot of auto-resolving cleverness to Git, as\n> > it inevitably _will_ choose incorrectly sometimes, and in those\n> > situations it will be much more confusing than if it didn't choose at\n> > all.\n> \n> I see your point. But nevertheless there is a specific workflow I target\n> to support which is not supported by your approach:\n> \n> Lets assume Alice creates a feature branch feature_a for her development\n> and needs to modify the submodule and creates a branch there as well. At\n> the same time Bob develops feature_b and also needs changes in the\n> submodule and so he creates a feature branch there as well.\n> \n> Assume we now have the following history in the submodule:\n> \n>   B---C---D         [feature_a]\n>  /         \\\n> A---E---F---G---K   [master]\n>      \\         /\n>       H---I---J     [feature_b]\n> \n> Now during the development of her branch Alice would link D in the\n> superproject as it is the tip of her branch. Bob would do the same and\n> link to J as his tip. Now Alice sends out her branch to the reviewers\n> and after everybody is happy with it the maintainer merges her branch\n> first. The superproject links to D.\n\nNo. The superproject would get a conflict between the A->D and A->F updates \nof the submodule. The correct resolution would be to go into the submodule, \ndo the merge to produce G, and then record this as the correct merge \nresolution in the superproject.\n\nYou want Git to do this automatically for you, whereas I think that Git \nshould not be that \"clever\", because there are situations (as I've \ndemonstrated previously in this thread) where the \"cleverness\" would do The \nWrong Thing.\n\n> Now Bob does the same and the\n> maintainer wants to merge his branch and gets a merge conflict because D\n> and J do not have a parent/children relationship.\n\nWell, s/D/G/, but your point still stands. And the correct resolution is, of \ncourse, to merge G and J to produce K, and then record K in the superproject \nas the correct merge resolution.\n\nAgain, the question is whether Git should do these submodule merges \nautomatically, or not.\n\n> I think this is a fairly natural pattern which evolves from the use of\n> feature branches in git. So I would like to make git behave naturally\n> for this workflow and automatically merge.\n\nPlease keep in mind that your workflow is but one, and Git has to support a \nwide variety of different workflows without breaking down.\n\nIt actually seems to me that - in your workflow scenario, where the \nsubmodule seems to be fairly tightly coupled to the superproject - you would \nbe better off using branch-tracking submodules (recently discussed in the \nthread called 'RFC: Making submodules \"track\" branches').\n\nWhen using branch-tracking submodules, Alice would configure the submodule \nto track the \"feature_a\" branch, while Bob would configure the submodule to \ntrack the \"feature_b\" branch. When merging these branches, the correct merge \nresolution would be (after having merged the submodule feature branches back \ninto the submodule \"master\") to track the \"master\" branch in the submodule.\n\nWhen merging the two feature branches back into \"master\" there would (in \naddition to the conflicted submodule entry) be conflicts in the .gitmodules \nfile on which submodule branch to track (I'm following Ævar's proposal \nhere), and the resolution of _that_ conflict would specify which submodule \nbranch/version to use in the resolved merge.\n\nNow, in your proposal, you would have an _additional_ config variable for \ncontrolling which submodule branch is equivalent to \"master\" in the above \nexample. If this branch were to be different from the \"tracked\" branch (as \ndefined in Ævar's proposal), you would be in the deeply confusing situation \nof having the merge resolved to the tip of one branch, while you've told the \nsubmodule to track a _different_ branch. The only thing that makes sense \nwould be for these two variables to always be identical, at which point you \nshould simply eliminate one of them.\n\nI guess what I'm getting at (sorry for taking a while to get here) is that \nyou could maybe solve your problem by a combination of what I suggested in \nmy previous mail, plus the use of branch-tracking submodules. There are \nstill some things to be worked out here, but I don't believe adding an \nalmost-but-not-quite-submodule-branch-tracking option is the best way to go.\n\n> Now your point is that master could be wrong and you are right, but\n> normal merges can go wrong in a similar way. Just imagine this:\n> \n> Alice adds a parameter to the static function somefunc() and changes all\n> callsites of it in her branch. Independently Bob writes new code in\n> his branch that uses somefunc() with the old signature. When both\n> branches are merged git has no chance of doing it right and the code\n> will not compile. So even normal merging is always a little heuristic.\n> Question is: How well does the heuristic perform in practise.\n\nTrue, but I don't necessarily accept that one sometimes-wrong heuristic \njustifies another sometimes-wrong heuristic. Follow that logic, and we can \npile on heuristics until we almost always get something wrong...\n\n> > Ok, so you can configure exactly which branch(es) you consider stable.\n> > I'd still much rather prefer the approach I outlined above, which does\n> > away with all the \"stable\" branch magic, and only considers the commit\n> > ancestry directly.\n> \n> Ok what do you think about combining both approaches: If no stable\n> branches are configured we default to your strategy and if the user\n> wants some magic (I mean isn't that what git is all about: magic)\n> configuring stable branches will enable git to resolve conflicts like\n> the ones I described above.\n\nFWIW, IMHO Git is NOT about magic at all. It even says so at the top of the \ngit(1) manual page: \"git - the stupid content tracker\". And both Junio and \nLinus have repeatedly argued how Git purposefully only auto-resolves the \n_simple_ cases, and leaves the _hard_ cases to the user, since trying to be \nclever about the hard cases inevitably leads to more confusion and insanity.\n\nIn this case, your scenario/proposal just about crosses into what I consider \nthe _hard_ space, which is why I'm critical of the cleverness.\n\nAs for combining both approaches (subject to some config option), I guess \nthat could work, but I'd certainly like to see a significant amount of \nsupport for your proposal before we go there.\n\n> My feeling is that in practise automatic merging into stable branches\n> will work well and the cases of failure will be neglectable to not\n> happening at all. So my approach would be to go ahead, implement the\n> strategy and let people play around with it so we can collect some real\n> life data whether it is helping or making matters worse.\n\nFeel free to post the patches, if you can spend the time making them. So \nfar, there's been no other feedback in this thread, so maybe I'm alone in my \nworries...\n\n\nCheers,\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"143771","messageId":"4C17BA67.4060500@web.de","threadId":"24081","inReplyTo":"201006150159.42680.johan@herland.net","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2010-06-15T17:37:43Z","receivedAt":"2010-06-15T17:37:43Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 15.06.2010 01:59, schrieb Johan Herland:\n> My point is that when Git tries to suggest merge resolutions, it should \n> purposefully NOT add these to the index, so that the user HAS to acknowledge \n> them. This is similar to the default behaviour of 'git rerere' which \n> resolves your conflicts automatically, but does not touch the corresponding \n> \"unmerged\" index entries, so that you manually have to 'git add' the result.\n\nI like that idea, as it avoids having unintended submodule commits added\nsilently to the superprojects index by the merge.\n\n\n>> Lets assume Alice creates a feature branch feature_a for her development\n>> and needs to modify the submodule and creates a branch there as well. At\n>> the same time Bob develops feature_b and also needs changes in the\n>> submodule and so he creates a feature branch there as well.\n>>\n>> Assume we now have the following history in the submodule:\n>>\n>>   B---C---D         [feature_a]\n>>  /         \\\n>> A---E---F---G---K   [master]\n>>      \\         /\n>>       H---I---J     [feature_b]\n>>\n>> Now during the development of her branch Alice would link D in the\n>> superproject as it is the tip of her branch. Bob would do the same and\n>> link to J as his tip. Now Alice sends out her branch to the reviewers\n>> and after everybody is happy with it the maintainer merges her branch\n>> first. The superproject links to D.\n> \n> No. The superproject would get a conflict between the A->D and A->F updates \n> of the submodule. The correct resolution would be to go into the submodule, \n> do the merge to produce G, and then record this as the correct merge \n> resolution in the superproject.\n\nBut as far as I understood this patch this merge has already been done\ninside the submodule (at least this is what the setup of the test case\nseems to do at a quick glance).\n\n\n> You want Git to do this automatically for you, whereas I think that Git \n> should not be that \"clever\", because there are situations (as I've \n> demonstrated previously in this thread) where the \"cleverness\" would do The \n> Wrong Thing.\n> \n>> Now Bob does the same and the\n>> maintainer wants to merge his branch and gets a merge conflict because D\n>> and J do not have a parent/children relationship.\n> \n> Well, s/D/G/, but your point still stands. And the correct resolution is, of \n> course, to merge G and J to produce K, and then record K in the superproject \n> as the correct merge resolution.\n> \n> Again, the question is whether Git should do these submodule merges \n> automatically, or not.\n\nHm, maybe I am missing something here, but isn't the question whether Git\nshould /use/ these submodule merges already done by a human being instead\nof /doing them itself/? So isn't it just about making Git so clever it\nproposes a merge already present in the submodule for recording in the\nsuperproject when merging there?\n\n\n> Feel free to post the patches, if you can spend the time making them. So \n> far, there's been no other feedback in this thread, so maybe I'm alone in my \n> worries...\n\nI fully understand your worries concerning automagic merges inside a\nsubmodule. But I really would like to see Git assisting me when merging\nsubmodule commits in the superproject that have already been merged in\nthe submodule repo. And for me the first commit containing the others\nis the one I would like to see then.\n"},{"id":"143803","messageId":"201006160205.20705.johan@herland.net","threadId":"24081","inReplyTo":"4C17BA67.4060500@web.de","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-06-16T00:05:20Z","receivedAt":"2010-06-16T00:05:20Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Tuesday 15 June 2010, Jens Lehmann wrote:\n> Am 15.06.2010 01:59, schrieb Johan Herland:\n> >> Lets assume Alice creates a feature branch feature_a for her\n> >> development and needs to modify the submodule and creates a branch\n> >> there as well. At the same time Bob develops feature_b and also needs\n> >> changes in the submodule and so he creates a feature branch there as\n> >> well.\n> >> \n> >> Assume we now have the following history in the submodule:\n> >>   B---C---D         [feature_a]\n> >>  /         \\\n> >> A---E---F---G---K   [master]\n> >>      \\         /\n> >>       H---I---J     [feature_b]\n> >> \n> >> Now during the development of her branch Alice would link D in the\n> >> superproject as it is the tip of her branch. Bob would do the same and\n> >> link to J as his tip. Now Alice sends out her branch to the reviewers\n> >> and after everybody is happy with it the maintainer merges her branch\n> >> first. The superproject links to D.\n> > \n> > No. The superproject would get a conflict between the A->D and A->F\n> > updates of the submodule. The correct resolution would be to go into\n> > the submodule, do the merge to produce G, and then record this as the\n> > correct merge resolution in the superproject.\n> \n> But as far as I understood this patch this merge has already been done\n> inside the submodule (at least this is what the setup of the test case\n> seems to do at a quick glance).\n\nOk, let's look at a sequence of events:\n\n0. There is a master branch in the superproject which points to commit A (on \nthe master branch) in the submodule.\n\n1. Alice creates feature_a branch in both superproject and submodule, \ncreates commits B, C & D in the submodule and updates the superproject to \npoint to D\n\n2. Someone creates E in the submodule, and updates the master branch in the \nsuperproject to point to E.\n\n3. Bob creates feature_b branch in both superproject and submodule, creates \ncommits H, I & J in the submodule and updates the superproject to point to J\n\n4. Someone creates F in the submodule, and updates the master branch in the \nsuperproject to point to F.\n\n5. Maintainer starts integrating feature_a into master in superproject, and \ndiscovers the conflict between A->D and A->F. Mantainer then descends into \nsubmodule to create the merge G. Maintainer can now 'git add' the submodule \nin the superproject to record A->G as the merge resolution of the A->D vs. \nA->F conflict.\n\n(6. Same as step #5, but replace Alice/A/D/F/G with Bob/E/J/G/K)\n\nI assume here that nobody has made the merge commit G before Git produces \nthe A->D vs. A->F conflict in step #5 (which prompts Maintainer to make G in \norder to resolve the conflict). I believe this would be the most common \ncase.\n\nIf the merge commit G for some reason _already_ exists in the submodule \nbefore step #5, the maintainer's job is to simply recognize it as the \ncorrect resolution of the conflict, and check it out (and finally 'git add' \nit to the superproject index). But I don't see this happening very often: \nFor one, who has the incentive to create G before it is needed in step #5? \nBoth Alice and Bob are content with pointing to their respective submodule \nbranches, and the only person who cares about doing the submodule merges is \nMaintainer who has to tie everything together into a coherent whole.\n\nHowever, we should not require clairvoyance from the Maintainer as to which \nsubmodules have been modified by each feature branch, and hence which of \nthem require preparatory submodule merges to be performed before the main \nsuperproject merge can be started. To the contrary, I believe the typical \nMaintainer will start the superproject merge, and then respond to the \nsubmodule conflicts that Git produces by descending into the submodule and \nmerging submodules (or whatever else is required to reach a satisfactory \nsubmodule state).\n\nThus, if the purpose of Heiko's patches is to simply recognize merges that \nhave already happened before step #5, then I'm afraid they will seldom or \nnever be useful in practice (since these merges typically happen _after_ the \nsuperproject merge has been started).\n\n> > You want Git to do this automatically for you, whereas I think that Git\n> > should not be that \"clever\", because there are situations (as I've\n> > demonstrated previously in this thread) where the \"cleverness\" would do\n> > The Wrong Thing.\n> > \n> >> Now Bob does the same and the\n> >> maintainer wants to merge his branch and gets a merge conflict because\n> >> D and J do not have a parent/children relationship.\n> > \n> > Well, s/D/G/, but your point still stands. And the correct resolution\n> > is, of course, to merge G and J to produce K, and then record K in the\n> > superproject as the correct merge resolution.\n> > \n> > Again, the question is whether Git should do these submodule merges\n> > automatically, or not.\n> \n> Hm, maybe I am missing something here, but isn't the question whether Git\n> should /use/ these submodule merges already done by a human being instead\n> of /doing them itself/? So isn't it just about making Git so clever it\n> proposes a merge already present in the submodule for recording in the\n> superproject when merging there?\n\nAh, yes, sorry, I confused the concepts at this point. Still:\n\n- If the purpose is to re-use existing submodule merges then I'm afraid (as \nI've argued above) that this would happen too seldom to be useful in \npractice (and even then you would already have had to set up the appropriate \nconfig for your branch, to enable Git to find this pre-existing merge at \nall).\n\n- If the purpose is to create new submodule merges to resolve the conflicts \n(which, granted, the patches currently don't do, but that I'm afraid they \nwould _have_ to do in order to be useful in practice), then there is too \nmuch cleverness/magic for my liking.\n\n> > Feel free to post the patches, if you can spend the time making them.\n> > So far, there's been no other feedback in this thread, so maybe I'm\n> > alone in my worries...\n> \n> I fully understand your worries concerning automagic merges inside a\n> submodule. But I really would like to see Git assisting me when merging\n> submodule commits in the superproject that have already been merged in\n> the submodule repo.\n\nAs I've argued above, I'm afraid this situation would seldom/never arise in \npractice.\n\nTaking a step back and comparing the merging of submodules vs. the merging \nof regular files:\n\nGit's rules are simple and straightforward for regular files: If both \nsides/branches have changed the same area of code (and the changes don't \nexactly coincide), you get a conflict. There's no magic/cleverness applied \nto try to figure out what a good resolution would look like; it's a \nconflict, and the user must resolve it. Simple as that.\n\nI'd argue that the submodule case should be the same: If both sides/branches \nchange the submodule (and the SHA1s don't exactly match), you get a \nconflict, and it's up to the user to resolve it.\n\nWe may to make an exception for the case where one SHA1 is a descendant of \nthe other (i.e. a fast-forward situation), since that seems like a safe \nchoice in most situations, but I don't feel safe doing much beyond that.\n\n> And for me the first commit containing the others is the one I would like\n> to see then.\n\nIn that case you will have to modify Heiko's patches, because (I believe) \nthey currently choose the _latest_ commit containing the others...\n\n\nCheers,\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"143826","messageId":"4C1906FA.7010906@web.de","threadId":"24081","inReplyTo":"201006160205.20705.johan@herland.net","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2010-06-16T17:16:42Z","receivedAt":"2010-06-16T17:16:42Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 16.06.2010 02:05, schrieb Johan Herland:\n> - If the purpose is to re-use existing submodule merges then I'm afraid (as \n> I've argued above) that this would happen too seldom to be useful in \n> practice (and even then you would already have had to set up the appropriate \n> config for your branch, to enable Git to find this pre-existing merge at \n> all).\n\nThat this is all but happening seldom for us is the reason for this WIP\npatch from Heiko. And other use cases won't be harmed by this change, no?\nAnd if some are, we can add a config option to .gitmodules to control that.\n\n\n> Taking a step back and comparing the merging of submodules vs. the merging \n> of regular files:\n> \n> Git's rules are simple and straightforward for regular files: If both \n> sides/branches have changed the same area of code (and the changes don't \n> exactly coincide), you get a conflict. There's no magic/cleverness applied \n> to try to figure out what a good resolution would look like; it's a \n> conflict, and the user must resolve it. Simple as that.\n> \n> I'd argue that the submodule case should be the same: If both sides/branches \n> change the submodule (and the SHA1s don't exactly match), you get a \n> conflict, and it's up to the user to resolve it.\n> \n> We may to make an exception for the case where one SHA1 is a descendant of \n> the other (i.e. a fast-forward situation), since that seems like a safe \n> choice in most situations, but I don't feel safe doing much beyond that.\n\nYes, I would like to see that fast-forward case silently handled by a merge\nin the superproject.\n\nAnd if it is no fast-forward but you find a unique merge where both of these\nSHA1s are included, you could advertise it as a possible solution but not\nautomagically add it to the index. So you give the maintainer of the\nsuperproject the opportunity to assess a possible solution but spare him the\nchore of trying to find the reason why the merge failed and what he can do\nabout it by showing him the right direction. He might then decide to take a\nlater commit of the submodule or resolve the whole issue differently, but\nthat is up to him.\n\n\n>> And for me the first commit containing the others is the one I would like\n>> to see then.\n> \n> In that case you will have to modify Heiko's patches, because (I believe) \n> they currently choose the _latest_ commit containing the others...\n\nYes, but IMHO that is a bit too much forwarding.\n"},{"id":"143836","messageId":"201006162332.56700.johan@herland.net","threadId":"24081","inReplyTo":"4C1906FA.7010906@web.de","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-06-16T21:32:56Z","receivedAt":"2010-06-16T21:32:56Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Wednesday 16 June 2010, Jens Lehmann wrote:\n> Am 16.06.2010 02:05, schrieb Johan Herland:\n> > - If the purpose is to re-use existing submodule merges then I'm afraid\n> > (as I've argued above) that this would happen too seldom to be useful\n> > in practice (and even then you would already have had to set up the\n> > appropriate config for your branch, to enable Git to find this\n> > pre-existing merge at all).\n> \n> That this is all but happening seldom for us is the reason for this WIP\n> patch from Heiko. And other use cases won't be harmed by this change, no?\n> And if some are, we can add a config option to .gitmodules to control\n> that.\n\nOk. I'm still not sure I see how this can happen frequently in practice, but \nsince you both probably use submodules more heavily than I do, I will not \nstand in the way of progress.\n\n> > Taking a step back and comparing the merging of submodules vs. the\n> > merging of regular files:\n> > \n> > Git's rules are simple and straightforward for regular files: If both\n> > sides/branches have changed the same area of code (and the changes\n> > don't exactly coincide), you get a conflict. There's no\n> > magic/cleverness applied to try to figure out what a good resolution\n> > would look like; it's a conflict, and the user must resolve it. Simple\n> > as that.\n> > \n> > I'd argue that the submodule case should be the same: If both\n> > sides/branches change the submodule (and the SHA1s don't exactly\n> > match), you get a conflict, and it's up to the user to resolve it.\n> > \n> > We may to make an exception for the case where one SHA1 is a descendant\n> > of the other (i.e. a fast-forward situation), since that seems like a\n> > safe choice in most situations, but I don't feel safe doing much\n> > beyond that.\n> \n> Yes, I would like to see that fast-forward case silently handled by a\n> merge in the superproject.\n> \n> And if it is no fast-forward but you find a unique merge where both of\n> these SHA1s are included, you could advertise it as a possible solution\n> but not automagically add it to the index. So you give the maintainer of\n> the superproject the opportunity to assess a possible solution but spare\n> him the chore of trying to find the reason why the merge failed and what\n> he can do about it by showing him the right direction. He might then\n> decide to take a later commit of the submodule or resolve the whole\n> issue differently, but that is up to him.\n\nI still particularily don't like the added config variable for specifying \nwhich branch(es) are considered \"stable\". Would it be possible to instead \nsearch all submodule branches for the earliest commits that reconcile the \ntwo commits, and then inform the user that these may be interesting to look \nat when trying to find a resolution? Something like:\n\n  Cannot auto-resolve conflict between $a_sha1 and $b_sha1 in submodule\n  $foo. The following merge commits in submodule $foo may help you resolve\n  this conflict:\n    - $sha1 (present in branches $a, $b, $c)\n    - $sha2 (present in branches $c, $d)\n    - $sha3 (present in branches $e, $f)\n\nThus the user/maintainer gets the full picture, and are given as many \nalternatives as possible to help resolve the conflict, instead of \nautomatically getting one (possibly wrong) resolution, just because the \n\"stable\" config was unset or incorrect.\n\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"143837","messageId":"7vy6eed3w0.fsf@alter.siamese.dyndns.org","threadId":"24081","inReplyTo":"201006162332.56700.johan@herland.net","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-06-16T22:11:27Z","receivedAt":"2010-06-16T22:11:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johan Herland <johan@herland.net> writes:\n\n> On Wednesday 16 June 2010, Jens Lehmann wrote:\n>> Am 16.06.2010 02:05, schrieb Johan Herland:\n>> > - If the purpose is to re-use existing submodule merges then I'm afraid\n>> > (as I've argued above) that this would happen too seldom to be useful\n>> > in practice (and even then you would already have had to set up the\n>> > appropriate config for your branch, to enable Git to find this\n>> > pre-existing merge at all).\n>> \n>> That this is all but happening seldom for us is the reason for this WIP\n>> patch from Heiko. And other use cases won't be harmed by this change, no?\n>> And if some are, we can add a config option to .gitmodules to control\n>> that.\n>\n> Ok. I'm still not sure I see how this can happen frequently in practice, but \n> since you both probably use submodules more heavily than I do, I will not \n> stand in the way of progress.\n\nAt least it would be useful to learn how they manage to often produce the\nsubmodule merge G.  Your scenario description was very clearly written and\nin that particular workflow I didn't think it would be plausible to have\nsuch a merge before it is needed.  IOW, their workflow must be quite\ndifferent from your scenario description, and I would like to see a\nplausible scenario description that is as clearly written as yours;\nperhaps that workflow can even be advertised as one of the BCP.\n\nOne possibility that comes to mind is perhaps Alice notices the presence\nof F after she recorded D, merges D and F in the submodule to produce G in\nthe submodule repository, but does _not_ update the superproject to point\nat it yet, for some reason.  Perhaps she hasn't tested the superproject\nwith the merged submodule yet.  Whatever the reason is, the tip of her\nbranch in the submodule would be ahead of what her superproject commit D\npoints at, but the commit is available to the maintainer to fetch.\n\nThen the maintainer would see G in the submodule (after fetching both\nsuperproject and submodule from Alice) already prepared to be used in a\nmerge between D and F.\n\nI dunno.\n"},{"id":"143839","messageId":"201006170239.01951.johan@herland.net","threadId":"24081","inReplyTo":"7vy6eed3w0.fsf@alter.siamese.dyndns.org","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-06-17T00:39:01Z","receivedAt":"2010-06-17T00:39:01Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Thursday 17 June 2010, Junio C Hamano wrote:\n> Johan Herland <johan@herland.net> writes:\n> > On Wednesday 16 June 2010, Jens Lehmann wrote:\n> >> Am 16.06.2010 02:05, schrieb Johan Herland:\n> >> > - If the purpose is to re-use existing submodule merges then I'm\n> >> > afraid (as I've argued above) that this would happen too seldom to\n> >> > be useful in practice (and even then you would already have had to\n> >> > set up the appropriate config for your branch, to enable Git to\n> >> > find this pre-existing merge at all).\n> >> \n> >> That this is all but happening seldom for us is the reason for this\n> >> WIP patch from Heiko. And other use cases won't be harmed by this\n> >> change, no? And if some are, we can add a config option to\n> >> .gitmodules to control that.\n> > \n> > Ok. I'm still not sure I see how this can happen frequently in\n> > practice, but since you both probably use submodules more heavily than\n> > I do, I will not stand in the way of progress.\n> \n> At least it would be useful to learn how they manage to often produce the\n> submodule merge G.  Your scenario description was very clearly written\n> and in that particular workflow I didn't think it would be plausible to\n> have such a merge before it is needed.  IOW, their workflow must be\n> quite different from your scenario description, and I would like to see\n> a plausible scenario description that is as clearly written as yours;\n> perhaps that workflow can even be advertised as one of the BCP.\n> \n> One possibility that comes to mind is perhaps Alice notices the presence\n> of F after she recorded D, merges D and F in the submodule to produce G\n> in the submodule repository, but does _not_ update the superproject to\n> point at it yet, for some reason.  Perhaps she hasn't tested the\n> superproject with the merged submodule yet.  Whatever the reason is, the\n> tip of her branch in the submodule would be ahead of what her\n> superproject commit D points at, but the commit is available to the\n> maintainer to fetch.\n\nDubious. If Alice's merge of D and F hasn't been properly tested yet, I \ndon't see why it should exist on the submodule's master branch, and if it \ndoesn't, it simply isn't considered, due to Heiko's \"stable\" branch magic.\n\n> Then the maintainer would see G in the submodule (after fetching both\n> superproject and submodule from Alice) already prepared to be used in a\n> merge between D and F.\n> \n> I dunno.\n\nMe neither, but after some more thinking I have another alternative as to \nwhy the merge G might exist (on the submodule master branch) before the \nsuperproject merge is started:\n\nIf the submodule happens to be maintained as a truly separate project (with \nits own maintainer), then the maintainer of that submodule may have decided \nto merge Alice's feature_a branch on its own merits, without looking at the \nsuperproject at all. When the superproject maintainer later performs the \nsuperproject merge he can just pick up the submodule merge done by the \nsubmodule maintainer.\n\nBut this is pure speculation, and as you say, I'd like to see what workflows \nJens and Heiko are actually using.\n\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"143886","messageId":"4C1A8FDC.7010309@web.de","threadId":"24081","inReplyTo":"201006170239.01951.johan@herland.net","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2010-06-17T21:13:00Z","receivedAt":"2010-06-17T21:13:00Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 17.06.2010 02:39, schrieb Johan Herland:\n> But this is pure speculation, and as you say, I'd like to see what workflows \n> Jens and Heiko are actually using.\n\nOk, here we go. And as I have difficulties thinking about that when looking\nat a single graph, I'll draw two: The upper for the superproject and the\nlower for the submodule.\n\nSuperproject:\n  -----2         [Alice's branch]\n /      \\\n1--3-----4---5   [master]\n    \\       /\n     ------6     [Bob's branch]\n\n       ^   ^\n       |   |     [commits of the submodule committed in the superproject]\n\nSubmodule:\n  ---B           [feature_a]\n /    \\\nA--C---D---E     [master]\n    \\     /\n     ----F       [feature_b]\n\nAlice hacks away on her feature branch and notices she has to make changes\nto a submodule. She creates the \"feature_a\" branch there with commit 'B'\nand asks the maintainer of the submodule to review and merge her change.\nOur policy is to never commit submodule commits that are not merged yet, as\nthey could just vanish (e.g. by rebasing; imagine having git as a submodule\nand committing a SHA1 from the \"pu\" branch in the superproject ... a later\nbisect might get really frustrating). So the submodule maintainer merges 'B'\ninto 'D' and tells Alice that. She commits 'D' for the submodule in her '2'\ncommit and asks the maintainer of the superproject to review and merge that.\nThe moment he merges that into '4', 'D' gets recorded in the master branch\nof the superproject for the submodule.\n\nMeanwhile Bob also needs a change in the submodule for his work in the\nsuperproject and adds commit 'F' on the \"feature_b\" branch there. He waits\nfor the submodule maintainer to merge that into 'E' so he can do commit '6'.\n\nBut now the submodule commit 'D' in the superproject commit '4' has become\nan obstacle for him and the superprojects maintainer. Bob can't rebase or\ncherrypick beyond or up to '4' because he will get a merge conflict. If he\nasks to merge his branch into '5', the superprojects maintainer will get a\nmerge conflict and tells to him to resolve that.\n\nThis situation would disappear when git merge would do fast-forwards for\nsubmodule commits. And I argue that this is The Right Thing, because just as\ncommit '5' contains /all/ changes from both branches to the files it should\nalso contain /all/ changes to the submodules files that happened during\nthese branches. And that means merge should resolve the submodule to commit\n'E'.\n\nThis is somehow similar to merging binary files. But for submodules Git has\na chance to tell the combined version of both changes in the fast-forward\ncase, whereas it can't know that for binary files. And yes, merge conflicts\ncould happen for the same reasons they may happen to files: The changes in\nBob's branch could break something in Alice's branch. But that applies for\nfiles just like it does for submodule commits, no?\n\n\nAnd the non-fast-forward case happens e.g. when Alice and Bob do not wait\nfor the submodule maintainer to merge their changes:\n\nSuperproject:\n  ---2         [Alice's branch]\n /    \\\n1--3---4---5   [master]\n    \\     /\n     ----6     [Bob's branch]\n\n     ^   ^\n     |   |       [commits of the submodule committed in the superproject]\n\nSubmodule:\n  ---B           [feature_a]\n /    \\\nA--C---D---E     [master]\n    \\     /\n     ----F       [feature_b]\n\nIn this case submodule commit 'B' is recorded in '2' and thus '4', while\ncommit 'F' will be recorded in '6'. So when '4' and '6' are merged, a valid\nguess for '5' would be to use submodule commit 'E', as it is the first one\nbased on both 'B' and 'F'.\n\nBut in this case it is not so clear that 'E' is the right commit, as there\nmight be other commits present in the paths 'B'->'E' and 'F'->'E'. So 'E'\nis just a probable solution for the merge, but not one I would like to see\nautomatically merged. But it should be proposed to the person doing the\nmerge as a probable resolution of the conflict, so that she can decide if\nthat is the case.\n\n\nAnd no 'special' branch is used here. But I think this approach will solve\na lot of the problems we - and maybe others - have with submodule merges\nwithout doing any harm to other workflows.\n"},{"id":"143898","messageId":"201006181140.16652.johan@herland.net","threadId":"24081","inReplyTo":"4C1A8FDC.7010309@web.de","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-06-18T09:40:16Z","receivedAt":"2010-06-18T09:40:16Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Thursday 17 June 2010, Jens Lehmann wrote:\n> Am 17.06.2010 02:39, schrieb Johan Herland:\n> > But this is pure speculation, and as you say, I'd like to see what\n> > workflows Jens and Heiko are actually using.\n> \n> Ok, here we go. And as I have difficulties thinking about that when\n> looking at a single graph, I'll draw two: The upper for the superproject\n> and the lower for the submodule.\n> \n> Superproject:\n>   -----2         [Alice's branch]\n>  /      \\\n> 1--3-----4---5   [master]\n>     \\       /\n>      ------6     [Bob's branch]\n> \n>        ^   ^\n>        |   |     [commits of the submodule committed in the superproject]\n> \n> Submodule:\n>   ---B           [feature_a]\n>  /    \\\n> A--C---D---E     [master]\n>     \\     /\n>      ----F       [feature_b]\n> \n> Alice hacks away on her feature branch and notices she has to make\n> changes to a submodule. She creates the \"feature_a\" branch there with\n> commit 'B' and asks the maintainer of the submodule to review and merge\n> her change. Our policy is to never commit submodule commits that are not\n> merged yet, as they could just vanish (e.g. by rebasing; imagine having\n> git as a submodule and committing a SHA1 from the \"pu\" branch in the\n> superproject ... a later bisect might get really frustrating). So the\n> submodule maintainer merges 'B' into 'D' and tells Alice that. She\n> commits 'D' for the submodule in her '2' commit and asks the maintainer\n> of the superproject to review and merge that. The moment he merges that\n> into '4', 'D' gets recorded in the master branch of the superproject for\n> the submodule.\n> \n> Meanwhile Bob also needs a change in the submodule for his work in the\n> superproject and adds commit 'F' on the \"feature_b\" branch there. He\n> waits for the submodule maintainer to merge that into 'E' so he can do\n> commit '6'.\n> \n> But now the submodule commit 'D' in the superproject commit '4' has\n> become an obstacle for him and the superprojects maintainer. Bob can't\n> rebase or cherrypick beyond or up to '4' because he will get a merge\n> conflict. If he asks to merge his branch into '5', the superprojects\n> maintainer will get a merge conflict and tells to him to resolve that.\n\nJust verifying here: The superproject graph (with referenced submodule \ncommits in parentheses) looks like this:\n\n   --------2(D)            [Alice's branch]\n  /         \\\n 1(A)--3(A)--4(D)---5(?)   [master]\n        \\          /\n         ---------6(E)     [Bob's branch]\n\n...and the conflict that causes problems when merging '4' and '6', is the \n'A'->'D' vs. 'A'->'E' submodule updates.\n\n> This situation would disappear when git merge would do fast-forwards for\n> submodule commits. And I argue that this is The Right Thing, because just\n> as commit '5' contains /all/ changes from both branches to the files it\n> should also contain /all/ changes to the submodules files that happened\n> during these branches. And that means merge should resolve the submodule\n> to commit 'E'.\n\nI agree, and this is in line with my counter-proposal to Heiko: <quote> \nGiven a submodule being part of a superproject conflict, if one of the \ncandidate submodule SHA1s is a descendant of all the other submodule SHA1 \ncandidates, then choose that SHA1 as the proposed resolution</quote>.\n\n> This is somehow similar to merging binary files. But for submodules Git\n> has a chance to tell the combined version of both changes in the\n> fast-forward case, whereas it can't know that for binary files. And yes,\n> merge conflicts could happen for the same reasons they may happen to\n> files: The changes in Bob's branch could break something in Alice's\n> branch. But that applies for files just like it does for submodule\n> commits, no?\n\nCorrect. I guess this means that - for the fast-forward case - Git can \nautomatically record this resolution in the index, hence not requiring the \nuser to \"confirm\" the resolution with 'git add'.\n\n> And the non-fast-forward case happens e.g. when Alice and Bob do not wait\n> for the submodule maintainer to merge their changes:\n> \n> Superproject:\n>   ---2         [Alice's branch]\n>  /    \\\n> 1--3---4---5   [master]\n>     \\     /\n>      ----6     [Bob's branch]\n> \n>      ^   ^\n>      |   |       [commits of the submodule committed in the superproject]\n> \n> Submodule:\n>   ---B           [feature_a]\n>  /    \\\n> A--C---D---E     [master]\n>     \\     /\n>      ----F       [feature_b]\n> \n> In this case submodule commit 'B' is recorded in '2' and thus '4', while\n> commit 'F' will be recorded in '6'. So when '4' and '6' are merged, a\n> valid guess for '5' would be to use submodule commit 'E', as it is the\n> first one based on both 'B' and 'F'.\n\nAgain, to verify: The superproject graph (with referenced submodule commits \nin parentheses) looks like this:\n\n   --------2(B)            [Alice's branch]\n  /         \\\n 1(A)--3(A)--4(B)---5(?)   [master]\n        \\          /\n         ---------6(F)     [Bob's branch]\n\n(Note that the situation would be different if '3' recorded 'C', as then '4' \nshould record 'D' instead of 'B', IMHO.)\n\nIn this case, the conflict that causes problems when merging '4' and '6', is \nthe 'A'->'B' vs. 'A'->'F' submodule updates.\n\nAnd, indeed, in the scenario you present 'E' is probably the best guess '5'.\n\n(Here, you still assume that although the submodule merges 'D'/'E' may not \nbe done by the time Alice/Bob records '2'/'6', they are definitely done by \nthe time the superproject maintainer gets around to creating '5'. Although \nthis apparently works well for your case, I'm sure there are other scenarios \nwhere this is not the case, and are neither helped, nor hurt, by this \neffort.)\n\n> But in this case it is not so clear that 'E' is the right commit, as\n> there might be other commits present in the paths 'B'->'E' and 'F'->'E'.\n> So 'E' is just a probable solution for the merge, but not one I would\n> like to see automatically merged. But it should be proposed to the\n> person doing the merge as a probable resolution of the conflict, so that\n> she can decide if that is the case.\n\nAgreed. Automatic resolving in this case is evil.\n\n> And no 'special' branch is used here.\n\nWell, you need to traverse _some_ submodule ref(s) in order to find 'E' at \nall. My argument is that there may also be _other_ submodule refs that \ncontain merges of 'B' and 'F' as well, and they should _also_ be considered \nas valid candidates for the resolution in '5'. I would in fact argue that \nyou should traverse _all_ submodule refs (maybe even including remote-\ntracking refs) to look for merges of 'B' and 'F' [1], and present them all \nas equal alternatives.\n\nConsider for example this submodule scenario:\n\n        -----------G      [maint]\n       /          /\n   ---B--------  /        [feature_a]\n  /    \\       \\/\n A--C---D---E  /\\         [master]\n     \\     /  /  \\\n      ----F---    \\       [feature_b]\n              \\    \\\n               --H--I--J  [next]\n\nIf there exist multiple merges that resolve 'B' and 'F' (in this case: 'G', \n'E' and 'I'), then all of those should be presented as equal alternatives to \nthe user.\n\n> But I think this approach will solve a lot of the problems we - and maybe\n> others - have with submodule merges without doing any harm to other\n> workflows.\n\nFor the fast-forward case, I fully agree.\n\nFor the non-fast-forward case, I would suggest to search for submodule \nmerges that contain both submodule commits (as described in [1]), and then:\n\n- If there are no merges, do nothing (leave a conflict).\n\n- If there is exactly one merge, then check it out (but do not record it as \nresolved in the index).\n\n- If there are more merge alternatives, present them as equal alternatives, \nbut do nothing (leave a conflict).\n\n\nHave fun! :)\n\n...Johan\n\n\n[1]: To put the search in general terms: Find all merge commits that has \n_both_ (or in the case of octopus; _all_) of the candidate commits (but none \nof the other merges) somewhere in its ancestry. You could implement this by \nfirst intersecting the sets returned from these commands (run in the \nsubmodule):\n\n  git rev-list --merges --ancestry-path --all ^B\n  git rev-list --merges --ancestry-path --all ^F\n\nto get the set of merges descending from both 'B' and 'F', and then prune \neach member in the remaining set that has another set member in its \nancestry.\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"143907","messageId":"4C1B7ABE.8080905@web.de","threadId":"24081","inReplyTo":"201006181140.16652.johan@herland.net","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2010-06-18T13:55:10Z","receivedAt":"2010-06-18T13:55:10Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 18.06.2010 11:40, schrieb Johan Herland:\n> On Thursday 17 June 2010, Jens Lehmann wrote:\n>> Am 17.06.2010 02:39, schrieb Johan Herland:\n>>> But this is pure speculation, and as you say, I'd like to see what\n>>> workflows Jens and Heiko are actually using.\n>>\n>> Ok, here we go. And as I have difficulties thinking about that when\n>> looking at a single graph, I'll draw two: The upper for the superproject\n>> and the lower for the submodule.\n>>\n>> Superproject:\n>>   -----2         [Alice's branch]\n>>  /      \\\n>> 1--3-----4---5   [master]\n>>     \\       /\n>>      ------6     [Bob's branch]\n>>\n>>        ^   ^\n>>        |   |     [commits of the submodule committed in the superproject]\n>>\n>> Submodule:\n>>   ---B           [feature_a]\n>>  /    \\\n>> A--C---D---E     [master]\n>>     \\     /\n>>      ----F       [feature_b]\n>>\n>> Alice hacks away on her feature branch and notices she has to make\n>> changes to a submodule. She creates the \"feature_a\" branch there with\n>> commit 'B' and asks the maintainer of the submodule to review and merge\n>> her change. Our policy is to never commit submodule commits that are not\n>> merged yet, as they could just vanish (e.g. by rebasing; imagine having\n>> git as a submodule and committing a SHA1 from the \"pu\" branch in the\n>> superproject ... a later bisect might get really frustrating). So the\n>> submodule maintainer merges 'B' into 'D' and tells Alice that. She\n>> commits 'D' for the submodule in her '2' commit and asks the maintainer\n>> of the superproject to review and merge that. The moment he merges that\n>> into '4', 'D' gets recorded in the master branch of the superproject for\n>> the submodule.\n>>\n>> Meanwhile Bob also needs a change in the submodule for his work in the\n>> superproject and adds commit 'F' on the \"feature_b\" branch there. He\n>> waits for the submodule maintainer to merge that into 'E' so he can do\n>> commit '6'.\n>>\n>> But now the submodule commit 'D' in the superproject commit '4' has\n>> become an obstacle for him and the superprojects maintainer. Bob can't\n>> rebase or cherrypick beyond or up to '4' because he will get a merge\n>> conflict. If he asks to merge his branch into '5', the superprojects\n>> maintainer will get a merge conflict and tells to him to resolve that.\n> \n> Just verifying here: The superproject graph (with referenced submodule \n> commits in parentheses) looks like this:\n> \n>    --------2(D)            [Alice's branch]\n>   /         \\\n>  1(A)--3(A)--4(D)---5(?)   [master]\n>         \\          /\n>          ---------6(E)     [Bob's branch]\n> \n> ...and the conflict that causes problems when merging '4' and '6', is the \n> 'A'->'D' vs. 'A'->'E' submodule updates.\n\nThat's correct.\n\n\n>> This is somehow similar to merging binary files. But for submodules Git\n>> has a chance to tell the combined version of both changes in the\n>> fast-forward case, whereas it can't know that for binary files. And yes,\n>> merge conflicts could happen for the same reasons they may happen to\n>> files: The changes in Bob's branch could break something in Alice's\n>> branch. But that applies for files just like it does for submodule\n>> commits, no?\n> \n> Correct. I guess this means that - for the fast-forward case - Git can \n> automatically record this resolution in the index, hence not requiring the \n> user to \"confirm\" the resolution with 'git add'.\n\nYup, I think we agree here and I just wanted to explain our regular\nworkflow and show that such a strategy would help us very much.\n\n\n>> And the non-fast-forward case happens e.g. when Alice and Bob do not wait\n>> for the submodule maintainer to merge their changes:\n>>\n>> Superproject:\n>>   ---2         [Alice's branch]\n>>  /    \\\n>> 1--3---4---5   [master]\n>>     \\     /\n>>      ----6     [Bob's branch]\n>>\n>>      ^   ^\n>>      |   |       [commits of the submodule committed in the superproject]\n>>\n>> Submodule:\n>>   ---B           [feature_a]\n>>  /    \\\n>> A--C---D---E     [master]\n>>     \\     /\n>>      ----F       [feature_b]\n>>\n>> In this case submodule commit 'B' is recorded in '2' and thus '4', while\n>> commit 'F' will be recorded in '6'. So when '4' and '6' are merged, a\n>> valid guess for '5' would be to use submodule commit 'E', as it is the\n>> first one based on both 'B' and 'F'.\n> \n> Again, to verify: The superproject graph (with referenced submodule commits \n> in parentheses) looks like this:\n> \n>    --------2(B)            [Alice's branch]\n>   /         \\\n>  1(A)--3(A)--4(B)---5(?)   [master]\n>         \\          /\n>          ---------6(F)     [Bob's branch]\n\nCorrect.\n\n\n>> But I think this approach will solve a lot of the problems we - and maybe\n>> others - have with submodule merges without doing any harm to other\n>> workflows.\n> \n> For the fast-forward case, I fully agree.\n> \n> For the non-fast-forward case, I would suggest to search for submodule \n> merges that contain both submodule commits (as described in [1]), and then:\n> \n> - If there are no merges, do nothing (leave a conflict).\n> \n> - If there is exactly one merge, then check it out (but do not record it as \n> resolved in the index).\n> \n> - If there are more merge alternatives, present them as equal alternatives, \n> but do nothing (leave a conflict).\n\nNice summary. Heiko, would you please post a new patch implementing this\napproach?\n"},{"id":"143935","messageId":"20100619094301.GA2667@book.hvoigt.net","threadId":"24081","inReplyTo":"4C1B7ABE.8080905@web.de","subject":"Re: Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Heiko Voigt","fromEmail":"hvoigt@hvoigt.net","sentAt":"2010-06-19T09:43:02Z","receivedAt":"2010-06-19T09:43:02Z","isPatch":true,"sender":{"key":"hvoigt@hvoigt.net","avatar":"https://avatars.githubusercontent.com/u/184958?v=4"},"body":"On Fri, Jun 18, 2010 at 03:55:10PM +0200, Jens Lehmann wrote:\n> Am 18.06.2010 11:40, schrieb Johan Herland:\n> > On Thursday 17 June 2010, Jens Lehmann wrote:\n> >> But I think this approach will solve a lot of the problems we - and maybe\n> >> others - have with submodule merges without doing any harm to other\n> >> workflows.\n> > \n> > For the fast-forward case, I fully agree.\n> > \n> > For the non-fast-forward case, I would suggest to search for submodule \n> > merges that contain both submodule commits (as described in [1]), and then:\n> > \n> > - If there are no merges, do nothing (leave a conflict).\n> > \n> > - If there is exactly one merge, then check it out (but do not record it as \n> > resolved in the index).\n> > \n> > - If there are more merge alternatives, present them as equal alternatives, \n> > but do nothing (leave a conflict).\n> \n> Nice summary. Heiko, would you please post a new patch implementing this\n> approach?\n\nYes sure. I agree with the proposed scheme.\n\nAs Jens is working on the automatically checkout submodules extension I\nwill base the merge patch on your branch. Is the checkout_submodule()\nfunction already stable enough to be used?\n\ncheers Heiko\n"},{"id":"143936","messageId":"20100619101736.GA3539@book.hvoigt.net","threadId":"24081","inReplyTo":"201006181140.16652.johan@herland.net","subject":"Re: Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Heiko Voigt","fromEmail":"hvoigt@hvoigt.net","sentAt":"2010-06-19T10:17:41Z","receivedAt":"2010-06-19T10:17:41Z","isPatch":true,"sender":{"key":"hvoigt@hvoigt.net","avatar":"https://avatars.githubusercontent.com/u/184958?v=4"},"body":"Hi,\n\nOn Fri, Jun 18, 2010 at 11:40:16AM +0200, Johan Herland wrote:\n> [1]: To put the search in general terms: Find all merge commits that has \n> _both_ (or in the case of octopus; _all_) of the candidate commits (but none \n> of the other merges) somewhere in its ancestry. You could implement this by \n> first intersecting the sets returned from these commands (run in the \n> submodule):\n> \n>   git rev-list --merges --ancestry-path --all ^B\n>   git rev-list --merges --ancestry-path --all ^F\n> \n> to get the set of merges descending from both 'B' and 'F', and then prune \n> each member in the remaining set that has another set member in its \n> ancestry.\n\nIs the --ancestry-path option already implemented? Because on my git\n1.7.1 it does not seem to. What does it do?\n\ncheers Heiko\n"},{"id":"143938","messageId":"201006191515.25640.johan@herland.net","threadId":"24081","inReplyTo":"20100619101736.GA3539@book.hvoigt.net","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-06-19T13:15:25Z","receivedAt":"2010-06-19T13:15:25Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Saturday 19 June 2010, Heiko Voigt wrote:\n> Hi,\n> \n> On Fri, Jun 18, 2010 at 11:40:16AM +0200, Johan Herland wrote:\n> > [1]: To put the search in general terms: Find all merge commits that\n> > has _both_ (or in the case of octopus; _all_) of the candidate commits\n> > (but none of the other merges) somewhere in its ancestry. You could\n> > implement this by first intersecting the sets returned from these\n> > commands (run in the\n> > \n> > submodule):\n> >   git rev-list --merges --ancestry-path --all ^B\n> >   git rev-list --merges --ancestry-path --all ^F\n> > \n> > to get the set of merges descending from both 'B' and 'F', and then\n> > prune each member in the remaining set that has another set member in\n> > its ancestry.\n> \n> Is the --ancestry-path option already implemented? Because on my git\n> 1.7.1 it does not seem to.\n\nIt was recently merged to 'next'.\n\n> What does it do?\n\nWhen given a commit range (\"$from..$to\", or \"$to ^$from\"), it shows commit \nthat are in $to but not in $from (i.e. the usual), but additionally limits \nthe list to those commits that descend from $from. Another use case for this \nfunctionality is, given a bug introduced in commit $foo, you can list the \ncommit in the master branch that are potentially \"contaminated\" with the \nbug, with the following command:\n\n  git log --ancestry-path $foo..master\n\nSee the --ancestry-path documentation in the jc/rev-list-ancestry-path \nseries for more info.\n\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"143940","messageId":"20100619155208.GB3539@book.hvoigt.net","threadId":"24081","inReplyTo":"201006191515.25640.johan@herland.net","subject":"[WIP PATCH 3/3] implement automatic fast forward merge for submodules","fromName":"Heiko Voigt","fromEmail":"hvoigt@hvoigt.net","sentAt":"2010-06-19T15:52:09Z","receivedAt":"2010-06-19T15:52:09Z","isPatch":true,"sender":{"key":"hvoigt@hvoigt.net","avatar":"https://avatars.githubusercontent.com/u/184958?v=4"},"body":"This implements a simple merge strategy for submodule hashes. We check\nwhether one side of the merge candidates is already contained in the\nother and then merge automatically.\n\nIf both sides contain changes we search for a merge in the submodule.\nIn case a single one exists we check that out and suggest it as the\nmerge resolution. A list of candidates is returned when we find multiple\nmerges that contain both sides of the changes.\n\nThis is useful for a workflow in which the developers can publish topic\nbranches in submodules and a seperate maintainer merges them. In case\nthe developers always wait until their branch gets merged before tracking\nthem in the superproject all merges of branches that contain submodule\nchanges will be resolved automatically. If developers choose to track\ntheir feature branch the maintainer might get a conflict but git will\nsearch the submodule for a merge and suggest it/them as a resolution.\n\nSigned-off-by: Heiko Voigt <hvoigt@hvoigt.net>\n---\n\nThis patch replaces the last one of the previously discussed series. It is\nstill work in progress but already implements the scheme discussed. I have not\nhad the time to adjust the tests so they fail currently. The extension to\nsetup_revisions() is still very hackyish which I will also cleanup in a later\niteration.\n\nThe whole series can also be found on:\n\nhttp://github.com/hvoigt/git/tree/submodule_merge_v2\n\n merge-recursive.c          |    9 ++-\n refs.c                     |    6 ++\n refs.h                     |    1 +\n revision.c                 |   29 ++++++---\n revision.h                 |    1 +\n submodule.c                |  155 ++++++++++++++++++++++++++++++++++++++++++++\n submodule.h                |    2 +\n t/t7405-submodule-merge.sh |  115 +++++++++++++++++++++++++++++++--\n 8 files changed, 300 insertions(+), 18 deletions(-)\n\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 206c103..a032a8b 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -20,6 +20,7 @@\n #include \"attr.h\"\n #include \"merge-recursive.h\"\n #include \"dir.h\"\n+#include \"submodule.h\"\n \n static struct tree *shift_tree_object(struct tree *one, struct tree *two,\n \t\t\t\t      const char *subtree_shift)\n@@ -525,13 +526,15 @@ static void update_file_flags(struct merge_options *o,\n \t\tvoid *buf;\n \t\tunsigned long size;\n \n-\t\tif (S_ISGITLINK(mode))\n+\t\tif (S_ISGITLINK(mode)) {\n \t\t\t/*\n \t\t\t * We may later decide to recursively descend into\n \t\t\t * the submodule directory and update its index\n \t\t\t * and/or work tree, but we do not do that now.\n \t\t\t */\n+\t\t\tupdate_wd = 0;\n \t\t\tgoto update_index;\n+\t\t}\n \n \t\tbuf = read_sha1_file(sha, &type, &size);\n \t\tif (!buf)\n@@ -716,8 +719,8 @@ static struct merge_file_info merge_file(struct merge_options *o,\n \t\t\tfree(result_buf.ptr);\n \t\t\tresult.clean = (merge_status == 0);\n \t\t} else if (S_ISGITLINK(a->mode)) {\n-\t\t\tresult.clean = 0;\n-\t\t\thashcpy(result.sha, a->sha1);\n+\t\t\tresult.clean = merge_submodule(result.sha, one->path, one->sha1,\n+\t\t\t\t\t\t       a->sha1, b->sha1);\n \t\t} else if (S_ISLNK(a->mode)) {\n \t\t\thashcpy(result.sha, a->sha1);\n \ndiff --git a/refs.c b/refs.c\nindex f2de9f5..3882131 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -703,6 +703,12 @@ int for_each_ref(each_ref_fn fn, void *cb_data)\n \treturn do_for_each_ref(NULL, \"refs/\", fn, 0, 0, cb_data);\n }\n \n+int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n+{\n+\treturn do_for_each_ref(submodule, \"refs/\", fn, 0,\n+\t\t\tDO_FOR_EACH_INCLUDE_BROKEN, cb_data);\n+}\n+\n int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)\n {\n \treturn do_for_each_ref(NULL, prefix, fn, strlen(prefix), 0, cb_data);\ndiff --git a/refs.h b/refs.h\nindex 384e311..0889d8b 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -19,6 +19,7 @@ struct ref_lock {\n  */\n typedef int each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data);\n extern int head_ref(each_ref_fn, void *);\n+extern int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);\n extern int for_each_ref(each_ref_fn, void *);\n extern int for_each_ref_in(const char *, each_ref_fn, void *);\n extern int for_each_tag_ref(each_ref_fn, void *);\ndiff --git a/revision.c b/revision.c\nindex b209d49..8955d7c 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -721,12 +721,15 @@ static void init_all_refs_cb(struct all_refs_cb *cb, struct rev_info *revs,\n \tcb->all_flags = flags;\n }\n \n-static void handle_refs(struct rev_info *revs, unsigned flags,\n+static void handle_refs(const char *submodule, struct rev_info *revs, unsigned flags,\n \t\tint (*for_each)(each_ref_fn, void *))\n {\n \tstruct all_refs_cb cb;\n \tinit_all_refs_cb(&cb, revs, flags);\n-\tfor_each(handle_one_ref, &cb);\n+\tif (!submodule)\n+\t\tfor_each(handle_one_ref, &cb);\n+\telse\n+\t\tfor_each_ref_submodule(submodule, handle_one_ref, &cb);\n }\n \n static void handle_one_reflog_commit(unsigned char *sha1, void *cb_data)\n@@ -1357,6 +1360,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n {\n \tint i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0;\n \tconst char **prune_data = NULL;\n+\tconst char *submodule = NULL;\n+\n+\tif (opt)\n+\t\tsubmodule = opt->submodule;\n \n \t/* First, search for \"--\" */\n \tseen_dashdash = 0;\n@@ -1381,26 +1388,30 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \t\t\tint opts;\n \n \t\t\tif (!strcmp(arg, \"--all\")) {\n-\t\t\t\thandle_refs(revs, flags, for_each_ref);\n-\t\t\t\thandle_refs(revs, flags, head_ref);\n+\t\t\t\tif (submodule) {\n+\t\t\t\t\thandle_refs(submodule, revs, flags, NULL);\n+\t\t\t\t} else {\n+\t\t\t\t\thandle_refs(NULL, revs, flags, for_each_ref);\n+\t\t\t\t\thandle_refs(NULL, revs, flags, head_ref);\n+\t\t\t\t}\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--branches\")) {\n-\t\t\t\thandle_refs(revs, flags, for_each_branch_ref);\n+\t\t\t\thandle_refs(NULL, revs, flags, for_each_branch_ref);\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--bisect\")) {\n-\t\t\t\thandle_refs(revs, flags, for_each_bad_bisect_ref);\n-\t\t\t\thandle_refs(revs, flags ^ UNINTERESTING, for_each_good_bisect_ref);\n+\t\t\t\thandle_refs(NULL, revs, flags, for_each_bad_bisect_ref);\n+\t\t\t\thandle_refs(NULL, revs, flags ^ UNINTERESTING, for_each_good_bisect_ref);\n \t\t\t\trevs->bisect = 1;\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--tags\")) {\n-\t\t\t\thandle_refs(revs, flags, for_each_tag_ref);\n+\t\t\t\thandle_refs(NULL, revs, flags, for_each_tag_ref);\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--remotes\")) {\n-\t\t\t\thandle_refs(revs, flags, for_each_remote_ref);\n+\t\t\t\thandle_refs(NULL, revs, flags, for_each_remote_ref);\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!prefixcmp(arg, \"--glob=\")) {\ndiff --git a/revision.h b/revision.h\nindex 568f1c9..0fe4322 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -145,6 +145,7 @@ extern volatile show_early_output_fn_t show_early_output;\n struct setup_revision_opt {\n \tconst char *def;\n \tvoid (*tweak)(struct rev_info *, struct setup_revision_opt *);\n+\tconst char *submodule;\n };\n \n extern void init_revisions(struct rev_info *revs, const char *prefix);\ndiff --git a/submodule.c b/submodule.c\nindex abd5fd5..ac76791 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -6,6 +6,7 @@\n #include \"revision.h\"\n #include \"run-command.h\"\n #include \"diffcore.h\"\n+#include \"refs.h\"\n \n static int add_submodule_odb(const char *path)\n {\n@@ -242,3 +243,157 @@ int checkout_submodule(const char *path, const unsigned char sha1[20], int force\n \n \treturn 0;\n }\n+\n+static int find_first_merges(struct object_array *result, const char *path,\n+\t\tstruct commit *a, struct commit *b)\n+{\n+\tint i, j;\n+\tstruct object_array merges;\n+\tstruct commit *commit;\n+\tint contains_another;\n+\n+\tchar merged_revision[42];\n+\tconst char *rev_args[] = { \"rev-list\", \"--merges\", \"--all\", merged_revision, NULL };\n+\tstruct rev_info revs;\n+\tstruct setup_revision_opt rev_opts;\n+\n+\tmemset(&merges, 0, sizeof(merges));\n+\tmemset(result, 0, sizeof(struct object_array));\n+\tmemset(&rev_opts, 0, sizeof(rev_opts));\n+\n+\t/* get all revisions that merge commit a */\n+\tsnprintf(merged_revision, sizeof(merged_revision), \"^%s\",\n+\t\t\tfind_unique_abbrev(a->object.sha1, 40));\n+\tinit_revisions(&revs, NULL);\n+\trev_opts.submodule = path;\n+\tsetup_revisions(sizeof(rev_args)/sizeof(char *)-1, rev_args, &revs, &rev_opts);\n+\n+\t/* save all revisions from the above list that contain b */\n+\tif (prepare_revision_walk(&revs))\n+\t\tdie(\"revision walk setup failed\");\n+\twhile ((commit = get_revision(&revs)) != NULL) {\n+\t\tstruct object *o = &(commit->object);\n+\t\tif (in_merge_bases(b, (struct commit **) &o, 1)) {\n+\t\t\tadd_object_array(o, NULL, &merges);\n+\t\t}\n+\t}\n+\n+\t/* Now we've got all merges that contain a and b. Prune all\n+\t * merges that contain another found merge and save them in\n+\t * result. */\n+\tfor (i = 0; i < merges.nr; i++) {\n+\t\tstruct commit *m1 = (struct commit *) merges.objects[i].item;\n+\n+\t\tcontains_another = 0;\n+\t\tfor (j = 0; j < merges.nr; j++) {\n+\t\t\tstruct commit *m2 = (struct commit *) merges.objects[j].item;\n+\t\t\tif (i != j && in_merge_bases(m2, &m1, 1)) {\n+\t\t\t\tcontains_another = 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (!contains_another)\n+\t\t\tadd_object_array(merges.objects[i].item,\n+\t\t\t\t\t merges.objects[i].name, result);\n+\t}\n+\n+\tfree(merges.objects);\n+\treturn result->nr;\n+}\n+\n+static void print_commit(struct commit *commit)\n+{\n+\tstatic const char *format = \" %h: %m %s\";\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tstruct pretty_print_context ctx = {0};\n+\tctx.date_mode = DATE_NORMAL;\n+\tformat_commit_message(commit, format, &sb, &ctx);\n+\tstrbuf_addstr(&sb, \"\\n\");\n+\tfprintf(stderr, \"%s\", sb.buf);\n+}\n+\n+int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20],\n+\t\t    const unsigned char a[20], const unsigned char b[20])\n+{\n+\tstruct commit *commit_base, *commit_a, *commit_b;\n+\tint parent_count;\n+\tstruct object_array merges;\n+\n+\tint i;\n+\n+\t/* store a in result in case we fail */\n+\thashcpy(result, a);\n+\n+\t/* we can not handle deletion conflicts */\n+\tif (is_null_sha1(base))\n+\t\treturn 0;\n+\tif (is_null_sha1(a))\n+\t\treturn 0;\n+\tif (is_null_sha1(b))\n+\t\treturn 0;\n+\n+\tif (add_submodule_odb(path)) {\n+\t\twarning(\"Failed to merge submodule %s (not checked out)\", path);\n+\t\treturn 0;\n+\t}\n+\n+\tif (!(commit_base = lookup_commit_reference(base)) ||\n+\t    !(commit_a = lookup_commit_reference(a)) ||\n+\t    !(commit_b = lookup_commit_reference(b)))\n+\t{\n+\t\twarning(\"Failed to merge submodule %s (commits not present)\", path);\n+\t\treturn 0;\n+\t}\n+\n+\t/* 1. case a is contained in b or vice versa */\n+\tif (in_merge_bases(commit_a, &commit_b, 1)) {\n+\t\thashcpy(result, b);\n+\t\treturn 1;\n+\t}\n+\tif (in_merge_bases(commit_b, &commit_a, 1)) {\n+\t\thashcpy(result, a);\n+\t\treturn 1;\n+\t}\n+\n+\t/* 2. case there are one ore more merges that contain a and b the\n+\t * submodule. If there is a single one check it out but leave it\n+\t * marked unmerged so the user needs to confirm the resolution */\n+\n+\t/* are both changes forward */\n+\tif (!in_merge_bases(commit_base, &commit_a, 1) ||\n+\t    !in_merge_bases(commit_base, &commit_b, 1))\n+\t{\n+\t\twarning(\"Submodule rewound can not merge\");\n+\t\treturn 0;\n+\t}\n+\n+\t/* find commit which merges them */\n+\tparent_count = find_first_merges(&merges, path, commit_a, commit_b);\n+\tif (!parent_count) {\n+\t\twarning(\"Failed to merge submodule %s (merge not found)\", path);\n+\t\tgoto finish;\n+\t}\n+\n+\tif (parent_count != 1) {\n+\t\twarning(\"Failed to merge submodule %s (multiple merges found):\", path);\n+\t\tfor (i = 0; i < merges.nr; i++) {\n+\t\t\tprint_commit((struct commit *) merges.objects[i].item);\n+\t\t}\n+\t\tgoto finish;\n+\t}\n+\n+\twarning(\"Failed to merge submodule %s (not fast-forward):\\n\", path);\n+\tfprintf(stderr, \"Found a possible merge resolution for the submodule:\\n\");\n+\tprint_commit((struct commit *) merges.objects[0].item);\n+\tfprintf(stderr, \"If this is correct simply add it to the index for example\\n\"\n+\t\t\t\"by using:\\n\\n\"\n+\t\t\t\"   git add %s\\n\\n\"\n+\t\t\t\"which will accept this suggestion.\\n\", path);\n+\n+\tcheckout_submodule(path, merges.objects[0].item->sha1, 0);\n+\n+finish:\n+\tfree(merges.objects);\n+\treturn 0;\n+}\ndiff --git a/submodule.h b/submodule.h\nindex fc6909e..12d6d73 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -7,5 +7,7 @@ void show_submodule_summary(FILE *f, const char *path,\n \t\tconst char *del, const char *add, const char *reset);\n unsigned is_submodule_modified(const char *path, int ignore_untracked);\n int checkout_submodule(const char *path, const unsigned char sha1[20], int force);\n+int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20],\n+\t\t    const unsigned char a[20], const unsigned char b[20]);\n \n #endif\ndiff --git a/t/t7405-submodule-merge.sh b/t/t7405-submodule-merge.sh\nindex 4a7b893..04dc371 100755\n--- a/t/t7405-submodule-merge.sh\n+++ b/t/t7405-submodule-merge.sh\n@@ -54,13 +54,116 @@ test_expect_success setup '\n \tgit merge -s ours a\n '\n \n-test_expect_success 'merging with modify/modify conflict' '\n+# History setup\n+#\n+#      b\n+#    /   \\\n+#   a     d\n+#    \\   /\n+#      c\n+#\n+# a in the main repository records to sub-a in the submodule and\n+# analogous b and c. d should be automatically found by merging c into\n+# b in the main repository.\n+test_expect_success 'setup for merge search' '\n+\tmkdir merge-search &&\n+\tcd merge-search &&\n+\tgit init &&\n+\tmkdir sub &&\n+\t(cd sub &&\n+\t git init &&\n+\t echo \"file-a\" > file-a &&\n+\t git add file-a &&\n+\t git commit -m \"sub-a\" &&\n+\t git checkout -b sub-a) &&\n+\tgit add sub &&\n+\tgit commit -m \"a\" &&\n+\tgit checkout -b a &&\n+\n+\tgit checkout -b b &&\n+\t(cd sub &&\n+\t git checkout -b sub-b &&\n+\t echo \"file-b\" > file-b &&\n+\t git add file-b &&\n+\t git commit -m \"sub-b\") &&\n+\tgit commit -a -m \"b\" &&\n+\n+\tgit checkout -b c a &&\n+\t(cd sub &&\n+\t git checkout -b sub-c sub-a &&\n+\t echo \"file-c\" > file-c &&\n+\t git add file-c &&\n+\t git commit -m \"sub-c\") &&\n+\tgit commit -a -m \"c\" &&\n+\n+\t(cd sub &&\n+\t git checkout -b sub-d sub-b &&\n+\t git merge sub-c &&\n+\t git checkout sub-b) &&\n+\tgit checkout -b test b &&\n+\tcd ..\n+'\n+\n+test_expect_success 'merging with common parent search' '\n+\tcd merge-search &&\n+\tgit checkout -b test-parent b &&\n+\tgit merge c &&\n+\tgit ls-tree test-parent | grep sub | cut -f1 | cut -f3 -d\" \" > actual &&\n+\t(cd sub &&\n+\t git rev-parse sub-d > ../expect) &&\n+\ttest_cmp actual expect &&\n+\tcd ..\n+'\n+\n+test_expect_success 'merging should fail for ambigous common parent' '\n+\tcd merge-search &&\n+\tgit checkout -b test-ambigous b &&\n+\t(cd sub &&\n+\t git checkout -b ambigous sub-d &&\n+\t echo \"ambigous-file\" > ambigous-file &&\n+\t git add ambigous-file &&\n+\t git commit -m \"ambigous\") &&\n+\ttest_must_fail git merge c &&\n+\tgit reset --hard &&\n+\tcd ..\n+'\n+\n+# in a situation like this\n+#\n+# submodule tree:\n+#\n+#    sub-a --- sub-b --- sub-d\n+#\n+# main tree:\n+#\n+#    e (sub-a)\n+#   /\n+#  d (sub-b)\n+#   \\\n+#    f (sub-d)\n+#\n+# A merge should fail because one change points backwards.\n+\n+test_expect_success 'merging should fail for changes that are backwards' '\n+\tcd merge-search &&\n+\tgit checkout -b d a &&\n+\t(cd sub &&\n+\t git checkout sub-b) &&\n+\tgit commit -a -m \"d\" &&\n+\n+\tgit checkout -b e d &&\n+\t(cd sub &&\n+\t git checkout sub-a) &&\n+\tgit commit -a -m \"e\" &&\n+\n+\tgit checkout -b f d &&\n+\t(cd sub &&\n+\t git checkout sub-d) &&\n+\tgit commit -a -m \"f\" &&\n \n-\tgit checkout -b test1 a &&\n-\ttest_must_fail git merge b &&\n-\ttest -f .git/MERGE_MSG &&\n-\tgit diff &&\n-\ttest -n \"$(git ls-files -u)\"\n+\tgit checkout -b test-backward e &&\n+\ttest_must_fail git merge f &&\n+\tcd ..\n '\n \n test_expect_success 'merging with a modify/modify conflict between merge bases' '\n-- \n1.7.1.465.g3692.dirty\n"},{"id":"143941","messageId":"4C1CE848.5020602@web.de","threadId":"24081","inReplyTo":"20100619094301.GA2667@book.hvoigt.net","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2010-06-19T15:54:48Z","receivedAt":"2010-06-19T15:54:48Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 19.06.2010 11:43, schrieb Heiko Voigt:\n> On Fri, Jun 18, 2010 at 03:55:10PM +0200, Jens Lehmann wrote:\n>> Nice summary. Heiko, would you please post a new patch implementing this\n>> approach?\n> \n> Yes sure. I agree with the proposed scheme.\n\nThank you very much!\n\n\n> As Jens is working on the automatically checkout submodules extension I\n> will base the merge patch on your branch. Is the checkout_submodule()\n> function already stable enough to be used?\n\nUnfortunately not (the checkout itself is working fine, but the test if\nthe checkout would overwrite local changes in the submodules is still\nmissing, so be warned!).\n"},{"id":"143960","messageId":"7vzkyptwat.fsf@alter.siamese.dyndns.org","threadId":"24081","inReplyTo":"201006181140.16652.johan@herland.net","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-06-20T18:04:42Z","receivedAt":"2010-06-20T18:04:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johan Herland <johan@herland.net> writes:\n\n> On Thursday 17 June 2010, Jens Lehmann wrote:\n> ...\n>> And no 'special' branch is used here.\n>\n> Well, you need to traverse _some_ submodule ref(s) in order to find 'E' at \n> all. My argument is that there may also be _other_ submodule refs that \n> contain merges of 'B' and 'F' as well, and they should _also_ be considered \n> as valid candidates for the resolution in '5'. I would in fact argue that \n> you should traverse _all_ submodule refs (maybe even including remote-\n> tracking refs) to look for merges of 'B' and 'F' [1], and present them all \n> as equal alternatives.\n>\n> Consider for example this submodule scenario:\n>\n>         -----------G      [maint]\n>        /          /\n>    ---B--------  /        [feature_a]\n>   /    \\       \\/\n>  A--C---D---E  /\\         [master]\n>      \\     /  /  \\\n>       ----F---    \\       [feature_b]\n>               \\    \\\n>                --H--I--J  [next]\n>\n> If there exist multiple merges that resolve 'B' and 'F' (in this case: 'G', \n> 'E' and 'I'), then all of those should be presented as equal alternatives to \n> the user.\n\nYou lost me completely here.\n\nI thought you were going to argue that it would be an utterly wrong thing\nto suggest E or I as a probably resolution if the superproject merge that\nneeds to merge superproject commits that binds B and F as its submodules\nis being done in the context of advance 'maint' track of the superproject.\n\nThink of 'D' as a commit that corresponds to a major version bump point of\nthe superproject; i.e. it introduces a major change to the submodule.  In\nthe 'maintenance track' of the superproject for maintaining the previous\nversion, you don't want to have any commit that has 'D' as an ancestor.\n\nFor an \"automated\" heuristics based on \"find common descendants\" to make\nsense, the branches you are merging have to share the common purpose, and\nyou need to limit the common descendants you find to the ones that are\ncompatible with the shared purpose.  The purpose of 'maintenance track'\nmay be to maintain the previous version without dragging newer and more\nexciting things that happened in the later development.  In the above\npicture, G (that has nothing but B and F) is the only commit that can be\nsafely assumed that two commits in the superproject space that bind B and\nF respectively can use as the submodule as their merge result.  E and I\nare contaminated with D and H whose purpose in the superproject space is\nunknown without further hint.\n"},{"id":"143966","messageId":"201006210106.07758.johan@herland.net","threadId":"24081","inReplyTo":"7vzkyptwat.fsf@alter.siamese.dyndns.org","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-06-20T23:06:07Z","receivedAt":"2010-06-20T23:06:07Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Sunday 20 June 2010, Junio C Hamano wrote:\n> Johan Herland <johan@herland.net> writes:\n> > On Thursday 17 June 2010, Jens Lehmann wrote:\n> > ...\n> > \n> >> And no 'special' branch is used here.\n> > \n> > Well, you need to traverse _some_ submodule ref(s) in order to find 'E'\n> > at all. My argument is that there may also be _other_ submodule refs\n> > that contain merges of 'B' and 'F' as well, and they should _also_ be\n> > considered as valid candidates for the resolution in '5'. I would in\n> > fact argue that you should traverse _all_ submodule refs (maybe even\n> > including remote- tracking refs) to look for merges of 'B' and 'F'\n> > [1], and present them all as equal alternatives.\n> > \n> > Consider for example this submodule scenario:\n> >         -----------G      [maint]\n> >        /          /\n> >    ---B--------  /        [feature_a]\n> >   /    \\       \\/\n> >  A--C---D---E  /\\         [master]\n> >      \\     /  /  \\\n> >       ----F---    \\       [feature_b]\n> >               \\    \\\n> >                --H--I--J  [next]\n> > \n> > If there exist multiple merges that resolve 'B' and 'F' (in this case:\n> > 'G', 'E' and 'I'), then all of those should be presented as equal\n> > alternatives to the user.\n> \n> You lost me completely here.\n> \n> I thought you were going to argue that it would be an utterly wrong thing\n> to suggest E or I as a probably resolution if the superproject merge that\n> needs to merge superproject commits that binds B and F as its submodules\n> is being done in the context of advance 'maint' track of the\n> superproject.\n> \n> Think of 'D' as a commit that corresponds to a major version bump point\n> of the superproject; i.e. it introduces a major change to the submodule.\n>  In the 'maintenance track' of the superproject for maintaining the\n> previous version, you don't want to have any commit that has 'D' as an\n> ancestor.\n> \n> For an \"automated\" heuristics based on \"find common descendants\" to make\n> sense, the branches you are merging have to share the common purpose, and\n> you need to limit the common descendants you find to the ones that are\n> compatible with the shared purpose.  The purpose of 'maintenance track'\n> may be to maintain the previous version without dragging newer and more\n> exciting things that happened in the later development.  In the above\n> picture, G (that has nothing but B and F) is the only commit that can be\n> safely assumed that two commits in the superproject space that bind B and\n> F respectively can use as the submodule as their merge result.  E and I\n> are contaminated with D and H whose purpose in the superproject space is\n> unknown without further hint.\n\nYes, from a 'maint'-perspective, using G in the superproject probably makes \nmore sense than using E or I. From a different superproject perspective, \nthough, using E or I might make more sense. If, say, the superproject \ncustomarily follows the commits on the 'master' branch in the submodule, but \nthe superproject has not yet gotten around to updating from A to C, D or E, \nthen, by the time we do the superproject merge of Alice and Bob's branches, \nI would still say that using E is better than using G.\n\nMy argument is that without knowing the purpose of the superproject merge \n(which Git by itself _cannot_ know), Git should not prefer _any_ of these \nmerges over the other, but must present them all as equal alternatives to \nthe user.\n\nOf course, the user has other alternatives as well, like creating a whole \nnew merge in the submodule, or doing something completely different. But if \nexisting submodule merges are to be considered valid alternatives, Git \ncannot pretend to know which of those merges are more suitable. It can only \npresent them to the user, and then the user (after having examined the \nmerges and their history relative to B and F) may choose the merge that \nmatches the purpose of the superproject merge.\n\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"143967","messageId":"7vk4pttfo3.fsf@alter.siamese.dyndns.org","threadId":"24081","inReplyTo":"201006210106.07758.johan@herland.net","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-06-21T00:03:56Z","receivedAt":"2010-06-21T00:03:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johan Herland <johan@herland.net> writes:\n\n>> For an \"automated\" heuristics based on \"find common descendants\" to make\n>> sense, the branches you are merging have to share the common purpose, and\n>> you need to limit the common descendants you find to the ones that are\n>> compatible with the shared purpose.  The purpose of 'maintenance track'\n>> may be to maintain the previous version without dragging newer and more\n>> exciting things that happened in the later development.  In the above\n>> picture, G (that has nothing but B and F) is the only commit that can be\n>> safely assumed that two commits in the superproject space that bind B and\n>> F respectively can use as the submodule as their merge result.  E and I\n>> are contaminated with D and H whose purpose in the superproject space is\n>> unknown without further hint.\n>\n> Yes, from a 'maint'-perspective, using G in the superproject probably makes \n> more sense than using E or I. From a different superproject perspective, \n> though, using E or I might make more sense.\n\nActually, what I was alluding to was that 'G' would be the _only_ commit\nthat may make sense (note that G may not necessarily make sense, but the\npoint is that we can say that others do _not_ make sense as alternatives)\nif we know that the context of making the superproject merge is that it is\ndoing the 'maintenance track' merge.  Similarly, if we know that the merge\nbeing done in the superproject is in the 'master' context, 'E' would be\nthe _only_ plausible candidate, similarly for 'I' in 'next' context.\n\nIt is further plausible to imagine that the .gitmodules file tracked in\nthe superproject's 'maint' branch can be used to express that 'maint'\nbranch of the submodule should be used.\n\nIf we revisit the Alice and Bob example with such an arrangement, if they\nwere working on their branches so that their results would be included in\nthe 'maint' track of the superproject, there won't be a merge conflict in\nthe .gitmodules file at the superproject level when their branch tips are\nmerged; we will know that the merged .gitmodules file will tell us that we\nwould want to follow 'maint' branch of the submodule.\n\nSimilarly if Alice were fixing a bug in 'maint' but Bob were advancing\nfeatures in 'master', then merging .gitmodules at the superproject level\nwill fast-forward at the path level (i.e. Alice didn't touch, but Bob\nchanged, so we take Bob's change), instructing us to follow 'master'\nbranch from the submodule automatically.\n"},{"id":"143975","messageId":"201006211219.02911.johan@herland.net","threadId":"24081","inReplyTo":"7vk4pttfo3.fsf@alter.siamese.dyndns.org","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-06-21T10:19:02Z","receivedAt":"2010-06-21T10:19:02Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Monday 21 June 2010, Junio C Hamano wrote:\n> Johan Herland <johan@herland.net> writes:\n> >> For an \"automated\" heuristics based on \"find common descendants\" to\n> >> make sense, the branches you are merging have to share the common\n> >> purpose, and you need to limit the common descendants you find to the\n> >> ones that are compatible with the shared purpose.  The purpose of\n> >> 'maintenance track' may be to maintain the previous version without\n> >> dragging newer and more exciting things that happened in the later\n> >> development.  In the above picture, G (that has nothing but B and F)\n> >> is the only commit that can be safely assumed that two commits in the\n> >> superproject space that bind B and F respectively can use as the\n> >> submodule as their merge result.  E and I are contaminated with D and\n> >> H whose purpose in the superproject space is unknown without further\n> >> hint.\n> > \n> > Yes, from a 'maint'-perspective, using G in the superproject probably\n> > makes more sense than using E or I. From a different superproject\n> > perspective, though, using E or I might make more sense.\n> \n> Actually, what I was alluding to was that 'G' would be the _only_ commit\n> that may make sense (note that G may not necessarily make sense, but the\n> point is that we can say that others do _not_ make sense as alternatives)\n> if we know that the context of making the superproject merge is that it\n> is doing the 'maintenance track' merge.  Similarly, if we know that the\n> merge being done in the superproject is in the 'master' context, 'E'\n> would be the _only_ plausible candidate, similarly for 'I' in 'next'\n> context.\n\nAh, so Git should automatically _eliminate_ other alternatives based on the \nfact that they are not compatible with the purpose of the superproject \nmerge. Still, that requires Git to know the purpose of the superproject \nmerge. Which it doesn't, AFAICS.\n\n> It is further plausible to imagine that the .gitmodules file tracked in\n> the superproject's 'maint' branch can be used to express that 'maint'\n> branch of the submodule should be used.\n\nOk, so you want to create some kind of relationship between the \nsuperproject's 'maint' branch and the submodule's 'maint' branch. At this \npoint we're almost back to the (magic IMHO) \"stable\" branch setting that \nHeiko alluded to in his initial patch series. Except, possibly, that instead \nof using the tip of that branch you'd use the first merge of B and F on that \nbranch.\n\nI still don't like this, as IMHO it's too subtle, and possibly conflicts \nwith explicitly tracking submodule branches (which, to me, is a more \nimportant feature).\n\n\nOr are you talking about outright tracking submodule branches (as proposed \nby Ævar in a different thread)? In that case, the issue changes completely:\n\nIf you're explicitly tracking the 'maint' branch in the submodule, then IMHO \nGit should always propose the tip of the submodule's 'maint' branch as the \nmerge resolution in the superproject (possibly with a warning printed if \nthat tip does not descend from both B and F).\n\n> If we revisit the Alice and Bob example with such an arrangement, if they\n> were working on their branches so that their results would be included in\n> the 'maint' track of the superproject, there won't be a merge conflict in\n> the .gitmodules file at the superproject level when their branch tips are\n> merged; we will know that the merged .gitmodules file will tell us that\n> we would want to follow 'maint' branch of the submodule.\n>\n> Similarly if Alice were fixing a bug in 'maint' but Bob were advancing\n> features in 'master', then merging .gitmodules at the superproject level\n> will fast-forward at the path level (i.e. Alice didn't touch, but Bob\n> changed, so we take Bob's change), instructing us to follow 'master'\n> branch from the submodule automatically.\n\nOk, so these are similar to Ævar's proposal (and its subsequent discussion) \nfor explicitly tracking submodule branches. Still not sure if we're actually \ntalking about the same thing, though.\n\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"143976","messageId":"7vlja8if5r.fsf@alter.siamese.dyndns.org","threadId":"24081","inReplyTo":"201006211219.02911.johan@herland.net","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-06-21T15:22:40Z","receivedAt":"2010-06-21T15:22:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johan Herland <johan@herland.net> writes:\n\n> I still don't like this, as IMHO it's too subtle, and possibly conflicts \n> with explicitly tracking submodule branches (which, to me, is a more \n> important feature).\n\nIf you mean, by \"explicitly tracking\", to say \"I don't care which commit\nfrom the submodule appears at this path, as long as it is at the tip of\nthis branch\", I still don't think it makes much sense, but what I outlined\nis not _incompatible_ with such a scheme.  In fact I think it would rather\nfit naturally as a sanity/safety measure.\n\nI presume that in your \"explicitly tracked\" world, if the user tries to\ncommit at the superproject level with a submodule commit that is\ninconsistent with that \"explicitly tracked\" branch (e.g. the commit is not\nreachable from the tip of that branch), you would issue a warning of some\nsort, using that knowledge.  What I outlined uses the exact same knowledge\nof which branch in the submodule the superproject branch is tied to to\nreject irrelevant existing merges as resolution candidates.\n\nOf course, this \".gitmodule in superproject can tell you which branch of\nsubmodule it follows\" is optional; the user needs to take responsibility\nof picking the right one among I, E and G, of course, if the information\ndoes not exist or is not available.\n"},{"id":"144016","messageId":"201006220035.31166.johan@herland.net","threadId":"24081","inReplyTo":"7vlja8if5r.fsf@alter.siamese.dyndns.org","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-06-21T22:35:30Z","receivedAt":"2010-06-21T22:35:30Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Monday 21 June 2010, Junio C Hamano wrote:\n> Johan Herland <johan@herland.net> writes:\n> > I still don't like this, as IMHO it's too subtle, and possibly\n> > conflicts with explicitly tracking submodule branches (which, to me,\n> > is a more important feature).\n> \n> If you mean, by \"explicitly tracking\", to say \"I don't care which commit\n> from the submodule appears at this path, as long as it is at the tip of\n> this branch\", I still don't think it makes much sense, but what I\n> outlined is not _incompatible_ with such a scheme.  In fact I think it\n> would rather fit naturally as a sanity/safety measure.\n\nI'll first try to explain where I'm coming from, to hopefully eliminate any \nconfusion about my position:\n\nIMHO, there should be 2 primary modes for submodules in Git:\n\nA. Explicitly tracking submodule commits. This is the existing submodule \nbehaviour. The superproject refers directly (in its tree) to a submodule \ncommit. The .gitmodules file contains associated information \n(submodule.<name>.path, .url and .update).\n\nB. Explicitly tracking submodule branches. An extra setting \n(submodule.<name>.branch) is added to the .gitmodules file, to determine \nwhich submodule branch to checkout. This setting overrides whatever \nsubmodule commit, if any, is stored in the superproject tree. There are two \nsub-modes for this mode:\n\nB.1. There is no submodule entry at all in the superproject tree. This \nindicates that you are not at all interested in tracking the history of the \nsubmodule relative to the superproject. You are always interested in \nchecking out the tip of submodule.<name>.branch in the submodule, even when \ndigging into the superproject's history.\n\nB.2. There is a submodule entry in the superproject tree. This \"hybrid\" \napproach indicates that although you primarily want to track a branch in the \nsubmodule (i.e. you mostly want the latest version of the submodule's \nbranch), you still want a record of where your submodule has been pointing, \nin your superproject's history. Exactly when (or how often) the \nsuperproject's submodule entry should be updated is yet TBD. So is when to \ncheck out according to .branch, and when to use the recorded submodule \ncommit. In the end, it'll probably be a policy decision for the projects \nthat choose this approach.\n\nOk, that hopefully explains the basic idea of tracking submodule commits (A) \nvs. tracking submodule branches (B). Now, how would this apply to merging \nsubmodules?\n\nIn case of B, I'd argue that the submodule merging should _only_ look at the \nvalue of submodule.<name>.branch from the superproject's .gitmodules. If \nthis setting is ambiguous (because of merge conflicts in .gitmodules), Git \nshould not touch the submodule at all (until .gitmodules is resolved). \nOtherwise, Git's only task is to checkout whatever branch is specified by \n.gitmodules. If the commit that is checked out does not descend from all of \nthe merge alternatives, a warning should be printed.\n\nWith that in mind, I enter this discussion because it might provide insight \non how to solve the problem of merging submodules in scenario A.\n\nIn mode A there is no submodule.<name>.branch setting, and I would not like \nto add an additional setting (let's call it submodule.<name>.merge_branch \nfor now) that is \"weaker\" than submodule.<name>.branch (meaning that it does \nnot trigger the transition from mode A to mode B). There are two major \nreasons for this:\n\n1. submodule.<name>.merge_branch would add semantics to the case of merging \nsubmodules that would be similar in spirit to what submodule.<name>.branch \ndoes (the \"spirit\" here is the special relationship to a submodule branch \nthat we're establishing), but still the .merge_branch setting would be \ndifferent in practice, by (a) only applying to the case of merging \nsubmodules (while .branch changes the semantics of almost all submodule \noperations), and (b) not even in the case of merging submodules would the \noptions do the same thing. I fear the semantics of the .merge_branch option \nwould be too complicated for an average user, and that its similarity to \n.branch would cause confusion.\n\n2. What would happen if you enabled _both_ .merge_branch and .branch? In the \ncase of merging submodules which setting will \"win\"? Even worse, if you set \n.merge_branch to \"foo\", and .branch to \"bar\", what will then happen?\n\nOk, so if I oppose adding .merge_branch, what do I propose instead?\n\nCurrently, not much, I'm afraid. But I have a gut feeling that the use case \npresented by Heiko and Jens is best solved EITHER by having no special \nbranch relationships between the superproject and submodule (which AFAICS is \nwhat we currently agree on in this thread, and Heiko has already submitted a \npatch to this effect), OR by employing a conservative version of mode B.2 in \nwhich we use .branch to track a submodule branch, but still keep a close \nlook at the recorded submodule commit, and, if necessary, maybe introduce \nsome other options to tell Git when to use the recorded commit, and when to \nuse the branch tip.\n\nIn other words, I think we should explore the .branch direction before we \nadd complexity and potential confusion by prematurely adding another option \nthat it somewhat similar to .branch in some contexts.\n\n> I presume that in your \"explicitly tracked\" world, if the user tries to\n> commit at the superproject level with a submodule commit that is\n> inconsistent with that \"explicitly tracked\" branch (e.g. the commit is\n> not reachable from the tip of that branch), you would issue a warning of\n> some sort, using that knowledge.\n\nYes.\n\n> What I outlined uses the exact same\n> knowledge of which branch in the submodule the superproject branch is\n> tied to to reject irrelevant existing merges as resolution candidates.\n\nTrue, but as I've argued above, I'm not sure that adding another setting \n(aka. .merge_branch) for this special/limited kind of branch tracking is \nworth it.\n\n> Of course, this \".gitmodule in superproject can tell you which branch of\n> submodule it follows\" is optional; the user needs to take responsibility\n> of picking the right one among I, E and G, of course, if the information\n> does not exist or is not available.\n\nYes, of course. And this corresponds to what I've proposed for scenario A, \nwhen there is no branch-related setting specified for the submodule.\n\n\nHope this helps,\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"144022","messageId":"7vmxung1bk.fsf@alter.siamese.dyndns.org","threadId":"24081","inReplyTo":"201006220035.31166.johan@herland.net","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-06-22T04:04:31Z","receivedAt":"2010-06-22T04:04:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johan Herland <johan@herland.net> writes:\n\n> True, but as I've argued above, I'm not sure that adding another setting \n> (aka. .merge_branch) for this special/limited kind of branch tracking is \n> worth it.\n\nI don't think .merge_branch is necessary nor even desired.  In fact, I\nthink your use of .branch, especially in the variant that does not have\nany submodule entry in the superproject tree, of your version (B) does not\nhave conceptual advantage.  You checkout the superproject first (which\nwould be the natural thing to do, as you may get update to its .gitmodules\nthere), and checkout the then-tip of the named branch of the submodule,\nyou would immediately get a stale checkout when you then go fetch the\nupdates to the submodule.\n\nAnd the worst part is that you wouldn't even _notice_ that your checkout\nis stale, as there is no record in the superproject which commit you were\nsupposed to be using to be consistent with the version the committer of\nthe superproject commit used to record it.\n\nI on the other hand think what you called \"hybrid\" makes sense (and I\ndon't even think it is hybrid but rather is a natural way to do this).\nWith the submodule.*.branch entry, you can:\n\n - make sure that your checkout is consistent; if your submodule checks\n   out a different commit or branch from what the superproject records in\n   its tree or in its .gitmodules (e.g. you forgot to update the submodule\n   when you switched superproject branch), git can notice the situation\n   and can help you implement policy decisions;\n\n - record a commit that is different from the tip of the submodule branch\n   when making a superproject commit; git can notice the situation and can\n   help you implement policy decisions (e.g. you could choose to reject\n   and tell the user to advance the submodule branch first before making\n   the commit in the superproject);\n\n - use it as an advisory \"existing merge commit selector\", as discussed in\n   this thread.\n\nThinking about what would happen in your (B) that doesn't record the exact\ncommit, I think that it doesn't have any advantage over the \"hybrid\" one.\nThe \"hybrid\" one can help you to make sure that what you commit in the\nsuperproject's .gitmodules and submodule's branch tip are kept consistent.\nWhen they are kept consistent, then switching branches in the superproject\nshould always flip between the tips of branches, no?\n"},{"id":"144031","messageId":"201006221248.08756.jherland@gmail.com","threadId":"24081","inReplyTo":"7vmxung1bk.fsf@alter.siamese.dyndns.org","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Johan Herland","fromEmail":"jherland@gmail.com","sentAt":"2010-06-22T10:48:08Z","receivedAt":"2010-06-22T10:48:08Z","isPatch":true,"sender":{"key":"jherland@gmail.com","avatar":null},"body":"On Tuesday 22 June 2010, Junio C Hamano wrote:\n> Johan Herland <johan@herland.net> writes:\n> > True, but as I've argued above, I'm not sure that adding another\n> > setting (aka. .merge_branch) for this special/limited kind of\n> > branch tracking is worth it.\n>\n> I don't think .merge_branch is necessary nor even desired.\n\nGood.\n\n> In fact, \n> I think your use of .branch, especially in the variant that does not\n> have any submodule entry in the superproject tree, of your version\n> (B) does not have conceptual advantage.  You checkout the\n> superproject first (which would be the natural thing to do, as you\n> may get update to its .gitmodules there), and checkout the then-tip\n> of the named branch of the submodule, you would immediately get a\n> stale checkout when you then go fetch the updates to the submodule.\n\nNot if the initial checkout of the submodule included an implicit \nfetch/pull within the submodule (exact behaviour probably to be \ncontrolled with some config).\n\n> And the worst part is that you wouldn't even _notice_ that your\n> checkout is stale, as there is no record in the superproject which\n> commit you were supposed to be using to be consistent with the\n> version the committer of the superproject commit used to record it.\n\nThe idea (in B.1.) is that if you _truly_ don't care which version of \nthe submodule you're checking out, then there should be no submodule \nentry in the superproject that would \"pollute\" your status/diffs.\n\nNote that I'm not in this camp myself, as I would very much like to keep \ntrack of where my submodule is (and has been) checked out. So I'll stop \ntrying to argue for a use case that I'm not going to use. At the time, \nit seemed like a logical conclusion of the tracking-submodule-branches \ndebate, but if it's not going to be used in practice, there's no point \nin keeping it alive.\n\n> I on the other hand think what you called \"hybrid\" makes sense (and I\n> don't even think it is hybrid but rather is a natural way to do\n> this).\n\nAgreed. I too believe that the \"hybrid\" is much more useful in practice \nthan the extreme version (without a gitlink entry in the superproject).\n\nBut I also believe that Git shouldn't enforce specific workflows, so \nthat if people actually want to track submodule branches in the \nnon-\"hybrid\" (haphazard) manner, then Git should not stand in their \nway.\n\nOn the other hand, if nobody's gonna do this, there's no point in \nimplementing support for it.\n\n> With the submodule.*.branch entry, you can: \n>\n>  - make sure that your checkout is consistent; if your submodule\n> checks out a different commit or branch from what the superproject\n> records in its tree or in its .gitmodules (e.g. you forgot to update\n> the submodule when you switched superproject branch), git can notice\n> the situation and can help you implement policy decisions;\n>\n>  - record a commit that is different from the tip of the submodule\n> branch when making a superproject commit; git can notice the\n> situation and can help you implement policy decisions (e.g. you could\n> choose to reject and tell the user to advance the submodule branch\n> first before making the commit in the superproject);\n>\n>  - use it as an advisory \"existing merge commit selector\", as\n> discussed in this thread.\n\nAh, I see. IINM you indeed prefer to use the same setting (aka. \nsubmodule.<name>.branch) for controlling both the merging of submodules \n(as discussed in this thread), and the other aspects of the submodule \nbranch tracking feature. We agree here.\n\nHowever, it seems you would like the .branch setting to be more advisory \nin nature: Instead of blindly checking out whatever .branch specifies, \nyou'd rather have a more careful interplay where the .branch option \nshould only check whether it is consistent with what happens to be \nchecked out in the submodule, and warn when this is not the case.\n\nThis may be better than what I suggested, but it's hard to say anything \nfor sure until the various alternatives are tested in practice.\n\n> Thinking about what would happen in your (B) that doesn't record the\n> exact commit, I think that it doesn't have any advantage over the\n> \"hybrid\" one. The \"hybrid\" one can help you to make sure that what\n> you commit in the superproject's .gitmodules and submodule's branch\n> tip are kept consistent. When they are kept consistent, then\n> switching branches in the superproject should always flip between the\n> tips of branches, no?\n\nYes, if branch \"foo\" in the superproject records \"branch = subfoo\" \nin .gitmodules, and the current tip of \"subfoo\" as a gitlink, and \nbranch \"bar\" in the superproject records \"branch = subbar\" \nin .gitmodules and the current tip of \"subbar\" as a gitlink, then, \nindeed, switching between these two branches should auto-flip between \nthe branch tips.\n\nOne of the remaining questions is what happens when the superproject \ndoes not change, but commits are added to the submodule branches. Now, \nwhen switching between branches in the superproject, should Git:\n\n1. Do nothing (this is the current behaviour, the user is forced to 'git \nsubmodule update' after 'git checkout' in the superproject)\n\n2. Only checkout the recorded gitlink (this defeats the purpose of \nbranch-tracking, IMO)\n\n3. Checkout the recorded gitlink, but warn about the updated branch tip \n(a valid behaviour IMO)\n\n4. Checkout the updated branch tip of the submodule, and warn about the \nout-of-date gitlink entry (also a valid behaviour IMO)\n\n5. Checkout the updated branch tip AND stage a new gitlink in the \nsuperproject (this is a bit to \"magic\", IMO)\n\n\n...Johan\n\n-- \nJohan Herland, <jherland@gmail.com>\nwww.herland.net\n"},{"id":"144057","messageId":"20100623073828.GA13602@pvv.org","threadId":"24081","inReplyTo":"201006211219.02911.johan@herland.net","subject":"Re: [WIP PATCH 0/3] implement merge strategy for submodule links","fromName":"Finn Arne Gangstad","fromEmail":"finnag@pvv.org","sentAt":"2010-06-23T07:38:28Z","receivedAt":"2010-06-23T07:38:28Z","isPatch":true,"sender":{"key":"finnag@pvv.org","avatar":"https://gravatar.com/avatar/b421ddd58c3f0f93aa473e17b98bb8d53c221fef741746bc8cb59fae4ec6d95e?d=mp&s=160"},"body":"On Mon, Jun 21, 2010 at 12:19:02PM +0200, Johan Herland wrote:\n> \n> Ah, so Git should automatically _eliminate_ other alternatives based on the \n> fact that they are not compatible with the purpose of the superproject \n> merge. Still, that requires Git to know the purpose of the superproject \n> merge. Which it doesn't, AFAICS.\n\nThis appears to be a good time to resuscitate an idea we had a while ago:\n\nWhy not make merging recursive wrt submodules?\n\nI have been trying for some time to figure out how to use git for some\nhuge projects that consist of hundreds of more or less tightly coupled\nmodules. Some of these modules are used for multiple projects, and\ntaken together they are too large to fit well into a single repository.\n\nI wouuld like to be able to use submodules to achieve several things:\n\n1. Partial clones/checkouts - clone only the modules you need\n2. Make git behave for projects that are too large for a single repo\n3. Bonus: share some modules between muptiple projects\n\nNow - for each superproject I would like this to behave as closely as\npossible to working with a single repo, so for merging this would mean\nthat any merge from toplevel would automatically do the merge in all\naffected submodules as well. Just merge the sha1's directly, don't try\nto be clever - merge as if it was a subdirectory.\n\n- Finn Arne\n"}]}