{"thread":{"id":"46351","subject":"[GSoC] Update: Week 8","startedAt":"2017-07-10T22:45:25Z","lastAt":"2017-07-10T23:43:01Z","messageCount":14,"participants":["Prathamesh Chavan","Brandon Williams","Stefan Beller"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"324120","messageId":"CAME+mvU_8-S4AhTtMYm1L6PK81v23wu4EuB+EnOgkDhi=jo9Rg@mail.gmail.com","threadId":"46351","inReplyTo":null,"subject":"[GSoC] Update: Week 8","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-10T22:45:19Z","receivedAt":"2017-07-10T22:45:25Z","isPatch":false,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"SUMMARY OF MY PROJECT:\n\nGit submodule subcommands are currently implemented by using shell script\n'git-submodule.sh'. There are several reasons why we'll prefer not to\nuse the shell script. My project intends to convert the subcommands into\nC code, thus making them builtins. This will increase Git's portability\nand hence the efficiency of working with the git-submodule commands.\nLink to the complete proposal: [1]\n\nMentors:\nStefan Beller <sbeller@google.com>\nChristian Couder <christian.couder@gmail.com>\n\nUPDATES:\n\nFollowing are the updates about my ongoing project:\n\n1. deinit: This patch is updated after its last review.\n   and the updated one is attached with this update.\n\n2. summary: Most of the time of the week was utilized for debugging\n   this patch. Its debugging is completed and the patch also went\n   under some review off the mailing list. Hence, this patch is also\n   attached for review in the latest update.\n\nPLAN FOR WEEK-9 (11 July 2017 to 17 July 2017):\n\n1. In this week a new version of 'deinit' patch is included, and well\n   as the first version of 'summary' is also included. In the following\n   week, I aim to work on improvising these patches.\n\n2. Apart from that, I also aim to work on getting the rest of the patches\n   ('status', 'sync', and other functions) merged.\n\n3. There is still work left with the foreach patch, and I wasn't able\n   to work on this week. Hence, I will work on finding a way of generating\n   the path variable without any hacks.\n\n[1]: https://docs.google.com/document/d/1krxVLooWl--75Pot3dazhfygR3wCUUWZWzTXtK1L-xU/\n\nThanks,\nPrathamesh Chavan\n"},{"id":"324123","messageId":"20170710225407.29344-2-pc44800@gmail.com","threadId":"46351","inReplyTo":"20170710225407.29344-1-pc44800@gmail.com","subject":"[GSoC][PATCH 2/8] submodule--helper: introduce for_each_submodule_list()","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-10T22:54:01Z","receivedAt":"2017-07-10T22:54:29Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"Introduce function for_each_submodule_list() and\nreplace a loop in module_init() with a call to it.\n\nThe new function will also be used in other parts of the\nsystem in later patches.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 39 +++++++++++++++++++++++++++++----------\n 1 file changed, 29 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 7af4de09b..e41572f7a 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -14,6 +14,9 @@\n #include \"refs.h\"\n #include \"connect.h\"\n \n+typedef void (*submodule_list_func_t)(const struct cache_entry *list_item,\n+\t\t\t\t      void *cb_data);\n+\n static char *get_default_remote(void)\n {\n \tchar *dest = NULL, *ret;\n@@ -352,17 +355,30 @@ static int module_list(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static void init_submodule(const char *path, const char *prefix, int quiet)\n+static void for_each_submodule_list(const struct module_list list,\n+\t\t\t\t    submodule_list_func_t fn, void *cb_data)\n {\n+\tint i;\n+\tfor (i = 0; i < list.nr; i++)\n+\t\tfn(list.entries[i], cb_data);\n+}\n+\n+struct init_cb {\n+\tconst char *prefix;\n+\tunsigned int quiet: 1;\n+};\n+#define INIT_CB_INIT { NULL, 0 }\n+\n+static void init_submodule(const struct cache_entry *list_item, void *cb_data)\n+{\n+\tstruct init_cb *info = cb_data;\n \tconst struct submodule *sub;\n \tstruct strbuf sb = STRBUF_INIT;\n \tchar *upd = NULL, *url = NULL, *displaypath;\n \n-\t/* Only loads from .gitmodules, no overlay with .git/config */\n-\tgitmodules_config();\n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath(list_item->name, info->prefix);\n \n-\tsub = submodule_from_path(null_sha1, path);\n+\tsub = submodule_from_path(null_sha1, list_item->name);\n \n \tif (!sub)\n \t\tdie(_(\"No url found for submodule path '%s' in .gitmodules\"),\n@@ -374,7 +390,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t *\n \t * Set active flag for the submodule being initialized\n \t */\n-\tif (!is_submodule_active(the_repository, path)) {\n+\tif (!is_submodule_active(the_repository, list_item->name)) {\n \t\tstrbuf_addf(&sb, \"submodule.%s.active\", sub->name);\n \t\tgit_config_set_gently(sb.buf, \"true\");\n \t}\n@@ -416,7 +432,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t\tif (git_config_set_gently(sb.buf, url))\n \t\t\tdie(_(\"Failed to register url for submodule path '%s'\"),\n \t\t\t    displaypath);\n-\t\tif (!quiet)\n+\t\tif (!info->quiet)\n \t\t\tfprintf(stderr,\n \t\t\t\t_(\"Submodule '%s' (%s) registered for path '%s'\\n\"),\n \t\t\t\tsub->name, url, displaypath);\n@@ -445,10 +461,10 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \n static int module_init(int argc, const char **argv, const char *prefix)\n {\n+\tstruct init_cb info = INIT_CB_INIT;\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n-\tint i;\n \n \tstruct option module_init_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"Suppress output for initializing a submodule\")),\n@@ -473,8 +489,11 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \tif (!argc && git_config_get_value_multi(\"submodule.active\"))\n \t\tmodule_list_active(&list);\n \n-\tfor (i = 0; i < list.nr; i++)\n-\t\tinit_submodule(list.entries[i]->name, prefix, quiet);\n+\tinfo.prefix = prefix;\n+\tinfo.quiet = !!quiet;\n+\n+\tgitmodules_config();\n+\tfor_each_submodule_list(list, init_submodule, &info);\n \n \treturn 0;\n }\n-- \n2.13.0\n\n"},{"id":"324124","messageId":"20170710225407.29344-1-pc44800@gmail.com","threadId":"46351","inReplyTo":"CAME+mvU_8-S4AhTtMYm1L6PK81v23wu4EuB+EnOgkDhi=jo9Rg@mail.gmail.com","subject":"[GSoC][PATCH 1/8] submodule--helper: introduce get_submodule_displaypath()","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-10T22:54:00Z","receivedAt":"2017-07-10T22:54:31Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"Introduce function get_submodule_displaypath() to replace the code\noccurring in submodule_init() for generating displaypath of the\nsubmodule with a call to it.\n\nThis new function will also be used in other parts of the system\nin later patches.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 33 ++++++++++++++++++++++-----------\n 1 file changed, 22 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 6abdad329..7af4de09b 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -220,6 +220,27 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr\n \treturn 0;\n }\n \n+static char *get_submodule_displaypath(const char *path, const char *prefix)\n+{\n+\tconst char *super_prefix = get_super_prefix();\n+\n+\tif (prefix && super_prefix) {\n+\t\tBUG(\"cannot have prefix '%s' and superprefix '%s'\",\n+\t\t    prefix, super_prefix);\n+\t} else if (prefix) {\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\t\tchar *displaypath = xstrdup(relative_path(path, prefix, &sb));\n+\t\tstrbuf_release(&sb);\n+\t\treturn displaypath;\n+\t} else if (super_prefix) {\n+\t\tint len = strlen(super_prefix);\n+\t\tconst char *format = is_dir_sep(super_prefix[len - 1]) ? \"%s%s\" : \"%s/%s\";\n+\t\treturn xstrfmt(format, super_prefix, path);\n+\t} else {\n+\t\treturn xstrdup(path);\n+\t}\n+}\n+\n struct module_list {\n \tconst struct cache_entry **entries;\n \tint alloc, nr;\n@@ -339,16 +360,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \n \t/* Only loads from .gitmodules, no overlay with .git/config */\n \tgitmodules_config();\n-\n-\tif (prefix && get_super_prefix())\n-\t\tdie(\"BUG: cannot have prefix and superprefix\");\n-\telse if (prefix)\n-\t\tdisplaypath = xstrdup(relative_path(path, prefix, &sb));\n-\telse if (get_super_prefix()) {\n-\t\tstrbuf_addf(&sb, \"%s%s\", get_super_prefix(), path);\n-\t\tdisplaypath = strbuf_detach(&sb, NULL);\n-\t} else\n-\t\tdisplaypath = xstrdup(path);\n+\tdisplaypath = get_submodule_displaypath(path, prefix);\n \n \tsub = submodule_from_path(null_sha1, path);\n \n@@ -363,7 +375,6 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t * Set active flag for the submodule being initialized\n \t */\n \tif (!is_submodule_active(the_repository, path)) {\n-\t\tstrbuf_reset(&sb);\n \t\tstrbuf_addf(&sb, \"submodule.%s.active\", sub->name);\n \t\tgit_config_set_gently(sb.buf, \"true\");\n \t}\n-- \n2.13.0\n\n"},{"id":"324125","messageId":"20170710225407.29344-4-pc44800@gmail.com","threadId":"46351","inReplyTo":"20170710225407.29344-1-pc44800@gmail.com","subject":"[GSoC][PATCH 4/8] submodule: port submodule subcommand 'status' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-10T22:54:03Z","receivedAt":"2017-07-10T22:54:35Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"This aims to make git-submodule 'status' a built-in. Hence, the function\ncmd_status() is ported from shell to C. This is done by introducing\nthree functions: module_status(), submodule_status() and print_status().\n\nThe function module_status() acts as the front-end of the subcommand.\nIt parses subcommand's options and then calls the function\nmodule_list_compute() for computing the list of submodules. Then\nthis functions calls for_each_submodule_list() looping through the\nlist obtained.\n\nThen for_each_submodule_list() calls submodule_status() for each of the\nsubmodule in its list. The function submodule_status() is responsible\nfor generating the status each submodule it is called for, and\nthen calls print_status().\n\nFinally, the function print_status() handles the printing of submodule's\nstatus.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 154 ++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            |  49 +-------------\n 2 files changed, 155 insertions(+), 48 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 80f744407..980b8ed27 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -560,6 +560,159 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+struct status_cb {\n+\tconst char *prefix;\n+\tunsigned int quiet: 1;\n+\tunsigned int recursive: 1;\n+\tunsigned int cached: 1;\n+};\n+#define STATUS_CB_INIT { NULL, 0, 0, 0 }\n+\n+static void print_status(struct status_cb *info, char state, const char *path,\n+\t\t\t char *sub_sha1, char *displaypath)\n+{\n+\tif (info->quiet)\n+\t\treturn;\n+\n+\tprintf(\"%c%s %s\", state, sub_sha1, displaypath);\n+\n+\tif (state == ' ' || state == '+') {\n+\t\tstruct argv_array name_rev_args = ARGV_ARRAY_INIT;\n+\n+\t\targv_array_pushl(&name_rev_args, \"print-name-rev\",\n+\t\t\t\t path, sub_sha1, NULL);\n+\t\tprint_name_rev(name_rev_args.argc, name_rev_args.argv,\n+\t\t\t       info->prefix);\n+\t} else {\n+\t\tprintf(\"\\n\");\n+\t}\n+}\n+\n+static void status_submodule(const struct cache_entry *list_item, void *cb_data)\n+{\n+\tstruct status_cb *info = cb_data;\n+\tchar *sub_sha1 = xstrdup(oid_to_hex(&list_item->oid));\n+\tchar *displaypath;\n+\tstruct argv_array diff_files_args = ARGV_ARRAY_INIT;\n+\n+\tif (!submodule_from_path(null_sha1, list_item->name))\n+\t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n+\t\t      list_item->name);\n+\n+\tdisplaypath = get_submodule_displaypath(list_item->name, info->prefix);\n+\n+\tif (list_item->ce_flags) {\n+\t\tprint_status(info, 'U', list_item->name,\n+\t\t\t     sha1_to_hex(null_sha1), displaypath);\n+\t\tgoto cleanup;\n+\t}\n+\n+\tif (!is_submodule_active(the_repository, list_item->name)) {\n+\t\tprint_status(info, '-', list_item->name, sub_sha1, displaypath);\n+\t\tgoto cleanup;\n+\t}\n+\n+\targv_array_pushl(&diff_files_args, \"diff-files\",\n+\t\t\t \"--ignore-submodules=dirty\", \"--quiet\", \"--\",\n+\t\t\t list_item->name, NULL);\n+\n+\t/* NEEDSWORK: future optimization possible */\n+\tif (!cmd_diff_files(diff_files_args.argc, diff_files_args.argv,\n+\t\t\t    info->prefix)) {\n+\t\tprint_status(info, ' ', list_item->name, sub_sha1, displaypath);\n+\t} else {\n+\t\tif (!info->cached) {\n+\t\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\t\tprepare_submodule_repo_env(&cp.env_array);\n+\t\t\tcp.git_cmd = 1;\n+\t\t\tcp.dir = list_item->name;\n+\n+\t\t\targv_array_pushl(&cp.args, \"rev-parse\",\n+\t\t\t\t\t \"--verify\", \"HEAD\", NULL);\n+\n+\t\t\t/* NEEDSWORK: future optimization possible */\n+\t\t\tif (capture_command(&cp, &sb, 0))\n+\t\t\t\tdie(_(\"could not run 'git rev-parse --verify\"\n+\t\t\t\t      \"HEAD' in submodule %s\"),\n+\t\t\t\t      list_item->name);\n+\n+\t\t\tstrbuf_strip_suffix(&sb, \"\\n\");\n+\t\t\tprint_status(info, '+', list_item->name, sb.buf,\n+\t\t\t\t     displaypath);\n+\t\t\tstrbuf_release(&sb);\n+\t\t} else {\n+\t\t\tprint_status(info, '+', list_item->name, sub_sha1,\n+\t\t\t\t     displaypath);\n+\t\t}\n+\t}\n+\n+\tif (info->recursive) {\n+\t\tstruct child_process cpr = CHILD_PROCESS_INIT;\n+\n+\t\tcpr.git_cmd = 1;\n+\t\tcpr.dir = list_item->name;\n+\t\tprepare_submodule_repo_env(&cpr.env_array);\n+\n+\t\targv_array_pushl(&cpr.args, \"--super-prefix\", displaypath,\n+\t\t\t\t \"submodule--helper\", \"status\", \"--recursive\",\n+\t\t\t\t NULL);\n+\n+\t\tif (info->cached)\n+\t\t\targv_array_push(&cpr.args, \"--cached\");\n+\n+\t\tif (info->quiet)\n+\t\t\targv_array_push(&cpr.args, \"--quiet\");\n+\n+\t\tif (run_command(&cpr))\n+\t\t\tdie(_(\"failed to recurse into submodule '%s'\"),\n+\t\t\t      list_item->name);\n+\t}\n+\n+cleanup:\n+\tfree(displaypath);\n+\tfree(sub_sha1);\n+}\n+\n+static int module_status(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct status_cb info = STATUS_CB_INIT;\n+\tstruct pathspec pathspec;\n+\tstruct module_list list = MODULE_LIST_INIT;\n+\tint quiet = 0;\n+\tint cached = 0;\n+\tint recursive = 0;\n+\n+\tstruct option module_status_options[] = {\n+\t\tOPT__QUIET(&quiet, N_(\"Suppress submodule status output\")),\n+\t\tOPT_BOOL(0, \"cached\", &cached, N_(\"Use commit stored in the index instead of the one stored in the submodule HEAD\")),\n+\t\tOPT_BOOL(0, \"recursive\", &recursive, N_(\"Recurse into nested submodules\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule status [--quiet] [--cached] [--recursive] [<path>]\"),\n+\t\tNULL\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, module_status_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n+\t\treturn 1;\n+\n+\tinfo.prefix = prefix;\n+\tinfo.quiet = !!quiet;\n+\tinfo.recursive = !!recursive;\n+\tinfo.cached = !!cached;\n+\n+\tgitmodules_config();\n+\tfor_each_submodule_list(list, status_submodule, &info);\n+\n+\treturn 0;\n+}\n+\n static int module_name(int argc, const char **argv, const char *prefix)\n {\n \tconst struct submodule *sub;\n@@ -1306,6 +1459,7 @@ static struct cmd_struct commands[] = {\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"print-name-rev\", print_name_rev, 0},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n+\t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex e988167e0..51b057d82 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -1005,54 +1005,7 @@ cmd_status()\n \t\tshift\n \tdone\n \n-\t{\n-\t\tgit submodule--helper list --prefix \"$wt_prefix\" \"$@\" ||\n-\t\techo \"#unmatched\" $?\n-\t} |\n-\twhile read -r mode sha1 stage sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$mode\" \"$sha1\"\n-\t\tname=$(git submodule--helper name \"$sm_path\") || exit\n-\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n-\t\tif test \"$stage\" = U\n-\t\tthen\n-\t\t\tsay \"U$sha1 $displaypath\"\n-\t\t\tcontinue\n-\t\tfi\n-\t\tif ! git submodule--helper is-active \"$sm_path\" ||\n-\t\t{\n-\t\t\t! test -d \"$sm_path\"/.git &&\n-\t\t\t! test -f \"$sm_path\"/.git\n-\t\t}\n-\t\tthen\n-\t\t\tsay \"-$sha1 $displaypath\"\n-\t\t\tcontinue;\n-\t\tfi\n-\t\tif git diff-files --ignore-submodules=dirty --quiet -- \"$sm_path\"\n-\t\tthen\n-\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n-\t\t\tsay \" $sha1 $displaypath$revname\"\n-\t\telse\n-\t\t\tif test -z \"$cached\"\n-\t\t\tthen\n-\t\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" && git rev-parse --verify HEAD)\n-\t\t\tfi\n-\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n-\t\t\tsay \"+$sha1 $displaypath$revname\"\n-\t\tfi\n-\n-\t\tif test -n \"$recursive\"\n-\t\tthen\n-\t\t\t(\n-\t\t\t\tprefix=\"$displaypath/\"\n-\t\t\t\tsanitize_submodule_env\n-\t\t\t\twt_prefix=\n-\t\t\t\tcd \"$sm_path\" &&\n-\t\t\t\teval cmd_status\n-\t\t\t) ||\n-\t\t\tdie \"$(eval_gettext \"Failed to recurse into submodule path '\\$sm_path'\")\"\n-\t\tfi\n-\tdone\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper status ${GIT_QUIET:+--quiet} ${cached:+--cached} ${recursive:+--recursive} \"$@\"\n }\n #\n # Sync remote urls for submodules\n-- \n2.13.0\n\n"},{"id":"324126","messageId":"20170710225407.29344-7-pc44800@gmail.com","threadId":"46351","inReplyTo":"20170710225407.29344-1-pc44800@gmail.com","subject":"[GSoC][PATCH 7/8] diff: change scope of the function count_lines()","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-10T22:54:06Z","receivedAt":"2017-07-10T22:54:42Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"Change the scope of function count_lines for allowing the function\nto be reused in other parts of the code as well.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n diff.c | 2 +-\n diff.h | 1 +\n 2 files changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/diff.c b/diff.c\nindex 00b4c8669..3240f8283 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -425,7 +425,7 @@ struct emit_callback {\n \tstruct strbuf *header;\n };\n \n-static int count_lines(const char *data, int size)\n+int count_lines(const char *data, int size)\n {\n \tint count, ch, completely_empty = 1, nl_just_seen = 0;\n \tcount = 0;\ndiff --git a/diff.h b/diff.h\nindex 2d442e296..8522514e9 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -273,6 +273,7 @@ extern struct diff_filepair *diff_unmerge(struct diff_options *, const char *pat\n extern int parse_long_opt(const char *opt, const char **argv,\n \t\t\t const char **optarg);\n \n+extern int count_lines(const char *data, int size);\n extern int git_diff_basic_config(const char *var, const char *value, void *cb);\n extern int git_diff_heuristic_config(const char *var, const char *value, void *cb);\n extern void init_diff_ui_defaults(void);\n-- \n2.13.0\n\n"},{"id":"324127","messageId":"20170710225407.29344-6-pc44800@gmail.com","threadId":"46351","inReplyTo":"20170710225407.29344-1-pc44800@gmail.com","subject":"[GSoC][PATCH 6/8] submodule: port submodule subcommand 'deinit' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-10T22:54:05Z","receivedAt":"2017-07-10T22:54:45Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"The same mechanism is used even for porting this submodule\nsubcommand, as used in the ported subcommands till now.\nThe function cmd_deinit in split up after porting into three\nfunctions: module_deinit(), for_each_submodule_list() and\ndeinit_submodule().\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 143 ++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            |  55 +----------------\n 2 files changed, 144 insertions(+), 54 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4e04b93f3..05d430846 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -909,6 +909,148 @@ static int module_sync(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+struct deinit_cb {\n+\tconst char *prefix;\n+\tunsigned int quiet: 1;\n+\tunsigned int force: 1;\n+\tunsigned int all: 1;\n+};\n+#define DEINIT_CB_INIT { NULL, 0, 0, 0 }\n+\n+static void deinit_submodule(const struct cache_entry *list_item,\n+\t\t\t     void *cb_data)\n+{\n+\tstruct deinit_cb *info = cb_data;\n+\tconst struct submodule *sub;\n+\tchar *displaypath = NULL;\n+\tstruct child_process cp_config = CHILD_PROCESS_INIT;\n+\tstruct strbuf sb_config = STRBUF_INIT;\n+\tchar *sm_path = xstrdup(list_item->name);\n+\tchar *sub_git_dir = xstrfmt(\"%s/.git\", sm_path);\n+\tstruct stat st;\n+\n+\tsub = submodule_from_path(null_sha1, sm_path);\n+\n+\tif (!sub || !sub->name)\n+\t\tgoto cleanup;\n+\n+\tdisplaypath = get_submodule_displaypath(sm_path, info->prefix);\n+\n+\t/* remove the submodule work tree (unless the user already did it) */\n+\tif (is_directory(sm_path)) {\n+\t\t/* protect submodules containing a .git directory */\n+\t\tif (is_git_directory(sub_git_dir))\n+\t\t\tdie(_(\"Submodule work tree '%s' contains a .git \"\n+\t\t\t      \"directory use 'rm -rf' if you really want \"\n+\t\t\t      \"to remove it including all of its history\"),\n+\t\t\t      displaypath);\n+\n+\t\tif (!info->force) {\n+\t\t\tstruct child_process cp_rm = CHILD_PROCESS_INIT;\n+\t\t\tcp_rm.git_cmd = 1;\n+\t\t\targv_array_pushl(&cp_rm.args, \"rm\", \"-qn\", sm_path,\n+\t\t\t\t\t NULL);\n+\n+\t\t\t/* list_item->name is changed by cmd_rm() below */\n+\t\t\tif (run_command(&cp_rm))\n+\t\t\t\tdie(_(\"Submodule work tree '%s' contains local \"\n+\t\t\t\t      \"modifications; use '-f' to discard them\"),\n+\t\t\t\t      displaypath);\n+\t\t}\n+\n+\t\tif (!lstat(sm_path, &st)) {\n+\t\t\tstruct strbuf sb_rm = STRBUF_INIT;\n+\t\t\tstrbuf_addstr(&sb_rm, sm_path);\n+\n+\t\t\tif (!remove_dir_recursively(&sb_rm, 0)) {\n+\t\t\t\tif (!info->quiet)\n+\t\t\t\t\tprintf(_(\"Cleared directory '%s'\\n\"),\n+\t\t\t\t\t\t displaypath);\n+\t\t\t} else {\n+\t\t\t\tif (!info->quiet)\n+\t\t\t\t\tprintf(_(\"Could not remove submodule work tree '%s'\\n\"),\n+\t\t\t\t\t\t displaypath);\n+\t\t\t}\n+\t\t\tstrbuf_release(&sb_rm);\n+\t\t}\n+\t}\n+\n+\tif (mkdir(sm_path, st.st_mode))\n+\t\tdie(_(\"could not create empty submodule directory %s\"),\n+\t\t      displaypath);\n+\n+\tcp_config.git_cmd = 1;\n+\targv_array_pushl(&cp_config.args, \"config\", \"--get-regexp\", NULL);\n+\targv_array_pushf(&cp_config.args, \"submodule.%s\\\\.\", sub->name);\n+\n+\t/* remove the .git/config entries (unless the user already did it) */\n+\tif (!capture_command(&cp_config, &sb_config, 0) && sb_config.len) {\n+\t\tchar *sub_key = xstrfmt(\"submodule.%s\", sub->name);\n+\t\t/*\n+\t\t * remove the whole section so we have a clean state when\n+\t\t * the user later decides to init this submodule again\n+\t\t */\n+\t\tgit_config_rename_section_in_file(NULL, sub_key, NULL);\n+\t\tif (!info->quiet)\n+\t\t\tprintf(_(\"Submodule '%s' (%s) unregistered for path '%s'\\n\"),\n+\t\t\t\t sub->name, sub->url, displaypath);\n+\t\tfree(sub_key);\n+\t}\n+\n+cleanup:\n+\tfree(displaypath);\n+\tfree(sub_git_dir);\n+\tfree(sm_path);\n+\tstrbuf_release(&sb_config);\n+}\n+\n+static int module_deinit(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct deinit_cb info = DEINIT_CB_INIT;\n+\tstruct pathspec pathspec;\n+\tstruct module_list list = MODULE_LIST_INIT;\n+\tint quiet = 0;\n+\tint force = 0;\n+\tint all = 0;\n+\n+\tstruct option module_deinit_options[] = {\n+\t\tOPT__QUIET(&quiet, N_(\"Suppress submodule status output\")),\n+\t\tOPT__FORCE(&force, N_(\"Remove submodule working trees even if they contain local changes\")),\n+\t\tOPT_BOOL(0, \"all\", &all, N_(\"Unregister all submodules\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule deinit [--quiet] [-f | --force] [--all | [--] [<path>...]]\"),\n+\t\tNULL\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, module_deinit_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n+\t\tBUG(\"module_list_compute should not choke on empty pathspec\");\n+\n+\tinfo.prefix = prefix;\n+\tinfo.quiet = !!quiet;\n+\tinfo.all = !!all;\n+\tinfo.force = !!force;\n+\n+\tif (all && argc) {\n+\t\terror(\"pathspec and --all are incompatible\");\n+\t\tusage_with_options(git_submodule_helper_usage,\n+\t\t\t\t   module_deinit_options);\n+\t}\n+\n+\tif (!argc && !all)\n+\t\tdie(_(\"Use '--all' if you really want to deinitialize all submodules\"));\n+\n+\tgitmodules_config();\n+\tfor_each_submodule_list(list, deinit_submodule, &info);\n+\n+\treturn 0;\n+}\n+\n static int clone_submodule(const char *path, const char *gitdir, const char *url,\n \t\t\t   const char *depth, struct string_list *reference,\n \t\t\t   int quiet, int progress)\n@@ -1639,6 +1781,7 @@ static struct cmd_struct commands[] = {\n \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n \t{\"print-default-remote\", print_default_remote, 0},\n \t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n+\t{\"deinit\", module_deinit, SUPPORT_SUPER_PREFIX},\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 6bfc5e17d..73e6f093f 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -428,60 +428,7 @@ cmd_deinit()\n \t\tshift\n \tdone\n \n-\tif test -n \"$deinit_all\" && test \"$#\" -ne 0\n-\tthen\n-\t\techo >&2 \"$(eval_gettext \"pathspec and --all are incompatible\")\"\n-\t\tusage\n-\tfi\n-\tif test $# = 0 && test -z \"$deinit_all\"\n-\tthen\n-\t\tdie \"$(eval_gettext \"Use '--all' if you really want to deinitialize all submodules\")\"\n-\tfi\n-\n-\t{\n-\t\tgit submodule--helper list --prefix \"$wt_prefix\" \"$@\" ||\n-\t\techo \"#unmatched\" $?\n-\t} |\n-\twhile read -r mode sha1 stage sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$mode\" \"$sha1\"\n-\t\tname=$(git submodule--helper name \"$sm_path\") || exit\n-\n-\t\tdisplaypath=$(git submodule--helper relative-path \"$sm_path\" \"$wt_prefix\")\n-\n-\t\t# Remove the submodule work tree (unless the user already did it)\n-\t\tif test -d \"$sm_path\"\n-\t\tthen\n-\t\t\t# Protect submodules containing a .git directory\n-\t\t\tif test -d \"$sm_path/.git\"\n-\t\t\tthen\n-\t\t\t\tdie \"$(eval_gettext \"\\\n-Submodule work tree '\\$displaypath' contains a .git directory\n-(use 'rm -rf' if you really want to remove it including all of its history)\")\"\n-\t\t\tfi\n-\n-\t\t\tif test -z \"$force\"\n-\t\t\tthen\n-\t\t\t\tgit rm -qn \"$sm_path\" ||\n-\t\t\t\tdie \"$(eval_gettext \"Submodule work tree '\\$displaypath' contains local modifications; use '-f' to discard them\")\"\n-\t\t\tfi\n-\t\t\trm -rf \"$sm_path\" &&\n-\t\t\tsay \"$(eval_gettext \"Cleared directory '\\$displaypath'\")\" ||\n-\t\t\tsay \"$(eval_gettext \"Could not remove submodule work tree '\\$displaypath'\")\"\n-\t\tfi\n-\n-\t\tmkdir \"$sm_path\" || say \"$(eval_gettext \"Could not create empty submodule directory '\\$displaypath'\")\"\n-\n-\t\t# Remove the .git/config entries (unless the user already did it)\n-\t\tif test -n \"$(git config --get-regexp submodule.\"$name\\.\")\"\n-\t\tthen\n-\t\t\t# Remove the whole section so we have a clean state when\n-\t\t\t# the user later decides to init this submodule again\n-\t\t\turl=$(git config submodule.\"$name\".url)\n-\t\t\tgit config --remove-section submodule.\"$name\" 2>/dev/null &&\n-\t\t\tsay \"$(eval_gettext \"Submodule '\\$name' (\\$url) unregistered for path '\\$displaypath'\")\"\n-\t\tfi\n-\tdone\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${prefix:+--prefix \"$prefix\"} ${force:+--force} ${deinit_all:+--all} \"$@\"\n }\n \n is_tip_reachable () (\n-- \n2.13.0\n\n"},{"id":"324128","messageId":"20170710225407.29344-8-pc44800@gmail.com","threadId":"46351","inReplyTo":"20170710225407.29344-1-pc44800@gmail.com","subject":"[GSoC][PATCH 8/8] submodule: port submodule subcommand 'summary' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-10T22:54:07Z","receivedAt":"2017-07-10T22:54:47Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"The submodule subcommand 'summary' is ported in the process of\nmaking git-submodule a builtin. The function cmd_summary() from\ngit-submodule.sh is ported to functions module_summary(),\ncompute_summary_module_list(), prepare_submodule_summary() and\nprint_submodule_summary().\n\nThe first function module_summary() parses the options of submodule\nsubcommand and also acts as the front-end of this subcommand.\nAfter parsing them, it calls the compute_summary_module_list()\n\nThe functions compute_summary_module_list() runs the diff_cmd,\nand generates the modules list, as required by the subcommand.\nThe generation of this module list is done by the using the\ncallback function submodule_summary_callback(), and stored in the\nstructure module_cb.\n\nOnce the module list is generated, prepare_submodule_summary()\nfurther goes through the list and filters the list, for\neventually calling the print_submodule_summary() function.\n\nFinally, the print_submodule_summary() takes care of generating\nand printing the summary for each submodule.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\nThis is the first version of submodule-summary posted on the mailing list.\n\nThis patch has previously being reviewed off the mailing list as well, and\nfollowing are the changes made after the previous update:\n\nAn initial check for is_sm_git_dir is added.\n\nInstead of changing the dir to sm_path in a child_process, now we instead\nare adding the env_variable GIT_DIR. This helped in avoiding the usage of\nshell in the child_process as well for getting all the tests cleared\nfrom t7508-status.\n\nAlso, the sentences which earlier were translated unnecessarily were\nchanged for getting all the test cleared with the env_variable\nGETTEXT_POISON, out of which 13 test from t7401-submodule-summary\nfailed earlier.\n\nStill I'm looking into a better way for generating the abbrevation of\nsha1_src and sha1_dst.\n\nComplete build report of this series is available at:\nhttps://travis-ci.org/pratham-pc/git/builds/\nBranch: week-8\nBuild #129\n\n builtin/submodule--helper.c | 466 ++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            | 182 +----------------\n 2 files changed, 467 insertions(+), 181 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 05d430846..1dc53c2b2 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -13,6 +13,9 @@\n #include \"remote.h\"\n #include \"refs.h\"\n #include \"connect.h\"\n+#include \"revision.h\"\n+#include \"diffcore.h\"\n+#include \"diff.h\"\n \n typedef void (*submodule_list_func_t)(const struct cache_entry *list_item,\n \t\t\t\t      void *cb_data);\n@@ -767,6 +770,468 @@ static int module_name(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+struct module_cb {\n+\tunsigned int mod_src;\n+\tunsigned int mod_dst;\n+\tstruct object_id oid_src;\n+\tstruct object_id oid_dst;\n+\tchar status;\n+\tconst char *sm_path;\n+};\n+#define MODULE_CB_INIT { 0, 0, NULL, NULL, '\\0', NULL }\n+\n+struct module_cb_list {\n+\tstruct module_cb **entries;\n+\tint alloc, nr;\n+};\n+#define MODULE_CB_LIST_INIT { NULL, 0, 0 }\n+\n+struct summary_cb {\n+\tint argc;\n+\tconst char **argv;\n+\tconst char *prefix;\n+\tchar *diff_cmd;\n+\tunsigned int cached: 1;\n+\tunsigned int for_status: 1;\n+\tunsigned int quiet: 1;\n+\tunsigned int files: 1;\n+\tint summary_limits;\n+};\n+#define SUMMARY_CB_INIT { 0, NULL, NULL, NULL, 0, 0, 0, 0, 0 }\n+\n+static void print_submodule_summary(struct summary_cb *info,\n+\t\t\t\t    struct module_cb *p)\n+{\n+\tint missing_src = 0;\n+\tint missing_dst = 0;\n+\tchar *displaypath;\n+\tchar *sha1_abbr_src;\n+\tchar *sha1_abbr_dst;\n+\tint errmsg = 0;\n+\tint total_commits = -1;\n+\tstruct strbuf sb_sha1_src = STRBUF_INIT;\n+\tstruct strbuf sb_sha1_dst = STRBUF_INIT;\n+\tchar *sha1_dst = oid_to_hex(&p->oid_dst);\n+\tchar *sha1_src = oid_to_hex(&p->oid_src);\n+\tchar *sm_git_dir = xstrfmt(\"%s/.git\", p->sm_path);\n+\tint is_sm_git_dir = 0;\n+\n+\tif (!info->cached && !strcmp(sha1_dst, sha1_to_hex(null_sha1))) {\n+\t\tif (S_ISGITLINK(p->mod_dst)) {\n+\t\t\tstruct child_process cp_rev_parse = CHILD_PROCESS_INIT;\n+\t\t\tstruct strbuf sb_rev_parse = STRBUF_INIT;\n+\n+\t\t\tcp_rev_parse.git_cmd = 1;\n+\t\t\tcp_rev_parse.no_stderr = 1;\n+\n+\t\t\targv_array_pushf(&cp_rev_parse.env_array,\n+\t\t\t\t\t \"GIT_DIR=%s/.git\", p->sm_path);\n+\t\t\targv_array_pushl(&cp_rev_parse.args,\n+\t\t\t\t\t \"rev-parse\", \"HEAD\", NULL);\n+\t\t\tif (!capture_command(&cp_rev_parse, &sb_rev_parse, 0)) {\n+\t\t\t\tstrbuf_strip_suffix(&sb_rev_parse, \"\\n\");\n+\t\t\t\tsha1_dst = xstrdup(sb_rev_parse.buf);\n+\t\t\t}\n+\t\t\tstrbuf_release(&sb_rev_parse);\n+\t\t} else if (S_ISLNK(p->mod_dst) || S_ISREG(p->mod_dst)) {\n+\t\t\tstruct child_process cp_hash_object = CHILD_PROCESS_INIT;\n+\t\t\tstruct strbuf sb_hash_object = STRBUF_INIT;\n+\n+\t\t\tcp_hash_object.git_cmd = 1;\n+\t\t\targv_array_pushl(&cp_hash_object.args,\n+\t\t\t\t\t \"hash-object\", p->sm_path,\n+\t\t\t\t\t NULL);\n+\t\t\tif (!capture_command(&cp_hash_object,\n+\t\t\t\t\t     &sb_hash_object, 0)) {\n+\t\t\t\tstrbuf_strip_suffix(&sb_hash_object, \"\\n\");\n+\t\t\t\tsha1_dst = xstrdup(sb_hash_object.buf);\n+\t\t\t}\n+\t\t\tstrbuf_release(&sb_hash_object);\n+\t\t} else {\n+\t\t\tif (p->mod_dst != 0)\n+\t\t\t\tdie(_(\"unexpected mode %d\\n\"), p->mod_dst);\n+\t\t}\n+\t}\n+\n+\tif (is_git_directory(sm_git_dir))\n+\t\tis_sm_git_dir = 1;\n+\n+\tif (is_sm_git_dir && S_ISGITLINK(p->mod_src)) {\n+\t\tstruct child_process cp_rev_parse = CHILD_PROCESS_INIT;\n+\n+\t\tcp_rev_parse.git_cmd = 1;\n+\t\tcp_rev_parse.no_stdout = 1;\n+\n+\t\targv_array_pushf(&cp_rev_parse.env_array, \"GIT_DIR=%s/.git\",\n+\t\t\t\t p->sm_path);\n+\t\targv_array_pushl(&cp_rev_parse.args, \"rev-parse\", \"-q\",\n+\t\t\t\t \"--verify\", NULL);\n+\t\targv_array_pushf(&cp_rev_parse.args, \"%s^0\", sha1_src);\n+\n+\t\tif (run_command(&cp_rev_parse))\n+\t\t\tmissing_src = 1;\n+\t}\n+\n+\tif (is_sm_git_dir && S_ISGITLINK(p->mod_dst)) {\n+\t\tstruct child_process cp_rev_parse = CHILD_PROCESS_INIT;\n+\n+\t\tcp_rev_parse.git_cmd = 1;\n+\t\tcp_rev_parse.no_stdout = 1;\n+\n+\t\targv_array_pushf(&cp_rev_parse.env_array, \"GIT_DIR=%s/.git\",\n+\t\t\t\t p->sm_path);\n+\t\targv_array_pushl(&cp_rev_parse.args, \"rev-parse\", \"-q\",\n+\t\t\t\t \"--verify\", NULL);\n+\t\targv_array_pushf(&cp_rev_parse.args, \"%s^0\", sha1_dst);\n+\n+\t\tif (run_command(&cp_rev_parse))\n+\t\t\tmissing_dst = 1;\n+\t}\n+\n+\tdisplaypath = get_submodule_displaypath(p->sm_path, info->prefix);\n+\n+\tif (!missing_dst && !missing_src) {\n+\t\tif (is_sm_git_dir) {\n+\t\t\tstruct child_process cp_rev_list = CHILD_PROCESS_INIT;\n+\t\t\tstruct strbuf sb_rev_list = STRBUF_INIT;\n+\t\t\tconst char *range;\n+\n+\t\t\tif (S_ISGITLINK(p->mod_src) && S_ISGITLINK(p->mod_dst))\n+\t\t\t\trange = xstrfmt(\"%s...%s\", sha1_src, sha1_dst);\n+\t\t\telse if (S_ISGITLINK(p->mod_src))\n+\t\t\t\trange = xstrdup(sha1_src);\n+\t\t\telse\n+\t\t\t\trange = xstrdup(sha1_dst);\n+\n+\t\t\tcp_rev_list.git_cmd = 1;\n+\t\t\targv_array_pushf(&cp_rev_list.env_array,\n+\t\t\t\t\t \"GIT_DIR=%s/.git\", p->sm_path);\n+\t\t\targv_array_pushl(&cp_rev_list.args, \"rev-list\",\n+\t\t\t\t\t \"--first-parent\", range, \"--\", NULL);\n+\t\t\tif (!capture_command(&cp_rev_list, &sb_rev_list, 0)) {\n+\t\t\t\tif (sb_rev_list.len)\n+\t\t\t\t\ttotal_commits = count_lines(sb_rev_list.buf,\n+\t\t\t\t\t\t\t\t    sb_rev_list.len);\n+\t\t\t\telse\n+\t\t\t\t\ttotal_commits = 0;\n+\t\t\t}\n+\t\t\tstrbuf_release(&sb_rev_list);\n+\t\t}\n+\t} else {\n+\t\terrmsg = 1;\n+\t}\n+\n+\tstrbuf_addstr(&sb_sha1_src, sha1_src);\n+\tstrbuf_addstr(&sb_sha1_dst, sha1_dst);\n+\n+\tstrbuf_remove(&sb_sha1_src, 7, 33);\n+\tstrbuf_remove(&sb_sha1_dst, 7, 33);\n+\n+\tsha1_abbr_src = strbuf_detach(&sb_sha1_src, NULL);\n+\tsha1_abbr_dst = strbuf_detach(&sb_sha1_dst, NULL);\n+\n+\tif (p->status == 'T') {\n+\t\tif (S_ISGITLINK(p->mod_dst)) {\n+\t\t\tif (total_commits < 0)\n+\t\t\t\tprintf(_(\"* %s %s(blob)->%s(submodule):\\n\"),\n+\t\t\t\t\t displaypath, sha1_abbr_src,\n+\t\t\t\t\t sha1_abbr_dst);\n+\t\t\telse\n+\t\t\t\tprintf(_(\"* %s %s(blob)->%s(submodule) (%d):\\n\"),\n+\t\t\t\t\t displaypath, sha1_abbr_src,\n+\t\t\t\t\t sha1_abbr_dst, total_commits);\n+\t\t} else {\n+\t\t\tif (total_commits < 0)\n+\t\t\t\tprintf(_(\"* %s %s(submodule)->%s(blob):\\n\"),\n+\t\t\t\t\t displaypath, sha1_abbr_src,\n+\t\t\t\t\t sha1_abbr_dst);\n+\t\t\telse\n+\t\t\t\tprintf(_(\"* %s %s(submodule)->%s(blob) (%d):\\n\"),\n+\t\t\t\t\t displaypath, sha1_abbr_src,\n+\t\t\t\t\t sha1_abbr_dst, total_commits);\n+\t\t}\n+\t} else {\n+\t\tif (total_commits < 0)\n+\t\t\tprintf(\"* %s %s...%s:\\n\", displaypath, sha1_abbr_src,\n+\t\t\t\t sha1_abbr_dst);\n+\t\telse\n+\t\t\tprintf(\"* %s %s...%s (%d):\\n\", displaypath,\n+\t\t\t\t sha1_abbr_src, sha1_abbr_dst, total_commits);\n+\t}\n+\n+\tif (errmsg) {\n+\t\t/*\n+\t\t * Don't give error msg for modification whose dst is not\n+\t\t * submodule, i.e. deleted or changed to blob\n+\t\t */\n+\t\tif (S_ISGITLINK(p->mod_src)) {\n+\t\t\tif (missing_src && missing_dst) {\n+\t\t\t\tprintf(_(\"  Warn: %s doesn't contain commits %s and %s\\n\"),\n+\t\t\t\t displaypath, sha1_src, sha1_dst);\n+\t\t\t} else if (missing_src) {\n+\t\t\t\tprintf(_(\"  Warn: %s doesn't contain commit %s\\n\"),\n+\t\t\t\t displaypath, sha1_src);\n+\t\t\t} else {\n+\t\t\t\tprintf(_(\"  Warn: %s doesn't contain commit %s\\n\"),\n+\t\t\t\t displaypath, sha1_dst);\n+\t\t\t}\n+\t\t}\n+\n+\t} else if (is_sm_git_dir) {\n+\t\tif (S_ISGITLINK(p->mod_src) && S_ISGITLINK(p->mod_dst)) {\n+\t\t\tstruct child_process cp_log = CHILD_PROCESS_INIT;\n+\t\t\tchar *limit = NULL;\n+\n+\t\t\tif (info->summary_limits > 0)\n+\t\t\t\tlimit = xstrfmt(\"-%d\", info->summary_limits);\n+\n+\t\t\tcp_log.git_cmd = 1;\n+\n+\t\t\targv_array_pushf(&cp_log.env_array, \"GIT_DIR=%s/.git\",\n+\t\t\t\t\t p->sm_path);\n+\t\t\targv_array_pushl(&cp_log.args, \"log\", NULL);\n+\t\t\tif (limit)\n+\t\t\t\targv_array_push(&cp_log.args, limit);\n+\t\t\targv_array_pushl(&cp_log.args, \"--pretty=  %m %s\",\n+\t\t\t\t\t \"--first-parent\", NULL);\n+\t\t\targv_array_pushf(&cp_log.args, \"%s...%s\", sha1_src,\n+\t\t\t\t\t sha1_dst);\n+\n+\t\t\trun_command(&cp_log);\n+\n+\t\t} else if (S_ISGITLINK(p->mod_dst)) {\n+\t\t\tstruct child_process cp_log = CHILD_PROCESS_INIT;\n+\n+\t\t\tcp_log.git_cmd = 1;\n+\t\t\targv_array_pushf(&cp_log.env_array, \"GIT_DIR=%s/.git\",\n+\t\t\t\t\t p->sm_path);\n+\t\t\targv_array_pushl(&cp_log.args, \"log\",\n+\t\t\t\t\t \"--pretty=  > %s\", \"-1\",\n+\t\t\t\t\t sha1_dst, NULL);\n+\n+\t\t\trun_command(&cp_log);\n+\t\t} else {\n+\t\t\tstruct child_process cp_log = CHILD_PROCESS_INIT;\n+\n+\t\t\tcp_log.git_cmd = 1;\n+\t\t\targv_array_pushf(&cp_log.env_array, \"GIT_DIR=%s/.git\",\n+\t\t\t\t\t p->sm_path);\n+\t\t\targv_array_pushl(&cp_log.args, \"log\",\n+\t\t\t\t\t \"--pretty=  < %s\",\n+\t\t\t\t\t \"-1\", sha1_src, NULL);\n+\n+\t\t\trun_command(&cp_log);\n+\t\t}\n+\t}\n+\tprintf(\"\\n\");\n+}\n+\n+static void prepare_submodule_summary(struct summary_cb *info,\n+\t\t\t\t      struct module_cb_list *list)\n+{\n+\tint i;\n+\tfor (i = 0; i < list->nr; i++) {\n+\t\tstruct module_cb *p = list->entries[i];\n+\t\tstruct child_process cp_rev_parse = CHILD_PROCESS_INIT;\n+\n+\t\tif (p->status == 'D' || p->status == 'T') {\n+\t\t\tprint_submodule_summary(info, p);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (info->for_status) {\n+\t\t\tchar *config_key;\n+\t\t\tconst char *ignore_config = \"none\";\n+\t\t\tconst char *value;\n+\t\t\tconst struct submodule *sub = submodule_from_path(null_sha1, p->sm_path);\n+\n+\t\t\tif (sub) {\n+\t\t\t\tconfig_key = xstrfmt(\"submodule.%s.ignore\",\n+\t\t\t\t\t\t     sub->name);\n+\t\t\t\tif (!git_config_get_value(config_key, &value))\n+\t\t\t\t\tignore_config = value;\n+\t\t\t\telse if (sub->ignore)\n+\t\t\t\t\tignore_config = sub->ignore;\n+\n+\t\t\t\tif (p->status != 'A' && !strcmp(ignore_config,\n+\t\t\t\t\t\t\t\t\"all\"))\n+\t\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* Also show added or modified modules which are checked out */\n+\t\tcp_rev_parse.dir = p->sm_path;\n+\t\tcp_rev_parse.git_cmd = 1;\n+\t\tcp_rev_parse.no_stderr = 1;\n+\t\tcp_rev_parse.no_stdout = 1;\n+\n+\t\targv_array_pushl(&cp_rev_parse.args, \"rev-parse\",\n+\t\t\t\t \"--git-dir\", NULL);\n+\n+\t\tif (!run_command(&cp_rev_parse))\n+\t\t\tprint_submodule_summary(info, p);\n+\t}\n+}\n+\n+static void submodule_summary_callback(struct diff_queue_struct *q,\n+\t\t\t\t       struct diff_options *options,\n+\t\t\t\t       void *data)\n+{\n+\tint i;\n+\tstruct module_cb_list *list = data;\n+\tfor (i = 0; i < q->nr; i++) {\n+\t\tstruct diff_filepair *p = q->queue[i];\n+\t\tstruct module_cb *temp;\n+\n+\t\tif (!S_ISGITLINK(p->one->mode) && !S_ISGITLINK(p->two->mode))\n+\t\t\tcontinue;\n+\t\ttemp = (struct module_cb*)malloc(sizeof(struct module_cb));\n+\t\ttemp->mod_src = p->one->mode;\n+\t\ttemp->mod_dst = p->two->mode;\n+\t\ttemp->oid_src = p->one->oid;\n+\t\ttemp->oid_dst = p->two->oid;\n+\t\ttemp->status = p->status;\n+\t\ttemp->sm_path = xstrdup(p->one->path);\n+\n+\t\tALLOC_GROW(list->entries, list->nr + 1, list->alloc);\n+\t\tlist->entries[list->nr++] = temp;\n+\t}\n+}\n+\n+static int compute_summary_module_list(char *head, struct summary_cb *info)\n+{\n+\tstruct argv_array diff_args = ARGV_ARRAY_INIT;\n+\tstruct rev_info rev;\n+\tstruct module_cb_list list = MODULE_CB_LIST_INIT;\n+\n+\targv_array_push(&diff_args, info->diff_cmd);\n+\tif (info->cached)\n+\t\targv_array_push(&diff_args, \"--cached\");\n+\targv_array_pushl(&diff_args, \"--ignore-submodules=dirty\", \"--raw\",\n+\t\t\t NULL);\n+\tif (head)\n+\t\targv_array_push(&diff_args, head);\n+\targv_array_push(&diff_args, \"--\");\n+\tif (info->argc)\n+\t\targv_array_pushv(&diff_args, info->argv);\n+\n+\tgit_config(git_diff_basic_config, NULL);\n+\tinit_revisions(&rev, info->prefix);\n+\tgitmodules_config();\n+\trev.abbrev = 0;\n+\tprecompose_argv(diff_args.argc, diff_args.argv);\n+\n+\tdiff_args.argc = setup_revisions(diff_args.argc, diff_args.argv,\n+\t\t\t\t\t &rev, NULL);\n+\trev.diffopt.output_format = DIFF_FORMAT_NO_OUTPUT | DIFF_FORMAT_CALLBACK;\n+\trev.diffopt.format_callback = submodule_summary_callback;\n+\trev.diffopt.format_callback_data = &list;\n+\n+\tif (!info->cached) {\n+\t\tif (!strcmp(info->diff_cmd, \"diff-index\"))\n+\t\t\tsetup_work_tree();\n+\t\tif (read_cache_preload(&rev.diffopt.pathspec) < 0) {\n+\t\t\tperror(\"read_cache_preload\");\n+\t\t\treturn -1;\n+\t\t}\n+\t} else if (read_cache() < 0) {\n+\t\tperror(\"read_cache\");\n+\t\treturn -1;\n+\t}\n+\n+\tif (!strcmp(info->diff_cmd, \"diff-index\"))\n+\t\trun_diff_index(&rev, info->cached);\n+\telse\n+\t\trun_diff_files(&rev, 0);\n+\tprepare_submodule_summary(info, &list);\n+\treturn 0;\n+\n+}\n+\n+static int module_summary(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct summary_cb info = SUMMARY_CB_INIT;\n+\tint cached = 0;\n+\tchar *diff_cmd = \"diff-index\";\n+\tint for_status = 0;\n+\tint quiet = 0;\n+\tint files = 0;\n+\tint summary_limits = -1;\n+\tchar *head = NULL;\n+\tstruct child_process cp_rev = CHILD_PROCESS_INIT;\n+\tstruct strbuf sb_rev = STRBUF_INIT;\n+\n+\tstruct option module_summary_options[] = {\n+\t\tOPT__QUIET(&quiet, N_(\"Suppress output for initializing a submodule\")),\n+\t\tOPT_BOOL(0, \"cached\", &cached, N_(\"Use the commit stored in the index instead of the submodule HEAD\")),\n+\t\tOPT_BOOL(0, \"files\", &files, N_(\"To compares the commit in the index with that in the submodule HEAD\")),\n+\t\tOPT_BOOL(0, \"for-status\", &for_status, N_(\"Skip submodules with 'all' ignore_config value\")),\n+\t\tOPT_INTEGER('n', \"summary-limits\", &summary_limits, N_(\"Limit the summary size\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule--helper summary [<options>] [--] [<path>]\"),\n+\t\tNULL\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, module_summary_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\n+\tif (!summary_limits)\n+\t\treturn 0;\n+\n+\tcp_rev.git_cmd = 1;\n+\targv_array_pushl(&cp_rev.args, \"rev-parse\", \"-q\", \"--verify\",\n+\t\t\t NULL);\n+\tif (argc)\n+\t\targv_array_push(&cp_rev.args, argv[0]);\n+\telse\n+\t\targv_array_pushl(&cp_rev.args, \"HEAD\", NULL);\n+\n+\tif (!capture_command(&cp_rev, &sb_rev, 0)) {\n+\t\tstrbuf_strip_suffix(&sb_rev, \"\\n\");\n+\t\thead = xstrdup(sb_rev.buf);\n+\t\tif (argc) {\n+\t\t\targv++;\n+\t\t\targc--;\n+\t\t}\n+\t\tstrbuf_release(&sb_rev);\n+\t} else if (!argc || !strcmp(argv[0], \"HEAD\")) {\n+\t\t/* before the first commit: compare with an empty tree */\n+\t\tstruct stat st;\n+\t\tunsigned char sha1[20];\n+\t\tif (fstat(0, &st) < 0 || index_fd(sha1, 0, &st, 2, prefix, 3))\n+\t\t\tdie(\"Unable to add %s to database\", sha1);\n+\t\thead = sha1_to_hex(sha1);\n+\t\tif (argc) {\n+\t\t\targv++;\n+\t\t\targc--;\n+\t\t}\n+\t} else {\n+\t\thead = \"HEAD\";\n+\t}\n+\n+\tif (files) {\n+\t\tif (cached)\n+\t\t\tdie(_(\"The --cached option cannot be used with the --files option\"));\n+\t\tdiff_cmd = \"diff-files\";\n+\t\thead = NULL;\n+\t}\n+\n+\tinfo.argc = argc;\n+\tinfo.argv = argv;\n+\tinfo.prefix = prefix;\n+\tinfo.cached = cached;\n+\tinfo.for_status = for_status;\n+\tinfo.quiet = quiet;\n+\tinfo.files = files;\n+\tinfo.summary_limits = summary_limits;\n+\tinfo.diff_cmd = diff_cmd;\n+\n+\treturn compute_summary_module_list(head, &info);\n+}\n+\n struct sync_cb {\n \tconst char *prefix;\n \tunsigned int quiet: 1;\n@@ -1782,6 +2247,7 @@ static struct cmd_struct commands[] = {\n \t{\"print-default-remote\", print_default_remote, 0},\n \t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n \t{\"deinit\", module_deinit, SUPPORT_SUPER_PREFIX},\n+\t{\"summary\", module_summary, SUPPORT_SUPER_PREFIX},\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 73e6f093f..a427ddafd 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -51,31 +51,6 @@ die_if_unmatched ()\n \tfi\n }\n \n-#\n-# Print a submodule configuration setting\n-#\n-# $1 = submodule name\n-# $2 = option name\n-# $3 = default value\n-#\n-# Checks in the usual git-config places first (for overrides),\n-# otherwise it falls back on .gitmodules.  This allows you to\n-# distribute project-wide defaults in .gitmodules, while still\n-# customizing individual repositories if necessary.  If the option is\n-# not in .gitmodules either, print a default value.\n-#\n-get_submodule_config () {\n-\tname=\"$1\"\n-\toption=\"$2\"\n-\tdefault=\"$3\"\n-\tvalue=$(git config submodule.\"$name\".\"$option\")\n-\tif test -z \"$value\"\n-\tthen\n-\t\tvalue=$(git config -f .gitmodules submodule.\"$name\".\"$option\")\n-\tfi\n-\tprintf '%s' \"${value:-$default}\"\n-}\n-\n isnumber()\n {\n \tn=$(($1 + 0)) 2>/dev/null && test \"$n\" = \"$1\"\n@@ -755,163 +730,8 @@ cmd_summary() {\n \t\tshift\n \tdone\n \n-\ttest $summary_limit = 0 && return\n-\n-\tif rev=$(git rev-parse -q --verify --default HEAD ${1+\"$1\"})\n-\tthen\n-\t\thead=$rev\n-\t\ttest $# = 0 || shift\n-\telif test -z \"$1\" || test \"$1\" = \"HEAD\"\n-\tthen\n-\t\t# before the first commit: compare with an empty tree\n-\t\thead=$(git hash-object -w -t tree --stdin </dev/null)\n-\t\ttest -z \"$1\" || shift\n-\telse\n-\t\thead=\"HEAD\"\n-\tfi\n-\n-\tif [ -n \"$files\" ]\n-\tthen\n-\t\ttest -n \"$cached\" &&\n-\t\tdie \"$(gettext \"The --cached option cannot be used with the --files option\")\"\n-\t\tdiff_cmd=diff-files\n-\t\thead=\n-\tfi\n-\n-\tcd_to_toplevel\n-\teval \"set $(git rev-parse --sq --prefix \"$wt_prefix\" -- \"$@\")\"\n-\t# Get modified modules cared by user\n-\tmodules=$(git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- \"$@\" |\n-\t\tsane_egrep '^:([0-7]* )?160000' |\n-\t\twhile read -r mod_src mod_dst sha1_src sha1_dst status sm_path\n-\t\tdo\n-\t\t\t# Always show modules deleted or type-changed (blob<->module)\n-\t\t\tif test \"$status\" = D || test \"$status\" = T\n-\t\t\tthen\n-\t\t\t\tprintf '%s\\n' \"$sm_path\"\n-\t\t\t\tcontinue\n-\t\t\tfi\n-\t\t\t# Respect the ignore setting for --for-status.\n-\t\t\tif test -n \"$for_status\"\n-\t\t\tthen\n-\t\t\t\tname=$(git submodule--helper name \"$sm_path\")\n-\t\t\t\tignore_config=$(get_submodule_config \"$name\" ignore none)\n-\t\t\t\ttest $status != A && test $ignore_config = all && continue\n-\t\t\tfi\n-\t\t\t# Also show added or modified modules which are checked out\n-\t\t\tGIT_DIR=\"$sm_path/.git\" git-rev-parse --git-dir >/dev/null 2>&1 &&\n-\t\t\tprintf '%s\\n' \"$sm_path\"\n-\t\tdone\n-\t)\n-\n-\ttest -z \"$modules\" && return\n-\n-\tgit $diff_cmd $cached --ignore-submodules=dirty --raw $head -- $modules |\n-\tsane_egrep '^:([0-7]* )?160000' |\n-\tcut -c2- |\n-\twhile read -r mod_src mod_dst sha1_src sha1_dst status name\n-\tdo\n-\t\tif test -z \"$cached\" &&\n-\t\t\ttest $sha1_dst = 0000000000000000000000000000000000000000\n-\t\tthen\n-\t\t\tcase \"$mod_dst\" in\n-\t\t\t160000)\n-\t\t\t\tsha1_dst=$(GIT_DIR=\"$name/.git\" git rev-parse HEAD)\n-\t\t\t\t;;\n-\t\t\t100644 | 100755 | 120000)\n-\t\t\t\tsha1_dst=$(git hash-object $name)\n-\t\t\t\t;;\n-\t\t\t000000)\n-\t\t\t\t;; # removed\n-\t\t\t*)\n-\t\t\t\t# unexpected type\n-\t\t\t\teval_gettextln \"unexpected mode \\$mod_dst\" >&2\n-\t\t\t\tcontinue ;;\n-\t\t\tesac\n-\t\tfi\n-\t\tmissing_src=\n-\t\tmissing_dst=\n-\n-\t\ttest $mod_src = 160000 &&\n-\t\t! GIT_DIR=\"$name/.git\" git-rev-parse -q --verify $sha1_src^0 >/dev/null &&\n-\t\tmissing_src=t\n-\n-\t\ttest $mod_dst = 160000 &&\n-\t\t! GIT_DIR=\"$name/.git\" git-rev-parse -q --verify $sha1_dst^0 >/dev/null &&\n-\t\tmissing_dst=t\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper summary ${GIT_QUIET:+--quiet} ${prefix:+--prefix \"$prefix\"} ${for_status:+--for-status} ${files:+--files} ${cached:+--cached} ${summary_limit:+-n $summary_limit} \"$@\"\n \n-\t\tdisplay_name=$(git submodule--helper relative-path \"$name\" \"$wt_prefix\")\n-\n-\t\ttotal_commits=\n-\t\tcase \"$missing_src,$missing_dst\" in\n-\t\tt,)\n-\t\t\terrmsg=\"$(eval_gettext \"  Warn: \\$display_name doesn't contain commit \\$sha1_src\")\"\n-\t\t\t;;\n-\t\t,t)\n-\t\t\terrmsg=\"$(eval_gettext \"  Warn: \\$display_name doesn't contain commit \\$sha1_dst\")\"\n-\t\t\t;;\n-\t\tt,t)\n-\t\t\terrmsg=\"$(eval_gettext \"  Warn: \\$display_name doesn't contain commits \\$sha1_src and \\$sha1_dst\")\"\n-\t\t\t;;\n-\t\t*)\n-\t\t\terrmsg=\n-\t\t\ttotal_commits=$(\n-\t\t\tif test $mod_src = 160000 && test $mod_dst = 160000\n-\t\t\tthen\n-\t\t\t\trange=\"$sha1_src...$sha1_dst\"\n-\t\t\telif test $mod_src = 160000\n-\t\t\tthen\n-\t\t\t\trange=$sha1_src\n-\t\t\telse\n-\t\t\t\trange=$sha1_dst\n-\t\t\tfi\n-\t\t\tGIT_DIR=\"$name/.git\" \\\n-\t\t\tgit rev-list --first-parent $range -- | wc -l\n-\t\t\t)\n-\t\t\ttotal_commits=\" ($(($total_commits + 0)))\"\n-\t\t\t;;\n-\t\tesac\n-\n-\t\tsha1_abbr_src=$(echo $sha1_src | cut -c1-7)\n-\t\tsha1_abbr_dst=$(echo $sha1_dst | cut -c1-7)\n-\t\tif test $status = T\n-\t\tthen\n-\t\t\tblob=\"$(gettext \"blob\")\"\n-\t\t\tsubmodule=\"$(gettext \"submodule\")\"\n-\t\t\tif test $mod_dst = 160000\n-\t\t\tthen\n-\t\t\t\techo \"* $display_name $sha1_abbr_src($blob)->$sha1_abbr_dst($submodule)$total_commits:\"\n-\t\t\telse\n-\t\t\t\techo \"* $display_name $sha1_abbr_src($submodule)->$sha1_abbr_dst($blob)$total_commits:\"\n-\t\t\tfi\n-\t\telse\n-\t\t\techo \"* $display_name $sha1_abbr_src...$sha1_abbr_dst$total_commits:\"\n-\t\tfi\n-\t\tif test -n \"$errmsg\"\n-\t\tthen\n-\t\t\t# Don't give error msg for modification whose dst is not submodule\n-\t\t\t# i.e. deleted or changed to blob\n-\t\t\ttest $mod_dst = 160000 && echo \"$errmsg\"\n-\t\telse\n-\t\t\tif test $mod_src = 160000 && test $mod_dst = 160000\n-\t\t\tthen\n-\t\t\t\tlimit=\n-\t\t\t\ttest $summary_limit -gt 0 && limit=\"-$summary_limit\"\n-\t\t\t\tGIT_DIR=\"$name/.git\" \\\n-\t\t\t\tgit log $limit --pretty='format:  %m %s' \\\n-\t\t\t\t--first-parent $sha1_src...$sha1_dst\n-\t\t\telif test $mod_dst = 160000\n-\t\t\tthen\n-\t\t\t\tGIT_DIR=\"$name/.git\" \\\n-\t\t\t\tgit log --pretty='format:  > %s' -1 $sha1_dst\n-\t\t\telse\n-\t\t\t\tGIT_DIR=\"$name/.git\" \\\n-\t\t\t\tgit log --pretty='format:  < %s' -1 $sha1_src\n-\t\t\tfi\n-\t\t\techo\n-\t\tfi\n-\t\techo\n-\tdone\n }\n #\n # List all submodules, prefixed with:\n-- \n2.13.0\n\n"},{"id":"324129","messageId":"20170710225407.29344-5-pc44800@gmail.com","threadId":"46351","inReplyTo":"20170710225407.29344-1-pc44800@gmail.com","subject":"[GSoC][PATCH 5/8] submodule: port submodule subcommand 'sync' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-10T22:54:04Z","receivedAt":"2017-07-10T22:54:50Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"Port the submodule subcommand 'sync' from shell to C using the same\nmechanism as that used for porting submodule subcommand 'status'.\nHence, here the function cmd_sync() is ported from shell to C.\nThis is done by introducing three functions: module_sync(),\nsync_submodule() and print_default_remote().\n\nThe function print_default_remote() is introduced for getting\nthe default remote as stdout.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 181 +++++++++++++++++++++++++++++++++++++++++++-\n git-submodule.sh            |  56 +-------------\n 2 files changed, 181 insertions(+), 56 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 980b8ed27..4e04b93f3 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -44,6 +44,20 @@ static char *get_default_remote(void)\n \treturn ret;\n }\n \n+static int print_default_remote(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *remote;\n+\n+\tif (argc != 1)\n+\t\tdie(_(\"submodule--helper print-default-remote takes no arguments\"));\n+\n+\tremote = get_default_remote();\n+\tif (remote)\n+\t\tputs(remote);\n+\n+\treturn 0;\n+}\n+\n static int starts_with_dot_slash(const char *str)\n {\n \treturn str[0] == '.' && is_dir_sep(str[1]);\n@@ -379,6 +393,25 @@ static void module_list_active(struct module_list *list)\n \t*list = active_modules;\n }\n \n+static char *get_up_path(const char *path)\n+{\n+\tint i;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\tfor (i = count_slashes(path); i; i--)\n+\t\tstrbuf_addstr(&sb, \"../\");\n+\n+\t/*\n+\t * Check if 'path' ends with slash or not\n+\t * for having the same output for dir/sub_dir\n+\t * and dir/sub_dir/\n+\t */\n+\tif (!is_dir_sep(path[strlen(path) - 1]))\n+\t\tstrbuf_addstr(&sb, \"../\");\n+\n+\treturn strbuf_detach(&sb, NULL);\n+}\n+\n static int module_list(int argc, const char **argv, const char *prefix)\n {\n \tint i;\n@@ -478,16 +511,18 @@ static void init_submodule(const struct cache_entry *list_item, void *cb_data)\n \t\t\tchar *remote = get_default_remote();\n \t\t\tstruct strbuf remotesb = STRBUF_INIT;\n \t\t\tstrbuf_addf(&remotesb, \"remote.%s.url\", remote);\n-\t\t\tfree(remote);\n \n \t\t\tif (git_config_get_string(remotesb.buf, &remoteurl)) {\n \t\t\t\twarning(_(\"could not lookup configuration '%s'. Assuming this repository is its own authoritative upstream.\"), remotesb.buf);\n \t\t\t\tremoteurl = xgetcwd();\n \t\t\t}\n \t\t\trelurl = relative_url(remoteurl, url, NULL);\n+\n+\t\t\tfree(remote);\n \t\t\tstrbuf_release(&remotesb);\n \t\t\tfree(remoteurl);\n \t\t\tfree(url);\n+\n \t\t\turl = relurl;\n \t\t}\n \n@@ -732,6 +767,148 @@ static int module_name(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+struct sync_cb {\n+\tconst char *prefix;\n+\tunsigned int quiet: 1;\n+\tunsigned int recursive: 1;\n+};\n+#define SYNC_CB_INIT { NULL, 0, 0 }\n+\n+static void sync_submodule(const struct cache_entry *list_item, void *cb_data)\n+{\n+\tstruct sync_cb *info = cb_data;\n+\tconst struct submodule *sub;\n+\tchar *sub_key, *remote_key;\n+\tchar *sub_origin_url, *super_config_url, *displaypath;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n+\tif (!is_submodule_active(the_repository, list_item->name))\n+\t\treturn;\n+\n+\tsub = submodule_from_path(null_sha1, list_item->name);\n+\n+\tif (!sub || !sub->url)\n+\t\tdie(_(\"no url found for submodule path '%s' in .gitmodules\"),\n+\t\t      list_item->name);\n+\n+\tif (starts_with_dot_dot_slash(sub->url) || starts_with_dot_slash(sub->url)) {\n+\t\tchar *remote_url, *up_path;\n+\t\tchar *remote = get_default_remote();\n+\t\tchar *remote_key = xstrfmt(\"remote.%s.url\", remote);\n+\t\tfree(remote);\n+\n+\t\tif (git_config_get_string(remote_key, &remote_url))\n+\t\t\tremote_url = xgetcwd();\n+\t\tup_path = get_up_path(list_item->name);\n+\t\tsub_origin_url = relative_url(remote_url, sub->url, up_path);\n+\t\tsuper_config_url = relative_url(remote_url, sub->url, NULL);\n+\t\tfree(remote_key);\n+\t\tfree(up_path);\n+\t\tfree(remote_url);\n+\t} else {\n+\t\tsub_origin_url = xstrdup(sub->url);\n+\t\tsuper_config_url = xstrdup(sub->url);\n+\t}\n+\n+\tdisplaypath = get_submodule_displaypath(list_item->name, info->prefix);\n+\n+\tif (!info->quiet)\n+\t\tprintf(_(\"Synchronizing submodule url for '%s'\\n\"),\n+\t\t\t displaypath);\n+\n+\tsub_key = xstrfmt(\"submodule.%s.url\", sub->name);\n+\tif (git_config_set_gently(sub_key, super_config_url))\n+\t\tdie(_(\"failed to register url for submodule path '%s'\"),\n+\t\t      displaypath);\n+\n+\tif (!is_submodule_populated_gently(list_item->name, NULL))\n+\t\tgoto cleanup;\n+\n+\tprepare_submodule_repo_env(&cp.env_array);\n+\tcp.git_cmd = 1;\n+\tcp.dir = list_item->name;\n+\targv_array_pushl(&cp.args, \"submodule--helper\",\n+\t\t\t \"print-default-remote\", NULL);\n+\tif (capture_command(&cp, &sb, 0))\n+\t\tdie(_(\"failed to get the default remote for submodule '%s'\"),\n+\t\t      list_item->name);\n+\n+\tstrbuf_strip_suffix(&sb, \"\\n\");\n+\tremote_key = xstrfmt(\"remote.%s.url\", sb.buf);\n+\tstrbuf_release(&sb);\n+\n+\tchild_process_init(&cp);\n+\tprepare_submodule_repo_env(&cp.env_array);\n+\tcp.git_cmd = 1;\n+\tcp.dir = list_item->name;\n+\targv_array_pushl(&cp.args, \"config\", remote_key, sub_origin_url, NULL);\n+\tif (run_command(&cp))\n+\t\tdie(_(\"failed to update remote for submodule '%s'\"),\n+\t\t      list_item->name);\n+\n+\tif (info->recursive) {\n+\t\tstruct child_process cpr = CHILD_PROCESS_INIT;\n+\n+\t\tcpr.git_cmd = 1;\n+\t\tcpr.dir = list_item->name;\n+\t\tprepare_submodule_repo_env(&cpr.env_array);\n+\n+\t\targv_array_pushl(&cpr.args, \"--super-prefix\", displaypath,\n+\t\t\t\t \"submodule--helper\", \"sync\", \"--recursive\",\n+\t\t\t\t NULL);\n+\n+\t\tif (info->quiet)\n+\t\t\targv_array_push(&cpr.args, \"--quiet\");\n+\n+\t\tif (run_command(&cpr))\n+\t\t\tdie(_(\"failed to recurse into submodule '%s'\"),\n+\t\t\t      list_item->name);\n+\t}\n+\n+cleanup:\n+\tfree(sub_key);\n+\tfree(super_config_url);\n+\tfree(displaypath);\n+\tfree(sub_origin_url);\n+}\n+\n+static int module_sync(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct sync_cb info = SYNC_CB_INIT;\n+\tstruct pathspec pathspec;\n+\tstruct module_list list = MODULE_LIST_INIT;\n+\tint quiet = 0;\n+\tint recursive = 0;\n+\n+\tstruct option module_sync_options[] = {\n+\t\tOPT__QUIET(&quiet, N_(\"Suppress output of synchronizing submodule url\")),\n+\t\tOPT_BOOL(0, \"recursive\", &recursive,\n+\t\t\tN_(\"Recurse into nested submodules\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule--helper sync [--quiet] [--recursive] [<path>]\"),\n+\t\tNULL\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, module_sync_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n+\t\treturn 1;\n+\n+\tinfo.prefix = prefix;\n+\tinfo.quiet = !!quiet;\n+\tinfo.recursive = !!recursive;\n+\n+\tgitmodules_config();\n+\tfor_each_submodule_list(list, sync_submodule, &info);\n+\n+\treturn 0;\n+}\n+\n static int clone_submodule(const char *path, const char *gitdir, const char *url,\n \t\t\t   const char *depth, struct string_list *reference,\n \t\t\t   int quiet, int progress)\n@@ -1460,6 +1637,8 @@ static struct cmd_struct commands[] = {\n \t{\"print-name-rev\", print_name_rev, 0},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n+\t{\"print-default-remote\", print_default_remote, 0},\n+\t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 51b057d82..6bfc5e17d 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -1037,63 +1037,9 @@ cmd_sync()\n \t\t\t;;\n \t\tesac\n \tdone\n-\tcd_to_toplevel\n-\t{\n-\t\tgit submodule--helper list --prefix \"$wt_prefix\" \"$@\" ||\n-\t\techo \"#unmatched\" $?\n-\t} |\n-\twhile read -r mode sha1 stage sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$mode\" \"$sha1\"\n-\n-\t\t# skip inactive submodules\n-\t\tif ! git submodule--helper is-active \"$sm_path\"\n-\t\tthen\n-\t\t\tcontinue\n-\t\tfi\n-\n-\t\tname=$(git submodule--helper name \"$sm_path\")\n-\t\turl=$(git config -f .gitmodules --get submodule.\"$name\".url)\n-\n-\t\t# Possibly a url relative to parent\n-\t\tcase \"$url\" in\n-\t\t./*|../*)\n-\t\t\t# rewrite foo/bar as ../.. to find path from\n-\t\t\t# submodule work tree to superproject work tree\n-\t\t\tup_path=\"$(printf '%s\\n' \"$sm_path\" | sed \"s/[^/][^/]*/../g\")\" &&\n-\t\t\t# guarantee a trailing /\n-\t\t\tup_path=${up_path%/}/ &&\n-\t\t\t# path from submodule work tree to submodule origin repo\n-\t\t\tsub_origin_url=$(git submodule--helper resolve-relative-url \"$url\" \"$up_path\") &&\n-\t\t\t# path from superproject work tree to submodule origin repo\n-\t\t\tsuper_config_url=$(git submodule--helper resolve-relative-url \"$url\") || exit\n-\t\t\t;;\n-\t\t*)\n-\t\t\tsub_origin_url=\"$url\"\n-\t\t\tsuper_config_url=\"$url\"\n-\t\t\t;;\n-\t\tesac\n \n-\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n-\t\tsay \"$(eval_gettext \"Synchronizing submodule url for '\\$displaypath'\")\"\n-\t\tgit config submodule.\"$name\".url \"$super_config_url\"\n-\n-\t\tif test -e \"$sm_path\"/.git\n-\t\tthen\n-\t\t(\n-\t\t\tsanitize_submodule_env\n-\t\t\tcd \"$sm_path\"\n-\t\t\tremote=$(get_default_remote)\n-\t\t\tgit config remote.\"$remote\".url \"$sub_origin_url\"\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper sync ${GIT_QUIET:+--quiet} ${recursive:+--recursive} \"$@\"\n \n-\t\t\tif test -n \"$recursive\"\n-\t\t\tthen\n-\t\t\t\tprefix=\"$prefix$sm_path/\"\n-\t\t\t\teval cmd_sync\n-\t\t\tfi\n-\t\t)\n-\t\tfi\n-\tdone\n }\n \n cmd_absorbgitdirs()\n-- \n2.13.0\n\n"},{"id":"324130","messageId":"20170710225407.29344-3-pc44800@gmail.com","threadId":"46351","inReplyTo":"20170710225407.29344-1-pc44800@gmail.com","subject":"[GSoC][PATCH 3/8] submodule: port set_name_rev() from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-10T22:54:02Z","receivedAt":"2017-07-10T22:54:51Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"Function set_name_rev() is ported from git-submodule to the\nsubmodule--helper builtin. The function get_name_rev() generates the\nvalue of the revision name as required, and the function\nprint_name_rev() handles the formating and printing of the obtained\nrevision name.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 63 +++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            | 16 ++----------\n 2 files changed, 65 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex e41572f7a..80f744407 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -244,6 +244,68 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)\n \t}\n }\n \n+static char *get_name_rev(const char *sub_path, const char* object_id)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tconst char ***d;\n+\n+\tstatic const char *describe_bare[] = {\n+\t\tNULL\n+\t};\n+\n+\tstatic const char *describe_tags[] = {\n+\t\t\"--tags\", NULL\n+\t};\n+\n+\tstatic const char *describe_contains[] = {\n+\t\t\"--contains\", NULL\n+\t};\n+\n+\tstatic const char *describe_all_always[] = {\n+\t\t\"--all\", \"--always\", NULL\n+\t};\n+\n+\tstatic const char **describe_argv[] = {\n+\t\tdescribe_bare, describe_tags, describe_contains,\n+\t\tdescribe_all_always, NULL\n+\t};\n+\n+\tfor (d = describe_argv; *d; d++) {\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\tprepare_submodule_repo_env(&cp.env_array);\n+\t\tcp.dir = sub_path;\n+\t\tcp.git_cmd = 1;\n+\t\tcp.no_stderr = 1;\n+\n+\t\targv_array_push(&cp.args, \"describe\");\n+\t\targv_array_pushv(&cp.args, *d);\n+\t\targv_array_push(&cp.args, object_id);\n+\n+\t\tif (!capture_command(&cp, &sb, 0) && sb.len) {\n+\t\t\tstrbuf_strip_suffix(&sb, \"\\n\");\n+\t\t\treturn strbuf_detach(&sb, NULL);\n+\t\t}\n+\n+\t}\n+\n+\tstrbuf_release(&sb);\n+\treturn NULL;\n+}\n+\n+static int print_name_rev(int argc, const char **argv, const char *prefix)\n+{\n+\tchar *namerev;\n+\tif (argc != 3)\n+\t\tdie(\"print-name-rev only accepts two arguments: <path> <sha1>\");\n+\n+\tnamerev = get_name_rev(argv[1], argv[2]);\n+\tif (namerev && namerev[0])\n+\t\tprintf(\" (%s)\", namerev);\n+\tprintf(\"\\n\");\n+\n+\treturn 0;\n+}\n+\n struct module_list {\n \tconst struct cache_entry **entries;\n \tint alloc, nr;\n@@ -1242,6 +1304,7 @@ static struct cmd_struct commands[] = {\n \t{\"relative-path\", resolve_relative_path, 0},\n \t{\"resolve-relative-url\", resolve_relative_url, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n+\t{\"print-name-rev\", print_name_rev, 0},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex e131760ee..e988167e0 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -759,18 +759,6 @@ cmd_update()\n \t}\n }\n \n-set_name_rev () {\n-\trevname=$( (\n-\t\tsanitize_submodule_env\n-\t\tcd \"$1\" && {\n-\t\t\tgit describe \"$2\" 2>/dev/null ||\n-\t\t\tgit describe --tags \"$2\" 2>/dev/null ||\n-\t\t\tgit describe --contains \"$2\" 2>/dev/null ||\n-\t\t\tgit describe --all --always \"$2\"\n-\t\t}\n-\t) )\n-\ttest -z \"$revname\" || revname=\" ($revname)\"\n-}\n #\n # Show commit summary for submodules in index or working tree\n #\n@@ -1042,14 +1030,14 @@ cmd_status()\n \t\tfi\n \t\tif git diff-files --ignore-submodules=dirty --quiet -- \"$sm_path\"\n \t\tthen\n-\t\t\tset_name_rev \"$sm_path\" \"$sha1\"\n+\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n \t\t\tsay \" $sha1 $displaypath$revname\"\n \t\telse\n \t\t\tif test -z \"$cached\"\n \t\t\tthen\n \t\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" && git rev-parse --verify HEAD)\n \t\t\tfi\n-\t\t\tset_name_rev \"$sm_path\" \"$sha1\"\n+\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n \t\t\tsay \"+$sha1 $displaypath$revname\"\n \t\tfi\n \n-- \n2.13.0\n\n"},{"id":"324131","messageId":"20170710233247.GC161700@google.com","threadId":"46351","inReplyTo":"20170710225407.29344-1-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 1/8] submodule--helper: introduce get_submodule_displaypath()","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-07-10T23:32:47Z","receivedAt":"2017-07-10T23:32:55Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 07/11, Prathamesh Chavan wrote:\n> Introduce function get_submodule_displaypath() to replace the code\n> occurring in submodule_init() for generating displaypath of the\n> submodule with a call to it.\n> \n> This new function will also be used in other parts of the system\n> in later patches.\n> \n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Stefan Beller <sbeller@google.com>\n> Signed-off-by: Prathamesh Chavan <pc44800@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 33 ++++++++++++++++++++++-----------\n>  1 file changed, 22 insertions(+), 11 deletions(-)\n> \n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 6abdad329..7af4de09b 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -220,6 +220,27 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr\n>  \treturn 0;\n>  }\n>  \n> +static char *get_submodule_displaypath(const char *path, const char *prefix)\n> +{\n> +\tconst char *super_prefix = get_super_prefix();\n> +\n> +\tif (prefix && super_prefix) {\n> +\t\tBUG(\"cannot have prefix '%s' and superprefix '%s'\",\n> +\t\t    prefix, super_prefix);\n> +\t} else if (prefix) {\n> +\t\tstruct strbuf sb = STRBUF_INIT;\n> +\t\tchar *displaypath = xstrdup(relative_path(path, prefix, &sb));\n> +\t\tstrbuf_release(&sb);\n> +\t\treturn displaypath;\n> +\t} else if (super_prefix) {\n> +\t\tint len = strlen(super_prefix);\n> +\t\tconst char *format = is_dir_sep(super_prefix[len - 1]) ? \"%s%s\" : \"%s/%s\";\n> +\t\treturn xstrfmt(format, super_prefix, path);\n> +\t} else {\n> +\t\treturn xstrdup(path);\n> +\t}\n> +}\n> +\n>  struct module_list {\n>  \tconst struct cache_entry **entries;\n>  \tint alloc, nr;\n> @@ -339,16 +360,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n>  \n>  \t/* Only loads from .gitmodules, no overlay with .git/config */\n>  \tgitmodules_config();\n> -\n> -\tif (prefix && get_super_prefix())\n> -\t\tdie(\"BUG: cannot have prefix and superprefix\");\n> -\telse if (prefix)\n> -\t\tdisplaypath = xstrdup(relative_path(path, prefix, &sb));\n> -\telse if (get_super_prefix()) {\n> -\t\tstrbuf_addf(&sb, \"%s%s\", get_super_prefix(), path);\n> -\t\tdisplaypath = strbuf_detach(&sb, NULL);\n> -\t} else\n> -\t\tdisplaypath = xstrdup(path);\n> +\tdisplaypath = get_submodule_displaypath(path, prefix);\n>  \n>  \tsub = submodule_from_path(null_sha1, path);\n>  \n> @@ -363,7 +375,6 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n>  \t * Set active flag for the submodule being initialized\n>  \t */\n>  \tif (!is_submodule_active(the_repository, path)) {\n> -\t\tstrbuf_reset(&sb);\n\nIs this line removal intended?  It doesn't look related to the rest of\nthis patch.\n\n>  \t\tstrbuf_addf(&sb, \"submodule.%s.active\", sub->name);\n>  \t\tgit_config_set_gently(sb.buf, \"true\");\n>  \t}\n> -- \n> 2.13.0\n> \n\n-- \nBrandon Williams\n"},{"id":"324133","messageId":"20170710233824.GD161700@google.com","threadId":"46351","inReplyTo":"20170710225407.29344-4-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 4/8] submodule: port submodule subcommand 'status' from shell to C","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-07-10T23:38:24Z","receivedAt":"2017-07-10T23:38:33Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 07/11, Prathamesh Chavan wrote:\n> This aims to make git-submodule 'status' a built-in. Hence, the function\n> cmd_status() is ported from shell to C. This is done by introducing\n> three functions: module_status(), submodule_status() and print_status().\n> \n> The function module_status() acts as the front-end of the subcommand.\n> It parses subcommand's options and then calls the function\n> module_list_compute() for computing the list of submodules. Then\n> this functions calls for_each_submodule_list() looping through the\n> list obtained.\n> \n> Then for_each_submodule_list() calls submodule_status() for each of the\n> submodule in its list. The function submodule_status() is responsible\n> for generating the status each submodule it is called for, and\n> then calls print_status().\n> \n> Finally, the function print_status() handles the printing of submodule's\n> status.\n> \n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Stefan Beller <sbeller@google.com>\n> Signed-off-by: Prathamesh Chavan <pc44800@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 154 ++++++++++++++++++++++++++++++++++++++++++++\n>  git-submodule.sh            |  49 +-------------\n>  2 files changed, 155 insertions(+), 48 deletions(-)\n> \n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 80f744407..980b8ed27 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -560,6 +560,159 @@ static int module_init(int argc, const char **argv, const char *prefix)\n>  \treturn 0;\n>  }\n>  \n> +struct status_cb {\n> +\tconst char *prefix;\n> +\tunsigned int quiet: 1;\n> +\tunsigned int recursive: 1;\n> +\tunsigned int cached: 1;\n> +};\n> +#define STATUS_CB_INIT { NULL, 0, 0, 0 }\n> +\n> +static void print_status(struct status_cb *info, char state, const char *path,\n> +\t\t\t char *sub_sha1, char *displaypath)\n> +{\n> +\tif (info->quiet)\n> +\t\treturn;\n> +\n> +\tprintf(\"%c%s %s\", state, sub_sha1, displaypath);\n> +\n> +\tif (state == ' ' || state == '+') {\n> +\t\tstruct argv_array name_rev_args = ARGV_ARRAY_INIT;\n\nThis struct needs to be cleared to prevent a memory leak.\n\n> +\n> +\t\targv_array_pushl(&name_rev_args, \"print-name-rev\",\n> +\t\t\t\t path, sub_sha1, NULL);\n> +\t\tprint_name_rev(name_rev_args.argc, name_rev_args.argv,\n> +\t\t\t       info->prefix);\n> +\t} else {\n> +\t\tprintf(\"\\n\");\n> +\t}\n> +}\n> +\n> +static void status_submodule(const struct cache_entry *list_item, void *cb_data)\n> +{\n> +\tstruct status_cb *info = cb_data;\n> +\tchar *sub_sha1 = xstrdup(oid_to_hex(&list_item->oid));\n> +\tchar *displaypath;\n> +\tstruct argv_array diff_files_args = ARGV_ARRAY_INIT;\n> +\n> +\tif (!submodule_from_path(null_sha1, list_item->name))\n> +\t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n> +\t\t      list_item->name);\n> +\n> +\tdisplaypath = get_submodule_displaypath(list_item->name, info->prefix);\n> +\n> +\tif (list_item->ce_flags) {\n> +\t\tprint_status(info, 'U', list_item->name,\n> +\t\t\t     sha1_to_hex(null_sha1), displaypath);\n> +\t\tgoto cleanup;\n> +\t}\n> +\n> +\tif (!is_submodule_active(the_repository, list_item->name)) {\n> +\t\tprint_status(info, '-', list_item->name, sub_sha1, displaypath);\n> +\t\tgoto cleanup;\n> +\t}\n> +\n> +\targv_array_pushl(&diff_files_args, \"diff-files\",\n> +\t\t\t \"--ignore-submodules=dirty\", \"--quiet\", \"--\",\n> +\t\t\t list_item->name, NULL);\n> +\n> +\t/* NEEDSWORK: future optimization possible */\n\nWhat sort of optimization? maybe you could document that?\n\n> +\tif (!cmd_diff_files(diff_files_args.argc, diff_files_args.argv,\n> +\t\t\t    info->prefix)) {\n> +\t\tprint_status(info, ' ', list_item->name, sub_sha1, displaypath);\n> +\t} else {\n> +\t\tif (!info->cached) {\n> +\t\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n> +\t\t\tstruct strbuf sb = STRBUF_INIT;\n> +\n> +\t\t\tprepare_submodule_repo_env(&cp.env_array);\n> +\t\t\tcp.git_cmd = 1;\n> +\t\t\tcp.dir = list_item->name;\n> +\n> +\t\t\targv_array_pushl(&cp.args, \"rev-parse\",\n> +\t\t\t\t\t \"--verify\", \"HEAD\", NULL);\n> +\n> +\t\t\t/* NEEDSWORK: future optimization possible */\n\nSame here.\n\n> +\t\t\tif (capture_command(&cp, &sb, 0))\n> +\t\t\t\tdie(_(\"could not run 'git rev-parse --verify\"\n> +\t\t\t\t      \"HEAD' in submodule %s\"),\n> +\t\t\t\t      list_item->name);\n> +\n> +\t\t\tstrbuf_strip_suffix(&sb, \"\\n\");\n> +\t\t\tprint_status(info, '+', list_item->name, sb.buf,\n> +\t\t\t\t     displaypath);\n> +\t\t\tstrbuf_release(&sb);\n> +\t\t} else {\n> +\t\t\tprint_status(info, '+', list_item->name, sub_sha1,\n> +\t\t\t\t     displaypath);\n> +\t\t}\n> +\t}\n> +\n> +\tif (info->recursive) {\n> +\t\tstruct child_process cpr = CHILD_PROCESS_INIT;\n> +\n> +\t\tcpr.git_cmd = 1;\n> +\t\tcpr.dir = list_item->name;\n> +\t\tprepare_submodule_repo_env(&cpr.env_array);\n> +\n> +\t\targv_array_pushl(&cpr.args, \"--super-prefix\", displaypath,\n> +\t\t\t\t \"submodule--helper\", \"status\", \"--recursive\",\n> +\t\t\t\t NULL);\n> +\n> +\t\tif (info->cached)\n> +\t\t\targv_array_push(&cpr.args, \"--cached\");\n> +\n> +\t\tif (info->quiet)\n> +\t\t\targv_array_push(&cpr.args, \"--quiet\");\n> +\n> +\t\tif (run_command(&cpr))\n> +\t\t\tdie(_(\"failed to recurse into submodule '%s'\"),\n> +\t\t\t      list_item->name);\n> +\t}\n> +\n> +cleanup:\n> +\tfree(displaypath);\n> +\tfree(sub_sha1);\n> +}\n> +\n> +static int module_status(int argc, const char **argv, const char *prefix)\n> +{\n> +\tstruct status_cb info = STATUS_CB_INIT;\n> +\tstruct pathspec pathspec;\n> +\tstruct module_list list = MODULE_LIST_INIT;\n> +\tint quiet = 0;\n> +\tint cached = 0;\n> +\tint recursive = 0;\n> +\n> +\tstruct option module_status_options[] = {\n> +\t\tOPT__QUIET(&quiet, N_(\"Suppress submodule status output\")),\n> +\t\tOPT_BOOL(0, \"cached\", &cached, N_(\"Use commit stored in the index instead of the one stored in the submodule HEAD\")),\n> +\t\tOPT_BOOL(0, \"recursive\", &recursive, N_(\"Recurse into nested submodules\")),\n> +\t\tOPT_END()\n> +\t};\n> +\n> +\tconst char *const git_submodule_helper_usage[] = {\n> +\t\tN_(\"git submodule status [--quiet] [--cached] [--recursive] [<path>]\"),\n> +\t\tNULL\n> +\t};\n> +\n> +\targc = parse_options(argc, argv, prefix, module_status_options,\n> +\t\t\t     git_submodule_helper_usage, 0);\n> +\n> +\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n> +\t\treturn 1;\n> +\n> +\tinfo.prefix = prefix;\n> +\tinfo.quiet = !!quiet;\n> +\tinfo.recursive = !!recursive;\n> +\tinfo.cached = !!cached;\n> +\n> +\tgitmodules_config();\n> +\tfor_each_submodule_list(list, status_submodule, &info);\n> +\n> +\treturn 0;\n> +}\n> +\n>  static int module_name(int argc, const char **argv, const char *prefix)\n>  {\n>  \tconst struct submodule *sub;\n> @@ -1306,6 +1459,7 @@ static struct cmd_struct commands[] = {\n>  \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n>  \t{\"print-name-rev\", print_name_rev, 0},\n>  \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n> +\t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n>  \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n>  \t{\"push-check\", push_check, 0},\n>  \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\n> diff --git a/git-submodule.sh b/git-submodule.sh\n> index e988167e0..51b057d82 100755\n> --- a/git-submodule.sh\n> +++ b/git-submodule.sh\n> @@ -1005,54 +1005,7 @@ cmd_status()\n>  \t\tshift\n>  \tdone\n>  \n> -\t{\n> -\t\tgit submodule--helper list --prefix \"$wt_prefix\" \"$@\" ||\n> -\t\techo \"#unmatched\" $?\n> -\t} |\n> -\twhile read -r mode sha1 stage sm_path\n> -\tdo\n> -\t\tdie_if_unmatched \"$mode\" \"$sha1\"\n> -\t\tname=$(git submodule--helper name \"$sm_path\") || exit\n> -\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n> -\t\tif test \"$stage\" = U\n> -\t\tthen\n> -\t\t\tsay \"U$sha1 $displaypath\"\n> -\t\t\tcontinue\n> -\t\tfi\n> -\t\tif ! git submodule--helper is-active \"$sm_path\" ||\n> -\t\t{\n> -\t\t\t! test -d \"$sm_path\"/.git &&\n> -\t\t\t! test -f \"$sm_path\"/.git\n> -\t\t}\n> -\t\tthen\n> -\t\t\tsay \"-$sha1 $displaypath\"\n> -\t\t\tcontinue;\n> -\t\tfi\n> -\t\tif git diff-files --ignore-submodules=dirty --quiet -- \"$sm_path\"\n> -\t\tthen\n> -\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n> -\t\t\tsay \" $sha1 $displaypath$revname\"\n> -\t\telse\n> -\t\t\tif test -z \"$cached\"\n> -\t\t\tthen\n> -\t\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" && git rev-parse --verify HEAD)\n> -\t\t\tfi\n> -\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n> -\t\t\tsay \"+$sha1 $displaypath$revname\"\n> -\t\tfi\n> -\n> -\t\tif test -n \"$recursive\"\n> -\t\tthen\n> -\t\t\t(\n> -\t\t\t\tprefix=\"$displaypath/\"\n> -\t\t\t\tsanitize_submodule_env\n> -\t\t\t\twt_prefix=\n> -\t\t\t\tcd \"$sm_path\" &&\n> -\t\t\t\teval cmd_status\n> -\t\t\t) ||\n> -\t\t\tdie \"$(eval_gettext \"Failed to recurse into submodule path '\\$sm_path'\")\"\n> -\t\tfi\n> -\tdone\n> +\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper status ${GIT_QUIET:+--quiet} ${cached:+--cached} ${recursive:+--recursive} \"$@\"\n>  }\n>  #\n>  # Sync remote urls for submodules\n> -- \n> 2.13.0\n> \n\n-- \nBrandon Williams\n"},{"id":"324134","messageId":"CAGZ79kYpFHkkhdkwYXEnQiWfuRONurintje575YVLE-ZVVRvzA@mail.gmail.com","threadId":"46351","inReplyTo":"20170710233247.GC161700@google.com","subject":"Re: [GSoC][PATCH 1/8] submodule--helper: introduce get_submodule_displaypath()","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-07-10T23:38:54Z","receivedAt":"2017-07-10T23:39:01Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Mon, Jul 10, 2017 at 4:32 PM, Brandon Williams <bmwill@google.com> wrote:\n>>       if (!is_submodule_active(the_repository, path)) {\n>> -             strbuf_reset(&sb);\n>\n> Is this line removal intended?  It doesn't look related to the rest of\n> this patch.\n\nIt is, as &sb is re-used and has to be cleared first.\nWith the code above removed, &sb is unmodified since\nstruct strbuf sb = STRBUF_INIT; hence the removal is ok here.\nIt is related, but only when looking at the entirety of the code. :-/\n"},{"id":"324135","messageId":"20170710234117.GE161700@google.com","threadId":"46351","inReplyTo":"20170710225407.29344-5-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 5/8] submodule: port submodule subcommand 'sync' from shell to C","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-07-10T23:41:17Z","receivedAt":"2017-07-10T23:41:25Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 07/11, Prathamesh Chavan wrote:\n> Port the submodule subcommand 'sync' from shell to C using the same\n> mechanism as that used for porting submodule subcommand 'status'.\n> Hence, here the function cmd_sync() is ported from shell to C.\n> This is done by introducing three functions: module_sync(),\n> sync_submodule() and print_default_remote().\n> \n> The function print_default_remote() is introduced for getting\n> the default remote as stdout.\n> \n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Stefan Beller <sbeller@google.com>\n> Signed-off-by: Prathamesh Chavan <pc44800@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 181 +++++++++++++++++++++++++++++++++++++++++++-\n>  git-submodule.sh            |  56 +-------------\n>  2 files changed, 181 insertions(+), 56 deletions(-)\n> \n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 980b8ed27..4e04b93f3 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -44,6 +44,20 @@ static char *get_default_remote(void)\n>  \treturn ret;\n>  }\n>  \n> +static int print_default_remote(int argc, const char **argv, const char *prefix)\n> +{\n> +\tconst char *remote;\n> +\n> +\tif (argc != 1)\n> +\t\tdie(_(\"submodule--helper print-default-remote takes no arguments\"));\n> +\n> +\tremote = get_default_remote();\n> +\tif (remote)\n> +\t\tputs(remote);\n> +\n> +\treturn 0;\n> +}\n> +\n>  static int starts_with_dot_slash(const char *str)\n>  {\n>  \treturn str[0] == '.' && is_dir_sep(str[1]);\n> @@ -379,6 +393,25 @@ static void module_list_active(struct module_list *list)\n>  \t*list = active_modules;\n>  }\n>  \n> +static char *get_up_path(const char *path)\n> +{\n> +\tint i;\n> +\tstruct strbuf sb = STRBUF_INIT;\n> +\n> +\tfor (i = count_slashes(path); i; i--)\n> +\t\tstrbuf_addstr(&sb, \"../\");\n> +\n> +\t/*\n> +\t * Check if 'path' ends with slash or not\n> +\t * for having the same output for dir/sub_dir\n> +\t * and dir/sub_dir/\n> +\t */\n> +\tif (!is_dir_sep(path[strlen(path) - 1]))\n> +\t\tstrbuf_addstr(&sb, \"../\");\n> +\n> +\treturn strbuf_detach(&sb, NULL);\n> +}\n> +\n>  static int module_list(int argc, const char **argv, const char *prefix)\n>  {\n>  \tint i;\n> @@ -478,16 +511,18 @@ static void init_submodule(const struct cache_entry *list_item, void *cb_data)\n>  \t\t\tchar *remote = get_default_remote();\n>  \t\t\tstruct strbuf remotesb = STRBUF_INIT;\n>  \t\t\tstrbuf_addf(&remotesb, \"remote.%s.url\", remote);\n> -\t\t\tfree(remote);\n>  \n>  \t\t\tif (git_config_get_string(remotesb.buf, &remoteurl)) {\n>  \t\t\t\twarning(_(\"could not lookup configuration '%s'. Assuming this repository is its own authoritative upstream.\"), remotesb.buf);\n>  \t\t\t\tremoteurl = xgetcwd();\n>  \t\t\t}\n>  \t\t\trelurl = relative_url(remoteurl, url, NULL);\n> +\n> +\t\t\tfree(remote);\n>  \t\t\tstrbuf_release(&remotesb);\n>  \t\t\tfree(remoteurl);\n>  \t\t\tfree(url);\n> +\n>  \t\t\turl = relurl;\n\nThe changes in this function seem unintended.\n\n>  \t\t}\n>  \n> @@ -732,6 +767,148 @@ static int module_name(int argc, const char **argv, const char *prefix)\n>  \treturn 0;\n>  }\n>  \n> +struct sync_cb {\n> +\tconst char *prefix;\n> +\tunsigned int quiet: 1;\n> +\tunsigned int recursive: 1;\n> +};\n> +#define SYNC_CB_INIT { NULL, 0, 0 }\n> +\n> +static void sync_submodule(const struct cache_entry *list_item, void *cb_data)\n> +{\n> +\tstruct sync_cb *info = cb_data;\n> +\tconst struct submodule *sub;\n> +\tchar *sub_key, *remote_key;\n> +\tchar *sub_origin_url, *super_config_url, *displaypath;\n> +\tstruct strbuf sb = STRBUF_INIT;\n> +\tstruct child_process cp = CHILD_PROCESS_INIT;\n> +\n> +\tif (!is_submodule_active(the_repository, list_item->name))\n> +\t\treturn;\n> +\n> +\tsub = submodule_from_path(null_sha1, list_item->name);\n> +\n> +\tif (!sub || !sub->url)\n> +\t\tdie(_(\"no url found for submodule path '%s' in .gitmodules\"),\n> +\t\t      list_item->name);\n> +\n> +\tif (starts_with_dot_dot_slash(sub->url) || starts_with_dot_slash(sub->url)) {\n> +\t\tchar *remote_url, *up_path;\n> +\t\tchar *remote = get_default_remote();\n> +\t\tchar *remote_key = xstrfmt(\"remote.%s.url\", remote);\n> +\t\tfree(remote);\n> +\n> +\t\tif (git_config_get_string(remote_key, &remote_url))\n> +\t\t\tremote_url = xgetcwd();\n> +\t\tup_path = get_up_path(list_item->name);\n> +\t\tsub_origin_url = relative_url(remote_url, sub->url, up_path);\n> +\t\tsuper_config_url = relative_url(remote_url, sub->url, NULL);\n> +\t\tfree(remote_key);\n> +\t\tfree(up_path);\n> +\t\tfree(remote_url);\n> +\t} else {\n> +\t\tsub_origin_url = xstrdup(sub->url);\n> +\t\tsuper_config_url = xstrdup(sub->url);\n> +\t}\n> +\n> +\tdisplaypath = get_submodule_displaypath(list_item->name, info->prefix);\n> +\n> +\tif (!info->quiet)\n> +\t\tprintf(_(\"Synchronizing submodule url for '%s'\\n\"),\n> +\t\t\t displaypath);\n> +\n> +\tsub_key = xstrfmt(\"submodule.%s.url\", sub->name);\n> +\tif (git_config_set_gently(sub_key, super_config_url))\n> +\t\tdie(_(\"failed to register url for submodule path '%s'\"),\n> +\t\t      displaypath);\n> +\n> +\tif (!is_submodule_populated_gently(list_item->name, NULL))\n> +\t\tgoto cleanup;\n> +\n> +\tprepare_submodule_repo_env(&cp.env_array);\n> +\tcp.git_cmd = 1;\n> +\tcp.dir = list_item->name;\n> +\targv_array_pushl(&cp.args, \"submodule--helper\",\n> +\t\t\t \"print-default-remote\", NULL);\n> +\tif (capture_command(&cp, &sb, 0))\n> +\t\tdie(_(\"failed to get the default remote for submodule '%s'\"),\n> +\t\t      list_item->name);\n> +\n> +\tstrbuf_strip_suffix(&sb, \"\\n\");\n> +\tremote_key = xstrfmt(\"remote.%s.url\", sb.buf);\n> +\tstrbuf_release(&sb);\n> +\n> +\tchild_process_init(&cp);\n> +\tprepare_submodule_repo_env(&cp.env_array);\n> +\tcp.git_cmd = 1;\n> +\tcp.dir = list_item->name;\n> +\targv_array_pushl(&cp.args, \"config\", remote_key, sub_origin_url, NULL);\n> +\tif (run_command(&cp))\n> +\t\tdie(_(\"failed to update remote for submodule '%s'\"),\n> +\t\t      list_item->name);\n> +\n> +\tif (info->recursive) {\n> +\t\tstruct child_process cpr = CHILD_PROCESS_INIT;\n> +\n> +\t\tcpr.git_cmd = 1;\n> +\t\tcpr.dir = list_item->name;\n> +\t\tprepare_submodule_repo_env(&cpr.env_array);\n> +\n> +\t\targv_array_pushl(&cpr.args, \"--super-prefix\", displaypath,\n> +\t\t\t\t \"submodule--helper\", \"sync\", \"--recursive\",\n> +\t\t\t\t NULL);\n> +\n> +\t\tif (info->quiet)\n> +\t\t\targv_array_push(&cpr.args, \"--quiet\");\n> +\n> +\t\tif (run_command(&cpr))\n> +\t\t\tdie(_(\"failed to recurse into submodule '%s'\"),\n> +\t\t\t      list_item->name);\n> +\t}\n> +\n> +cleanup:\n> +\tfree(sub_key);\n> +\tfree(super_config_url);\n> +\tfree(displaypath);\n> +\tfree(sub_origin_url);\n> +}\n> +\n> +static int module_sync(int argc, const char **argv, const char *prefix)\n> +{\n> +\tstruct sync_cb info = SYNC_CB_INIT;\n> +\tstruct pathspec pathspec;\n> +\tstruct module_list list = MODULE_LIST_INIT;\n> +\tint quiet = 0;\n> +\tint recursive = 0;\n> +\n> +\tstruct option module_sync_options[] = {\n> +\t\tOPT__QUIET(&quiet, N_(\"Suppress output of synchronizing submodule url\")),\n> +\t\tOPT_BOOL(0, \"recursive\", &recursive,\n> +\t\t\tN_(\"Recurse into nested submodules\")),\n> +\t\tOPT_END()\n> +\t};\n> +\n> +\tconst char *const git_submodule_helper_usage[] = {\n> +\t\tN_(\"git submodule--helper sync [--quiet] [--recursive] [<path>]\"),\n> +\t\tNULL\n> +\t};\n> +\n> +\targc = parse_options(argc, argv, prefix, module_sync_options,\n> +\t\t\t     git_submodule_helper_usage, 0);\n> +\n> +\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n> +\t\treturn 1;\n> +\n> +\tinfo.prefix = prefix;\n> +\tinfo.quiet = !!quiet;\n> +\tinfo.recursive = !!recursive;\n> +\n> +\tgitmodules_config();\n> +\tfor_each_submodule_list(list, sync_submodule, &info);\n> +\n> +\treturn 0;\n> +}\n> +\n>  static int clone_submodule(const char *path, const char *gitdir, const char *url,\n>  \t\t\t   const char *depth, struct string_list *reference,\n>  \t\t\t   int quiet, int progress)\n> @@ -1460,6 +1637,8 @@ static struct cmd_struct commands[] = {\n>  \t{\"print-name-rev\", print_name_rev, 0},\n>  \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n>  \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n> +\t{\"print-default-remote\", print_default_remote, 0},\n> +\t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n>  \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n>  \t{\"push-check\", push_check, 0},\n>  \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\n> diff --git a/git-submodule.sh b/git-submodule.sh\n> index 51b057d82..6bfc5e17d 100755\n> --- a/git-submodule.sh\n> +++ b/git-submodule.sh\n> @@ -1037,63 +1037,9 @@ cmd_sync()\n>  \t\t\t;;\n>  \t\tesac\n>  \tdone\n> -\tcd_to_toplevel\n> -\t{\n> -\t\tgit submodule--helper list --prefix \"$wt_prefix\" \"$@\" ||\n> -\t\techo \"#unmatched\" $?\n> -\t} |\n> -\twhile read -r mode sha1 stage sm_path\n> -\tdo\n> -\t\tdie_if_unmatched \"$mode\" \"$sha1\"\n> -\n> -\t\t# skip inactive submodules\n> -\t\tif ! git submodule--helper is-active \"$sm_path\"\n> -\t\tthen\n> -\t\t\tcontinue\n> -\t\tfi\n> -\n> -\t\tname=$(git submodule--helper name \"$sm_path\")\n> -\t\turl=$(git config -f .gitmodules --get submodule.\"$name\".url)\n> -\n> -\t\t# Possibly a url relative to parent\n> -\t\tcase \"$url\" in\n> -\t\t./*|../*)\n> -\t\t\t# rewrite foo/bar as ../.. to find path from\n> -\t\t\t# submodule work tree to superproject work tree\n> -\t\t\tup_path=\"$(printf '%s\\n' \"$sm_path\" | sed \"s/[^/][^/]*/../g\")\" &&\n> -\t\t\t# guarantee a trailing /\n> -\t\t\tup_path=${up_path%/}/ &&\n> -\t\t\t# path from submodule work tree to submodule origin repo\n> -\t\t\tsub_origin_url=$(git submodule--helper resolve-relative-url \"$url\" \"$up_path\") &&\n> -\t\t\t# path from superproject work tree to submodule origin repo\n> -\t\t\tsuper_config_url=$(git submodule--helper resolve-relative-url \"$url\") || exit\n> -\t\t\t;;\n> -\t\t*)\n> -\t\t\tsub_origin_url=\"$url\"\n> -\t\t\tsuper_config_url=\"$url\"\n> -\t\t\t;;\n> -\t\tesac\n>  \n> -\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n> -\t\tsay \"$(eval_gettext \"Synchronizing submodule url for '\\$displaypath'\")\"\n> -\t\tgit config submodule.\"$name\".url \"$super_config_url\"\n> -\n> -\t\tif test -e \"$sm_path\"/.git\n> -\t\tthen\n> -\t\t(\n> -\t\t\tsanitize_submodule_env\n> -\t\t\tcd \"$sm_path\"\n> -\t\t\tremote=$(get_default_remote)\n> -\t\t\tgit config remote.\"$remote\".url \"$sub_origin_url\"\n> +\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper sync ${GIT_QUIET:+--quiet} ${recursive:+--recursive} \"$@\"\n>  \n> -\t\t\tif test -n \"$recursive\"\n> -\t\t\tthen\n> -\t\t\t\tprefix=\"$prefix$sm_path/\"\n> -\t\t\t\teval cmd_sync\n> -\t\t\tfi\n> -\t\t)\n> -\t\tfi\n> -\tdone\n>  }\n>  \n>  cmd_absorbgitdirs()\n> -- \n> 2.13.0\n> \n\n-- \nBrandon Williams\n"},{"id":"324136","messageId":"20170710234252.GF161700@google.com","threadId":"46351","inReplyTo":"CAGZ79kYpFHkkhdkwYXEnQiWfuRONurintje575YVLE-ZVVRvzA@mail.gmail.com","subject":"Re: [GSoC][PATCH 1/8] submodule--helper: introduce get_submodule_displaypath()","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-07-10T23:42:52Z","receivedAt":"2017-07-10T23:43:01Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 07/10, Stefan Beller wrote:\n> On Mon, Jul 10, 2017 at 4:32 PM, Brandon Williams <bmwill@google.com> wrote:\n> >>       if (!is_submodule_active(the_repository, path)) {\n> >> -             strbuf_reset(&sb);\n> >\n> > Is this line removal intended?  It doesn't look related to the rest of\n> > this patch.\n> \n> It is, as &sb is re-used and has to be cleared first.\n> With the code above removed, &sb is unmodified since\n> struct strbuf sb = STRBUF_INIT; hence the removal is ok here.\n> It is related, but only when looking at the entirety of the code. :-/\n\nAh I see. Thanks!\n\n-- \nBrandon Williams\n"}]}