{"thread":{"id":"11150","subject":"[PATCH 0/6] builtin-remote","startedAt":"2007-12-05T19:00:10Z","lastAt":"2007-12-05T22:38:41Z","messageCount":14,"participants":["Johannes Schindelin","Linus Torvalds","René Scharfe"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"62033","messageId":"Pine.LNX.4.64.0712051858270.27959@racer.site","threadId":"11150","inReplyTo":null,"subject":"[PATCH 0/6] builtin-remote","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-12-05T19:00:10Z","receivedAt":"2007-12-05T19:00:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nthis series introduces remote as a builtin, and fixes a long-standing bug \n(if you created a remote with --mirror, prune would not do the right \nthing).\n\nI know it is pretty late in the game for 1.5.4, but then, I do not expect \nthis to go into that version...\n\nCiao,\nDscho\n"},{"id":"62034","messageId":"Pine.LNX.4.64.0712051900370.27959@racer.site","threadId":"11150","inReplyTo":"Pine.LNX.4.64.0712051858270.27959@racer.site","subject":"(unknown)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-12-05T19:00:47Z","receivedAt":"2007-12-05T19:00:47Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"[PATCH 1/6] path-list: add functions to work with unsorted lists\n\nUp to now, path-lists were sorted at all times.  But sometimes it\nis much more convenient to build the list and sort it at the end,\nor sort it not at all.\n\nAdd path_list_append() and sort_path_list() to allow that.\n\nAlso, add the unsorted_path_list_has_path() function, to do a linear\nsearch.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\n\tI should have done this much earlier...\n\n path-list.c |   30 ++++++++++++++++++++++++++++++\n path-list.h |    8 +++++++-\n 2 files changed, 37 insertions(+), 1 deletions(-)\n\ndiff --git a/path-list.c b/path-list.c\nindex 3d83b7b..92e5cf2 100644\n--- a/path-list.c\n+++ b/path-list.c\n@@ -102,3 +102,33 @@ void print_path_list(const char *text, const struct path_list *p)\n \tfor (i = 0; i < p->nr; i++)\n \t\tprintf(\"%s:%p\\n\", p->items[i].path, p->items[i].util);\n }\n+\n+struct path_list_item *path_list_append(const char *path, struct path_list *list)\n+{\n+\tALLOC_GROW(list->items, list->nr + 1, list->alloc);\n+\tlist->items[list->nr].path =\n+\t\tlist->strdup_paths ? xstrdup(path) : (char *)path;\n+\treturn list->items + list->nr++;\n+}\n+\n+static int cmp_items(const void *a, const void *b)\n+{\n+\tconst struct path_list_item *one = a;\n+\tconst struct path_list_item *two = b;\n+\treturn strcmp(one->path, two->path);\n+}\n+\n+void sort_path_list(struct path_list *list)\n+{\n+\tqsort(list->items, list->nr, sizeof(*list->items), cmp_items);\n+}\n+\n+int unsorted_path_list_has_path(struct path_list *list, const char *path)\n+{\n+\tint i;\n+\tfor (i = 0; i < list->nr; i++)\n+\t\tif (!strcmp(path, list->items[i].path))\n+\t\t\treturn 1;\n+\treturn 0;\n+}\n+\ndiff --git a/path-list.h b/path-list.h\nindex 5931e2c..ca2cbba 100644\n--- a/path-list.h\n+++ b/path-list.h\n@@ -13,10 +13,16 @@ struct path_list\n };\n \n void print_path_list(const char *text, const struct path_list *p);\n+void path_list_clear(struct path_list *list, int free_util);\n \n+/* Use these functions only on sorted lists: */\n int path_list_has_path(const struct path_list *list, const char *path);\n-void path_list_clear(struct path_list *list, int free_util);\n struct path_list_item *path_list_insert(const char *path, struct path_list *list);\n struct path_list_item *path_list_lookup(const char *path, struct path_list *list);\n \n+/* Use these functions only on unsorted lists: */\n+struct path_list_item *path_list_append(const char *path, struct path_list *list);\n+void sort_path_list(struct path_list *list);\n+int unsorted_path_list_has_path(struct path_list *list, const char *path);\n+\n #endif /* PATH_LIST_H */\n-- \n1.5.3.7.2157.g9598e\n"},{"id":"62035","messageId":"Pine.LNX.4.64.0712051900530.27959@racer.site","threadId":"11150","inReplyTo":"Pine.LNX.4.64.0712051858270.27959@racer.site","subject":"[PATCH 2/6] parseopt: add flag to stop on first non option","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-12-05T19:01:01Z","receivedAt":"2007-12-05T19:01:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\n\tThis allows \"git remote --option command --command-option\".\n\n parse-options.c |    2 ++\n parse-options.h |    1 +\n 2 files changed, 3 insertions(+), 0 deletions(-)\n\ndiff --git a/parse-options.c b/parse-options.c\nindex e12b428..6df1230 100644\n--- a/parse-options.c\n+++ b/parse-options.c\n@@ -229,6 +229,8 @@ int parse_options(int argc, const char **argv, const struct option *options,\n \t\tconst char *arg = args.argv[0];\n \n \t\tif (*arg != '-' || !arg[1]) {\n+\t\t\tif (flags & PARSE_OPT_STOP_AT_NON_OPTION)\n+\t\t\t\tbreak;\n \t\t\targv[j++] = args.argv[0];\n \t\t\tcontinue;\n \t\t}\ndiff --git a/parse-options.h b/parse-options.h\nindex 102ac31..0d40cd2 100644\n--- a/parse-options.h\n+++ b/parse-options.h\n@@ -18,6 +18,7 @@ enum parse_opt_type {\n \n enum parse_opt_flags {\n \tPARSE_OPT_KEEP_DASHDASH = 1,\n+\tPARSE_OPT_STOP_AT_NON_OPTION = 2,\n };\n \n enum parse_opt_option_flags {\n-- \n1.5.3.7.2157.g9598e\n"},{"id":"62036","messageId":"Pine.LNX.4.64.0712051901290.27959@racer.site","threadId":"11150","inReplyTo":"Pine.LNX.4.64.0712051900370.27959@racer.site","subject":"Re: your mail","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-12-05T19:01:42Z","receivedAt":"2007-12-05T19:01:42Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 5 Dec 2007, Johannes Schindelin wrote:\n\n> [PATCH 1/6] path-list: add functions to work with unsorted lists\n\nOoops.\n\nSorry,\nDscho\n"},{"id":"62038","messageId":"Pine.LNX.4.64.0712051901550.27959@racer.site","threadId":"11150","inReplyTo":"Pine.LNX.4.64.0712051858270.27959@racer.site","subject":"[PATCH 3/6] Test \"git remote show\" and \"git remote prune\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-12-05T19:02:02Z","receivedAt":"2007-12-05T19:02:02Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nWhile at it, also fix a few instances where a cd was done outside of a\nsubshell.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t5505-remote.sh |   34 ++++++++++++++++++++++++++++++++++\n 1 files changed, 34 insertions(+), 0 deletions(-)\n\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex 636aec2..c7d7242 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -97,4 +97,38 @@ test_expect_success 'remove remote' '\n )\n '\n \n+cat > test/expect << EOF\n+* remote origin\n+  URL: $(pwd)/one/.git\n+  Remote branch(es) merged with 'git pull' while on branch master\n+    master\n+  New remote branches (next fetch will store in remotes/origin)\n+    master\n+  Tracked remote branches\n+    side master\n+EOF\n+\n+test_expect_success 'show' '\n+\t(cd test &&\n+\t git config --add remote.origin.fetch \\\n+\t\trefs/heads/master:refs/heads/upstream &&\n+\t git fetch &&\n+\t git branch -d -r origin/master &&\n+\t (cd ../one &&\n+\t  echo 1 > file &&\n+\t  git commit -m update file) &&\n+\t git remote show origin > output &&\n+\t git diff expect output)\n+'\n+\n+test_expect_success 'prune' '\n+\t(cd one &&\n+\t git branch -m side side2) &&\n+\t(cd test &&\n+\t git fetch origin &&\n+\t git remote prune origin &&\n+\t git rev-parse refs/remotes/origin/side2 &&\n+\t ! git rev-parse refs/remotes/origin/side)\n+'\n+\n test_done\n-- \n1.5.3.7.2157.g9598e\n"},{"id":"62037","messageId":"Pine.LNX.4.64.0712051902080.27959@racer.site","threadId":"11150","inReplyTo":"Pine.LNX.4.64.0712051858270.27959@racer.site","subject":"[PATCH 4/6] Make git-remote a builtin","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-12-05T19:02:15Z","receivedAt":"2007-12-05T19:02:15Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Makefile                                           |    3 +-\n builtin-remote.c                                   |  517 ++++++++++++++++++++\n builtin.h                                          |    1 +\n .../examples/git-remote.perl                       |    0 \n git.c                                              |    1 +\n remote.c                                           |    3 +-\n remote.h                                           |    1 +\n t/t5505-remote.sh                                  |    4 +-\n 8 files changed, 526 insertions(+), 4 deletions(-)\n create mode 100644 builtin-remote.c\n rename git-remote.perl => contrib/examples/git-remote.perl (100%)\n\ndiff --git a/Makefile b/Makefile\nindex 233bb5f..e840ca3 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -228,7 +228,7 @@ SCRIPT_SH = \\\n SCRIPT_PERL = \\\n \tgit-add--interactive.perl \\\n \tgit-archimport.perl git-cvsimport.perl git-relink.perl \\\n-\tgit-cvsserver.perl git-remote.perl git-cvsexportcommit.perl \\\n+\tgit-cvsserver.perl git-cvsexportcommit.perl \\\n \tgit-send-email.perl git-svn.perl\n \n SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \\\n@@ -362,6 +362,7 @@ BUILTIN_OBJS = \\\n \tbuiltin-push.o \\\n \tbuiltin-read-tree.o \\\n \tbuiltin-reflog.o \\\n+\tbuiltin-remote.o \\\n \tbuiltin-send-pack.o \\\n \tbuiltin-config.o \\\n \tbuiltin-rerere.o \\\ndiff --git a/builtin-remote.c b/builtin-remote.c\nnew file mode 100644\nindex 0000000..41ac4a1\n--- /dev/null\n+++ b/builtin-remote.c\n@@ -0,0 +1,517 @@\n+#include \"cache.h\"\n+#include \"parse-options.h\"\n+#include \"transport.h\"\n+#include \"remote.h\"\n+#include \"path-list.h\"\n+#include \"strbuf.h\"\n+#include \"run-command.h\"\n+#include \"refs.h\"\n+\n+static const char * const builtin_remote_usage[] = {\n+\t\"git remote\",\n+        \"git remote add <name> <url>\",\n+        \"git remote rm <name>\",\n+        \"git remote show <name>\",\n+        \"git remote prune <name>\",\n+        \"git remote update [group]\",\n+\tNULL\n+};\n+\n+static int verbose;\n+\n+static inline int postfixcmp(const char *string, const char *postfix)\n+{\n+\tint len1 = strlen(string), len2 = strlen(postfix);\n+\tif (len1 < len2)\n+\t\treturn 1;\n+\treturn strcmp(string + len1 - len2, postfix);\n+}\n+\n+static inline const char *skip_prefix(const char *name, const char *prefix)\n+{\n+\treturn !name ? \"\" :\n+\t\tprefixcmp(name, prefix) ?  name : name + strlen(prefix);\n+}\n+\n+static int opt_parse_track(const struct option *opt, const char *arg, int not)\n+{\n+\tstruct path_list *list = opt->value;\n+\tif (not)\n+\t\tpath_list_clear(list, 0);\n+\telse\n+\t\tpath_list_append(arg, list);\n+\treturn 0;\n+}\n+\n+static int fetch_remote(const char *name)\n+{\n+\tconst char *argv[] = { \"fetch\", name, NULL };\n+\tif (run_command_v_opt(argv, RUN_GIT_CMD))\n+\t\treturn error (\"Could not fetch %s\", name);\n+\treturn 0;\n+}\n+\n+static int add(int argc, const char **argv)\n+{\n+\tint fetch = 0, mirror = 0;\n+\tstruct path_list track = { NULL, 0, 0 };\n+\tconst char *master = NULL;\n+\tstruct remote *remote;\n+\tstruct strbuf buf, buf2;\n+\tconst char *name, *url;\n+\tint i;\n+\n+\tstruct option options[] = {\n+\t\tOPT_GROUP(\"add specific options\"),\n+\t\tOPT_BOOLEAN('f', \"fetch\", &fetch, \"fetch the remote branches\"),\n+\t\tOPT_CALLBACK('t', \"track\", &track, \"branch\",\n+\t\t\t\"branch(es) to track\", opt_parse_track),\n+\t\tOPT_STRING('m', \"master\", &master, \"branch\", \"master branch\"),\n+\t\tOPT_BOOLEAN(0, \"mirror\", &mirror, \"no separate remotes\"),\n+\t\tOPT_END()\n+\t};\n+\n+\targc = parse_options(argc, argv, options, builtin_remote_usage, 0);\n+\n+\tif (argc < 2)\n+\t\tusage_with_options(builtin_remote_usage, options);\n+\n+\tname = argv[0];\n+\turl = argv[1];\n+\n+\tremote = remote_get(name);\n+\tif (remote && (remote->url_nr > 1 || strcmp(name, remote->url[0]) ||\n+\t\t\tremote->fetch_refspec_nr))\n+\t\tdie (\"remote %s already exists.\", name);\n+\n+\tstrbuf_init(&buf, 0);\n+\tstrbuf_init(&buf2, 0);\n+\n+\tstrbuf_addf(&buf, \"remote.%s.url\", name);\n+\tif (git_config_set(buf.buf, url))\n+\t\treturn 1;\n+\n+\tif (track.nr == 0)\n+\t\tpath_list_append(\"*\", &track);\n+\tfor (i = 0; i < track.nr; i++) {\n+\t\tstruct path_list_item *item = track.items + i;\n+\n+\t\tstrbuf_reset(&buf);\n+\t\tstrbuf_addf(&buf, \"remote.%s.fetch\", name);\n+\n+\t\tstrbuf_reset(&buf2);\n+\t\tif (mirror)\n+\t\t\tstrbuf_addf(&buf2, \"refs/%s:refs/%s\",\n+\t\t\t\t\titem->path, item->path);\n+\t\telse\n+\t\t\tstrbuf_addf(&buf2, \"refs/heads/%s:refs/remotes/%s/%s\",\n+\t\t\t\t\titem->path, name, item->path);\n+\t\tif (git_config_set_multivar(buf.buf, buf2.buf, \"^$\", 0))\n+\t\t\treturn 1;\n+\t}\n+\n+\tif (fetch && fetch_remote(name))\n+\t\treturn 1;\n+\n+\tif (master) {\n+\t\tstrbuf_reset(&buf);\n+\t\tstrbuf_addf(&buf, \"refs/remotes/%s/HEAD\", name);\n+\n+\t\tstrbuf_reset(&buf2);\n+\t\tstrbuf_addf(&buf2, \"refs/remotes/%s/%s\", name, master);\n+\n+\t\tif (create_symref(buf.buf, buf2.buf, \"remote add\"))\n+\t\t\treturn error (\"Could not setup master '%s'\", master);\n+\t}\n+\n+\tstrbuf_release(&buf);\n+\tstrbuf_release(&buf2);\n+\tpath_list_clear(&track, 0);\n+\n+\treturn 0;\n+}\n+\n+struct branch_info {\n+\tchar *remote;\n+\tstruct path_list merge;\n+};\n+\n+static struct path_list branch_list;\n+\n+static int config_read_branches(const char *key, const char *value)\n+{\n+\tif (!prefixcmp(key, \"branch.\")) {\n+\t\tchar *name;\n+\t\tstruct path_list_item *item;\n+\t\tstruct branch_info *info;\n+\t\tenum { REMOTE, MERGE } type;\n+\n+\t\tkey += 7;\n+\t\tif (!postfixcmp(key, \".remote\")) {\n+\t\t\tname = xstrndup(key, strlen(key) - 7);\n+\t\t\ttype = REMOTE;\n+\t\t} else if (!postfixcmp(key, \".merge\")) {\n+\t\t\tname = xstrndup(key, strlen(key) - 6);\n+\t\t\ttype = MERGE;\n+\t\t} else\n+\t\t\treturn 0;\n+\n+\t\titem = path_list_insert(name, &branch_list);\n+\n+\t\tif (!item->util)\n+\t\t\titem->util = xcalloc(sizeof(struct branch_info), 1);\n+\t\tinfo = item->util;\n+\t\tif (type == REMOTE) {\n+\t\t\tif (info->remote)\n+\t\t\t\twarning (\"more than one branch.%s\", key);\n+\t\t\tinfo->remote = xstrdup(value);\n+\t\t} else {\n+\t\t\tchar *space = strchr(value, ' ');\n+\t\t\tvalue = skip_prefix(value, \"refs/heads/\");\n+\t\t\twhile (space) {\n+\t\t\t\tchar *merge;\n+\t\t\t\tmerge = xstrndup(value, space - value);\n+\t\t\t\tpath_list_append(merge, &info->merge);\n+\t\t\t\tvalue = skip_prefix(space + 1, \"refs/heads/\");\n+\t\t\t\tspace = strchr(value, ' ');\n+\t\t\t}\n+\t\t\tpath_list_append(xstrdup(value), &info->merge);\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+static void read_branches()\n+{\n+\tif (branch_list.nr)\n+\t\treturn;\n+\tgit_config(config_read_branches);\n+\tsort_path_list(&branch_list);\n+}\n+\n+struct ref_states {\n+\tstruct remote *remote;\n+\tstruct strbuf remote_prefix;\n+\tstruct path_list new, stale, tracked;\n+};\n+\n+static int handle_one_branch(const char *refname,\n+\tconst unsigned char *sha1, int flags, void *cb_data)\n+{\n+\tstruct ref_states *states = cb_data;\n+\tstruct refspec refspec;\n+\n+\tmemset(&refspec, 0, sizeof(refspec));\n+\trefspec.dst = (char *)refname;\n+\tif (!remote_find_tracking(states->remote, &refspec)) {\n+\t\tstruct path_list_item *item;\n+\t\tconst char *name = skip_prefix(refspec.src, \"refs/heads/\");\n+\t\tif (unsorted_path_list_has_path(&states->tracked, name) ||\n+\t\t\t\tunsorted_path_list_has_path(&states->new,\n+\t\t\t\t\tname))\n+\t\t\treturn 0;\n+\t\titem = path_list_append(name, &states->stale);\n+\t\titem->util = xstrdup(refname);\n+\t}\n+\treturn 0;\n+}\n+\n+static int get_ref_states(const struct ref *ref, struct ref_states *states)\n+{\n+\tstruct ref *fetch_map = NULL, **tail = &fetch_map;\n+\tint i;\n+\n+\tfor (i = 0; i < states->remote->fetch_refspec_nr; i++)\n+\t\tif (get_fetch_map(ref, states->remote->fetch +i, &tail, 1))\n+\t\t\tdie (\"Could not get fetch map for refspec %s\",\n+\t\t\t\tstates->remote->fetch_refspec[i]);\n+\n+\tstates->new.strdup_paths = states->tracked.strdup_paths = 1;\n+\tfor (ref = fetch_map; ref; ref = ref->next) {\n+\t\tstruct path_list *target = &states->tracked;\n+\t\tunsigned char sha1[20];\n+\t\tvoid *util = NULL;\n+\n+\t\tif (!ref->peer_ref || read_ref(ref->peer_ref->name, sha1))\n+\t\t\ttarget = &states->new;\n+\t\telse {\n+\t\t\ttarget = &states->tracked;\n+\t\t\tif (hashcmp(sha1, ref->new_sha1))\n+\t\t\t\tutil = &states;\n+\t\t}\n+\t\tpath_list_append(skip_prefix(ref->name, \"refs/heads/\"),\n+\t\t\t\ttarget)->util = util;\n+\t}\n+\tfree_refs(fetch_map);\n+\n+\tstrbuf_addf(&states->remote_prefix,\n+\t\t\"refs/remotes/%s/\", states->remote->name);\n+\tfor_each_ref(handle_one_branch, states);\n+\tsort_path_list(&states->stale);\n+\n+\treturn 0;\n+}\n+\n+static int remove_tracking_branch(const char *refname,\n+\tconst unsigned char *sha1, int flags, void *cb_data)\n+{\n+\tconst char *remote_prefix = cb_data;\n+\n+\tif (!prefixcmp(refname, remote_prefix) &&\n+\t\t\tdelete_ref(refname, sha1))\n+\t\treturn error(\"Could not remove branch %s\", refname);\n+\treturn 0;\n+}\n+\n+static int rm(int argc, const char **argv)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\tstruct remote *remote;\n+\tstruct strbuf buf;\n+\tint i;\n+\n+\tif (argc != 2)\n+\t\tusage_with_options(builtin_remote_usage, options);\n+\n+\tremote = remote_get(argv[1]);\n+\tif (!remote)\n+\t\tdie (\"No such remote: %s\", argv[1]);\n+\n+\tstrbuf_init(&buf, 0);\n+\tstrbuf_addf(&buf, \"remote.%s\", remote->name);\n+\tif (git_config_rename_section(buf.buf, NULL) < 1)\n+\t\treturn error(\"Could not remove config section '%s'\", buf.buf);\n+\n+\tread_branches();\n+\tfor (i = 0; i < branch_list.nr; i++) {\n+\t\tstruct path_list_item *item = branch_list.items +i;\n+\t\tstruct branch_info *info = item->util;\n+\t\tif (info->remote && !strcmp(info->remote, remote->name)) {\n+\t\t\tconst char *keys[] = { \"remote\", \"merge\", NULL }, **k;\n+\t\t\tfor (k = keys; *k; k++) {\n+\t\t\t\tstrbuf_reset(&buf);\n+\t\t\t\tstrbuf_addf(&buf, \"branch.%s.%s\",\n+\t\t\t\t\t\titem->path, *k);\n+\t\t\t\tif (git_config_set(buf.buf, NULL)) {\n+\t\t\t\t\tstrbuf_release(&buf);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t/*\n+\t * NEEDSTHOUGHT: this could check something like\n+\t * !remote_find_tracking(remote, &refspec) to know if the\n+\t * branch was really tracked.  But then we'll have to make\n+\t * sure that no other remote writes into that branch.\n+\t * Probably not worth it.\n+\t */\n+\tstrbuf_reset(&buf);\n+\tstrbuf_addf(&buf, \"refs/remotes/%s/\", remote->name);\n+\ti = for_each_ref(remove_tracking_branch, buf.buf);\n+\tstrbuf_release(&buf);\n+\n+\treturn i;\n+}\n+\n+static void show_list(const char *title, struct path_list *list)\n+{\n+\tint i;\n+\n+\tif (!list->nr)\n+\t\treturn;\n+\n+\tprintf(title, list->nr > 1 ? \"es\" : \"\");\n+\tprintf(\"\\n    \");\n+\tfor (i = 0; i < list->nr; i++)\n+\t\tprintf(\"%s%s\", i ? \" \" : \"\", list->items[i].path);\n+\tprintf(\"\\n\");\n+}\n+\n+static int show_or_prune(int argc, const char **argv, int prune)\n+{\n+\tint dry_run = 0, result = 0;\n+\tstruct option options[] = {\n+\t\tOPT_GROUP(\"show specific options\"),\n+\t\tOPT__DRY_RUN(&dry_run),\n+\t\tOPT_END()\n+\t};\n+\tstruct ref_states states;\n+\n+\targc = parse_options(argc, argv, options, builtin_remote_usage, 0);\n+\n+\tif (argc < 1)\n+\t\tusage_with_options(builtin_remote_usage, options);\n+\n+\tmemset(&states, 0, sizeof(states));\n+\tfor (; argc; argc--, argv++) {\n+\t\tstruct transport *transport;\n+\t\tconst struct ref *ref;\n+\t\tstruct strbuf buf;\n+\t\tint i, got_states;\n+\n+\t\tstates.remote = remote_get(*argv);\n+\t\tif (!states.remote)\n+\t\t\treturn error(\"No such remote: %s\", *argv);\n+\t\ttransport = transport_get(NULL, states.remote->url[0]);\n+\t\tref = transport_get_remote_refs(transport);\n+\n+\t\tread_branches();\n+\t\tgot_states = get_ref_states(ref, &states);\n+\t\tif (got_states)\n+\t\t\tresult = error(\"Error getting local info for '%s'\",\n+\t\t\t\t\tstates.remote->name);\n+\n+\t\tif (prune) {\n+\t\t\tstruct strbuf buf;\n+\n+\t\t\tstrbuf_init(&buf, 0);\n+\t\t\tfor (i = 0; i < states.stale.nr; i++) {\n+\t\t\t\tstrbuf_reset(&buf);\n+\t\t\t\tstrbuf_addf(&buf, \"refs/remotes/%s/%s\", *argv,\n+\t\t\t\t\t\tstates.stale.items[i].path);\n+\t\t\t\tresult |= delete_ref(buf.buf, NULL);\n+\t\t\t}\n+\n+\t\t\tstrbuf_release(&buf);\n+\t\t\tgoto cleanup_states;\n+\t\t}\n+\n+\t\tprintf(\"* remote %s\\n  URL: %s\\n\", *argv,\n+\t\t\tstates.remote->url[0] ?\n+\t\t\t\tstates.remote->url[0] : \"(no URL)\");\n+\n+\t\tfor (i = 0; i < branch_list.nr; i++) {\n+\t\t\tstruct path_list_item *branch = branch_list.items + i;\n+\t\t\tstruct branch_info *info = branch->util;\n+\t\t\tint j;\n+\n+\t\t\tif (!info->merge.nr || strcmp(*argv, info->remote))\n+\t\t\t\tcontinue;\n+\t\t\tprintf(\"  Remote branch%s merged with 'git pull' \"\n+\t\t\t\t\"while on branch %s\\n   \",\n+\t\t\t\tinfo->merge.nr > 1 ? \"es\" : \"\",\n+\t\t\t\tbranch->path);\n+\t\t\tfor (j = 0; j < info->merge.nr; j++)\n+\t\t\t\tprintf(\" %s\", info->merge.items[j].path);\n+\t\t\tprintf(\"\\n\");\n+\t\t}\n+\n+\t\tif (got_states)\n+\t\t\tcontinue;\n+\t\tstrbuf_init(&buf, 0);\n+\t\tstrbuf_addf(&buf, \"  New remote branch%%s (next fetch will \"\n+\t\t\t\"store in remotes/%s)\", states.remote->name);\n+\t\tshow_list(buf.buf, &states.new);\n+\t\tstrbuf_release(&buf);\n+\t\tshow_list(\"  Stale tracking branch%s (use 'git remote prune')\",\n+\t\t\t\t&states.stale);\n+\t\tshow_list(\"  Tracked remote branch%s\",\n+\t\t\t\t&states.tracked);\n+\n+\t\tif (states.remote->push_refspec_nr) {\n+\t\t\tprintf(\"  Local branch%s pushed with 'git push'\\n   \",\n+\t\t\t\tstates.remote->push_refspec_nr > 1 ?\n+\t\t\t\t\t\"es\" : \"\");\n+\t\t\tfor (i = 0; i < states.remote->push_refspec_nr; i++) {\n+\t\t\t\tstruct refspec *spec = states.remote->push + i;\n+\t\t\t\tprintf(\" %s%s%s%s\", spec->force ? \"+\" : \"\",\n+\t\t\t\t\tskip_prefix(spec->src, \"refs/heads/\"),\n+\t\t\t\t\tspec->dst ? \":\" : \"\",\n+\t\t\t\t\tskip_prefix(spec->dst, \"refs/heads/\"));\n+\t\t\t}\n+\t\t}\n+cleanup_states:\n+\t\t/* NEEDSWORK: free remote */\n+\t\tpath_list_clear(&states.new, 0);\n+\t\tpath_list_clear(&states.stale, 0);\n+\t\tpath_list_clear(&states.tracked, 0);\n+\t}\n+\n+\treturn result;\n+}\n+\n+static int update_one(struct remote *remote, void *priv)\n+{\n+\tif (!remote->skip_default_update)\n+\t\treturn fetch_remote(remote->name);\n+\treturn 0;\n+}\n+\n+static int update(int argc, const char **argv)\n+{\n+\tint i;\n+\n+\tif (argc < 2)\n+\t\treturn for_each_remote(update_one, NULL);\n+\n+\tfor (i = 1; i < argc; i++)\n+\t\tif (fetch_remote(argv[i]))\n+\t\t\treturn 1;\n+\treturn 0;\n+}\n+\n+static int get_one_entry(struct remote *remote, void *priv)\n+{\n+\tstruct path_list *list = priv;\n+\n+\tpath_list_append(remote->name, list)->util = (void *)remote->url[0];\n+\tif (remote->url[0] && remote->url[1])\n+\t\twarning (\"Remote %s has more than one URL\", remote->name);\n+\n+\treturn 0;\n+}\n+\n+static int show_all()\n+{\n+\tstruct path_list list = { NULL, 0, 0 };\n+\tint result = for_each_remote(get_one_entry, &list);\n+\n+\tif (!result) {\n+\t\tint i;\n+\n+\t\tsort_path_list(&list);\n+\t\tfor (i = 0; i < list.nr; i++) {\n+\t\t\tstruct path_list_item *item = list.items + i;\n+\t\t\tprintf(\"%s%s%s\\n\", item->path,\n+\t\t\t\tverbose ? \"\\t\" : \"\",\n+\t\t\t\tverbose && item->util ?\n+\t\t\t\t\t(const char *)item->util : \"\");\n+\t\t}\n+\t}\n+\treturn result;\n+}\n+\n+int cmd_remote(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct option options[] = {\n+\t\tOPT__VERBOSE(&verbose),\n+\t\tOPT_END()\n+\t};\n+\tint result;\n+\n+\targc = parse_options(argc, argv, options, builtin_remote_usage,\n+\t\tPARSE_OPT_STOP_AT_NON_OPTION);\n+\n+\tif (argc < 1)\n+\t\tresult = show_all();\n+\telse if (!strcmp(argv[0], \"add\"))\n+\t\tresult = add(argc, argv);\n+\telse if (!strcmp(argv[0], \"rm\"))\n+\t\tresult = rm(argc, argv);\n+\telse if (!strcmp(argv[0], \"show\"))\n+\t\tresult = show_or_prune(argc, argv, 0);\n+\telse if (!strcmp(argv[0], \"prune\"))\n+\t\tresult = show_or_prune(argc, argv, 1);\n+\telse if (!strcmp(argv[0], \"update\"))\n+\t\tresult = update(argc, argv);\n+\telse {\n+\t\terror (\"Unknown subcommand: %s\", argv[0]);\n+\t\tusage_with_options(builtin_remote_usage, options);\n+\t}\n+\n+\treturn result ? 1 : 0;\n+}\ndiff --git a/builtin.h b/builtin.h\nindex cb675c4..20b6e75 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -66,6 +66,7 @@ extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);\n extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n extern int cmd_reflog(int argc, const char **argv, const char *prefix);\n+extern int cmd_remote(int argc, const char **argv, const char *prefix);\n extern int cmd_config(int argc, const char **argv, const char *prefix);\n extern int cmd_rerere(int argc, const char **argv, const char *prefix);\n extern int cmd_reset(int argc, const char **argv, const char *prefix);\ndiff --git a/git-remote.perl b/contrib/examples/git-remote.perl\nsimilarity index 100%\nrename from git-remote.perl\nrename to contrib/examples/git-remote.perl\ndiff --git a/git.c b/git.c\nindex c8b7e74..80e9082 100644\n--- a/git.c\n+++ b/git.c\n@@ -349,6 +349,7 @@ static void handle_internal_command(int argc, const char **argv)\n \t\t{ \"push\", cmd_push, RUN_SETUP },\n \t\t{ \"read-tree\", cmd_read_tree, RUN_SETUP },\n \t\t{ \"reflog\", cmd_reflog, RUN_SETUP },\n+\t\t{ \"remote\", cmd_remote, RUN_SETUP },\n \t\t{ \"repo-config\", cmd_config },\n \t\t{ \"rerere\", cmd_rerere, RUN_SETUP },\n \t\t{ \"reset\", cmd_reset, RUN_SETUP },\ndiff --git a/remote.c b/remote.c\nindex 3fb0f99..ae7abe4 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -280,7 +280,8 @@ static int handle_config(const char *key, const char *value)\n \t\t\tremote->fetch_tags = -1;\n \t} else if (!strcmp(subkey, \".proxy\")) {\n \t\tremote->http_proxy = xstrdup(value);\n-\t}\n+\t} else if (!strcmp(subkey, \".skipdefaultupdate\"))\n+\t\tremote->skip_default_update = 1;\n \treturn 0;\n }\n \ndiff --git a/remote.h b/remote.h\nindex 86e036d..bb26d3c 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -22,6 +22,7 @@ struct remote {\n \t * 2 to always fetch tags\n \t */\n \tint fetch_tags;\n+\tint skip_default_update;\n \n \tconst char *receivepack;\n \tconst char *uploadpack;\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex c7d7242..d343a96 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -100,9 +100,9 @@ test_expect_success 'remove remote' '\n cat > test/expect << EOF\n * remote origin\n   URL: $(pwd)/one/.git\n-  Remote branch(es) merged with 'git pull' while on branch master\n+  Remote branch merged with 'git pull' while on branch master\n     master\n-  New remote branches (next fetch will store in remotes/origin)\n+  New remote branch (next fetch will store in remotes/origin)\n     master\n   Tracked remote branches\n     side master\n-- \n1.5.3.7.2157.g9598e\n"},{"id":"62039","messageId":"Pine.LNX.4.64.0712051902300.27959@racer.site","threadId":"11150","inReplyTo":"Pine.LNX.4.64.0712051858270.27959@racer.site","subject":"[PATCH 5/6] builtin-remote: prune remotes correctly that were added with --mirror","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-12-05T19:02:41Z","receivedAt":"2007-12-05T19:02:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nThis adds special handling for mirror remotes.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\n\tThis fixes a real bug in git-remote, which I tried to fix in the\n\tperl script, failing.\n\n builtin-remote.c  |   16 +++++++++++++---\n t/t5505-remote.sh |   16 ++++++++++++++++\n 2 files changed, 29 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex 41ac4a1..142eb97 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -367,12 +367,22 @@ static int show_or_prune(int argc, const char **argv, int prune)\n \n \t\tif (prune) {\n \t\t\tstruct strbuf buf;\n+\t\t\tint prefix_len;\n \n \t\t\tstrbuf_init(&buf, 0);\n+\t\t\tif (states.remote->fetch_refspec_nr == 1 &&\n+\t\t\t\t\tstates.remote->fetch->pattern &&\n+\t\t\t\t\t!strcmp(states.remote->fetch->src,\n+\t\t\t\t\t\tstates.remote->fetch->dst))\n+\t\t\t\t/* handle --mirror remote */\n+\t\t\t\tstrbuf_addstr(&buf, \"refs/heads/\");\n+\t\t\telse\n+\t\t\t\tstrbuf_addf(&buf, \"refs/remotes/%s/\", *argv);\n+\t\t\tprefix_len = buf.len;\n+\n \t\t\tfor (i = 0; i < states.stale.nr; i++) {\n-\t\t\t\tstrbuf_reset(&buf);\n-\t\t\t\tstrbuf_addf(&buf, \"refs/remotes/%s/%s\", *argv,\n-\t\t\t\t\t\tstates.stale.items[i].path);\n+\t\t\t\tstrbuf_setlen(&buf, prefix_len);\n+\t\t\t\tstrbuf_addstr(&buf, states.stale.items[i].path);\n \t\t\t\tresult |= delete_ref(buf.buf, NULL);\n \t\t\t}\n \ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex d343a96..2376e0a 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -131,4 +131,20 @@ test_expect_success 'prune' '\n \t ! git rev-parse refs/remotes/origin/side)\n '\n \n+test_expect_success 'add --mirror && prune' '\n+\t(mkdir mirror &&\n+\t cd mirror &&\n+\t git init &&\n+\t git remote add --mirror -f origin ../one) &&\n+\t(cd one &&\n+\t git branch -m side2 side) &&\n+\t(cd mirror &&\n+\t git rev-parse --verify refs/heads/side2 &&\n+\t ! git rev-parse --verify refs/heads/side &&\n+\t git fetch origin &&\n+\t git remote prune origin &&\n+\t ! git rev-parse --verify refs/heads/side2 &&\n+\t git rev-parse --verify refs/heads/side)\n+'\n+\n test_done\n-- \n1.5.3.7.2157.g9598e\n"},{"id":"62040","messageId":"Pine.LNX.4.64.0712051902510.27959@racer.site","threadId":"11150","inReplyTo":"Pine.LNX.4.64.0712051858270.27959@racer.site","subject":"[PATCH 6/6] DWIM \"git add remote ...\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-12-05T19:03:00Z","receivedAt":"2007-12-05T19:03:00Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nIt is wrong to divert to \"git remote add\" when you typed the\n(more English) \"git add remote\".  But is it also pretty convenient.\n\nSo implement it, but do not document it ;-)\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin-add.c     |    7 +++++++\n t/t5505-remote.sh |    6 ++++++\n 2 files changed, 13 insertions(+), 0 deletions(-)\n\ndiff --git a/builtin-add.c b/builtin-add.c\nindex 5c29cc2..b5b4c2f 100644\n--- a/builtin-add.c\n+++ b/builtin-add.c\n@@ -196,6 +196,13 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \tconst char **pathspec;\n \tstruct dir_struct dir;\n \n+\tif (argc > 1 && !strcmp(argv[1], \"remote\") &&\n+\t\t\taccess(\"remote\", F_OK)) {\n+\t\targv[1] = argv[0];\n+\t\targv[0] = \"remote\";\n+\t\treturn cmd_remote(argc, argv, prefix);\n+\t}\n+\n \targc = parse_options(argc, argv, builtin_add_options,\n \t\t\t  builtin_add_usage, 0);\n \tif (patch_interactive)\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex 2376e0a..83ed70c 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -147,4 +147,10 @@ test_expect_success 'add --mirror && prune' '\n \t git rev-parse --verify refs/heads/side)\n '\n \n+test_expect_success 'add remote' '\n+\t(cd test &&\n+\t git add remote -f another-one ../one &&\n+\t git diff master remotes/another-one/master)\n+'\n+\n test_done\n-- \n1.5.3.7.2157.g9598e\n"},{"id":"62041","messageId":"Pine.LNX.4.64.0712051905000.27959@racer.site","threadId":"11150","inReplyTo":"Pine.LNX.4.64.0712051900370.27959@racer.site","subject":"[PATCH 1/6] path-list: add functions to work with unsorted lists","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-12-05T19:05:09Z","receivedAt":"2007-12-05T19:05:09Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nUp to now, path-lists were sorted at all times.  But sometimes it\nis much more convenient to build the list and sort it at the end,\nor sort it not at all.\n\nAdd path_list_append() and sort_path_list() to allow that.\n\nAlso, add the unsorted_path_list_has_path() function, to do a linear\nsearch.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\n\tI should have done that long ago.\n\n path-list.c |   30 ++++++++++++++++++++++++++++++\n path-list.h |    8 +++++++-\n 2 files changed, 37 insertions(+), 1 deletions(-)\n\ndiff --git a/path-list.c b/path-list.c\nindex 3d83b7b..92e5cf2 100644\n--- a/path-list.c\n+++ b/path-list.c\n@@ -102,3 +102,33 @@ void print_path_list(const char *text, const struct path_list *p)\n \tfor (i = 0; i < p->nr; i++)\n \t\tprintf(\"%s:%p\\n\", p->items[i].path, p->items[i].util);\n }\n+\n+struct path_list_item *path_list_append(const char *path, struct path_list *list)\n+{\n+\tALLOC_GROW(list->items, list->nr + 1, list->alloc);\n+\tlist->items[list->nr].path =\n+\t\tlist->strdup_paths ? xstrdup(path) : (char *)path;\n+\treturn list->items + list->nr++;\n+}\n+\n+static int cmp_items(const void *a, const void *b)\n+{\n+\tconst struct path_list_item *one = a;\n+\tconst struct path_list_item *two = b;\n+\treturn strcmp(one->path, two->path);\n+}\n+\n+void sort_path_list(struct path_list *list)\n+{\n+\tqsort(list->items, list->nr, sizeof(*list->items), cmp_items);\n+}\n+\n+int unsorted_path_list_has_path(struct path_list *list, const char *path)\n+{\n+\tint i;\n+\tfor (i = 0; i < list->nr; i++)\n+\t\tif (!strcmp(path, list->items[i].path))\n+\t\t\treturn 1;\n+\treturn 0;\n+}\n+\ndiff --git a/path-list.h b/path-list.h\nindex 5931e2c..ca2cbba 100644\n--- a/path-list.h\n+++ b/path-list.h\n@@ -13,10 +13,16 @@ struct path_list\n };\n \n void print_path_list(const char *text, const struct path_list *p);\n+void path_list_clear(struct path_list *list, int free_util);\n \n+/* Use these functions only on sorted lists: */\n int path_list_has_path(const struct path_list *list, const char *path);\n-void path_list_clear(struct path_list *list, int free_util);\n struct path_list_item *path_list_insert(const char *path, struct path_list *list);\n struct path_list_item *path_list_lookup(const char *path, struct path_list *list);\n \n+/* Use these functions only on unsorted lists: */\n+struct path_list_item *path_list_append(const char *path, struct path_list *list);\n+void sort_path_list(struct path_list *list);\n+int unsorted_path_list_has_path(struct path_list *list, const char *path);\n+\n #endif /* PATH_LIST_H */\n-- \n1.5.3.7.2157.g9598e\n"},{"id":"62046","messageId":"alpine.LFD.0.9999.0712051129280.13796@woody.linux-foundation.org","threadId":"11150","inReplyTo":"Pine.LNX.4.64.0712051902510.27959@racer.site","subject":"Re: [PATCH 6/6] DWIM \"git add remote ...\"","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2007-12-05T19:34:01Z","receivedAt":"2007-12-05T19:34:01Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 5 Dec 2007, Johannes Schindelin wrote:\n> \n> It is wrong to divert to \"git remote add\" when you typed the\n> (more English) \"git add remote\".  But is it also pretty convenient.\n\nPlease don't do cute things like this. Suddenly \"git add remote\" has two \ndifferent meanings depending on whether you have a file called \"remote\" or \nnot. That is *not* ok.\n\nNot to mention the fact that your patch is also a horrible piece of \nbug-infested shit, to put it less-than-politely. Namely, you now broke \n\"git add remote\" when \"remote\" is a symbolic link pointing to hyperspace.\n\nBut even if you fix that bug, it only goes to show just how misguided \nthings like these are. It's a *lot* more important to make sense and not \nhave surprising special cases, than to try to make git command lines act \nas if they were free-form English.\n\n\t\tLinus\n"},{"id":"62051","messageId":"Pine.LNX.4.64.0712051946350.27959@racer.site","threadId":"11150","inReplyTo":"alpine.LFD.0.9999.0712051129280.13796@woody.linux-foundation.org","subject":"Re: [PATCH 6/6] DWIM \"git add remote ...\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-12-05T19:47:44Z","receivedAt":"2007-12-05T19:47:44Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 5 Dec 2007, Linus Torvalds wrote:\n\n> On Wed, 5 Dec 2007, Johannes Schindelin wrote:\n> > \n> > It is wrong to divert to \"git remote add\" when you typed the (more \n> > English) \"git add remote\".  But is it also pretty convenient.\n> \n> Please don't do cute things like this. Suddenly \"git add remote\" has two \n> different meanings depending on whether you have a file called \"remote\" \n> or not. That is *not* ok.\n> \n> Not to mention the fact that your patch is also a horrible piece of \n> bug-infested shit, to put it less-than-politely. Namely, you now broke \n> \"git add remote\" when \"remote\" is a symbolic link pointing to \n> hyperspace.\n> \n> But even if you fix that bug, it only goes to show just how misguided \n> things like these are. It's a *lot* more important to make sense and not \n> have surprising special cases, than to try to make git command lines act \n> as if they were free-form English.\n\nHehe.  You're right, of course.  But I could not resist showing off that \npatch which I wrote after I mixed up the command line of \"remote add\" for \nthe 926th time.\n\nCiao,\nDscho\n"},{"id":"62060","messageId":"Pine.LNX.4.64.0712052139560.27959@racer.site","threadId":"11150","inReplyTo":"Pine.LNX.4.64.0712051902080.27959@racer.site","subject":"[PATCH 7/6] builtin-remote: guard remote->url accesses by remote->url_nr check","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-12-05T21:40:49Z","receivedAt":"2007-12-05T21:40:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nstruct remote's url member is not a NULL terminated list.  Instead, we\nhave to check url_nr before accessing it.\n\nNoticed by Johannes Sixt.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\n\tFor your viewing pleasure, this is not a resend, but an amend.  \n\tFeel free to squash with 4/6, or to bug me to do it.\n\n builtin-remote.c |   10 ++++++----\n 1 files changed, 6 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex 142eb97..ea323e2 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -356,7 +356,8 @@ static int show_or_prune(int argc, const char **argv, int prune)\n \t\tstates.remote = remote_get(*argv);\n \t\tif (!states.remote)\n \t\t\treturn error(\"No such remote: %s\", *argv);\n-\t\ttransport = transport_get(NULL, states.remote->url[0]);\n+\t\ttransport = transport_get(NULL, states.remote->url_nr > 0 ?\n+\t\t\tstates.remote->url[0] : NULL);\n \t\tref = transport_get_remote_refs(transport);\n \n \t\tread_branches();\n@@ -391,7 +392,7 @@ static int show_or_prune(int argc, const char **argv, int prune)\n \t\t}\n \n \t\tprintf(\"* remote %s\\n  URL: %s\\n\", *argv,\n-\t\t\tstates.remote->url[0] ?\n+\t\t\tstates.remote->url_nr > 0 ?\n \t\t\t\tstates.remote->url[0] : \"(no URL)\");\n \n \t\tfor (i = 0; i < branch_list.nr; i++) {\n@@ -468,8 +469,9 @@ static int get_one_entry(struct remote *remote, void *priv)\n {\n \tstruct path_list *list = priv;\n \n-\tpath_list_append(remote->name, list)->util = (void *)remote->url[0];\n-\tif (remote->url[0] && remote->url[1])\n+\tpath_list_append(remote->name, list)->util = remote->url_nr ?\n+\t\t(void *)remote->url[0] : NULL;\n+\tif (remote->url_nr > 1)\n \t\twarning (\"Remote %s has more than one URL\", remote->name);\n \n \treturn 0;\n-- \n1.5.3.7.2157.g9598e\n"},{"id":"62063","messageId":"47571F3E.1060903@lsrfire.ath.cx","threadId":"11150","inReplyTo":"Pine.LNX.4.64.0712051901550.27959@racer.site","subject":"Re: [PATCH 3/6] Test \"git remote show\" and \"git remote prune\"","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2007-12-05T21:59:26Z","receivedAt":"2007-12-05T21:59:26Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Johannes Schindelin schrieb:\n> While at it, also fix a few instances where a cd was done outside of a\n> subshell.\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  t/t5505-remote.sh |   34 ++++++++++++++++++++++++++++++++++\n>  1 files changed, 34 insertions(+), 0 deletions(-)\n\nIt seems to me the patch only adds tests, but doesn't fix existing ones.\n And looking at t5505-remote.sh, every call of cd is already done inside\nof a subshell, so there doesn't seem to be anything to fix either. :-?\n"},{"id":"62069","messageId":"Pine.LNX.4.64.0712052237110.27959@racer.site","threadId":"11150","inReplyTo":"47571F3E.1060903@lsrfire.ath.cx","subject":"Re: [PATCH 3/6] Test \"git remote show\" and \"git remote prune\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-12-05T22:38:41Z","receivedAt":"2007-12-05T22:38:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 5 Dec 2007, Ren? Scharfe wrote:\n\n> Johannes Schindelin schrieb:\n> > While at it, also fix a few instances where a cd was done outside of a \n> > subshell.\n> > \n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> >  t/t5505-remote.sh |   34 ++++++++++++++++++++++++++++++++++\n> >  1 files changed, 34 insertions(+), 0 deletions(-)\n> \n> It seems to me the patch only adds tests, but doesn't fix existing ones. \n> And looking at t5505-remote.sh, every call of cd is already done inside \n> of a subshell, so there doesn't seem to be anything to fix either. :-?\n\nRight.  This comment is from a long time ago, back when I had my own \n(incomplete) t5505-remote.sh.  It was funny to me that Junio chose exactly \nthe same name... but his implementation was different ;-)\n\nI agree that this comment is obsolete.\n\nThanks,\nDscho\n"}]}