{"thread":{"id":"18692","subject":"[PATCH] git remote update: New option --prune (-p)","startedAt":"2009-04-02T12:38:24Z","lastAt":"2009-04-05T09:47:39Z","messageCount":15,"participants":["Finn Arne Gangstad","demerphq","Jeff King","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"110211","messageId":"20090402123823.GA1756@pvv.org","threadId":"18692","inReplyTo":null,"subject":"[PATCH] git remote update: New option --prune (-p)","fromName":"Finn Arne Gangstad","fromEmail":"finnag@pvv.org","sentAt":"2009-04-02T12:38:24Z","receivedAt":"2009-04-02T12:38:24Z","isPatch":true,"sender":{"key":"finnag@pvv.org","avatar":"https://gravatar.com/avatar/b421ddd58c3f0f93aa473e17b98bb8d53c221fef741746bc8cb59fae4ec6d95e?d=mp&s=160"},"body":"With the --prune (or -p) option, git remote update will also prune\nall the remotes that it fetches.  Previously, you had to do a manual git\nremote prune <remote> for each of the remotes you wanted to prune, and this\ncould be tedious with many remotes.\n\nA single command will now update all remotes, and remove all stale\nbranches: git remote update -p\n\nSigned-off-by: Finn Arne Gangstad <finnag@pvv.org>\n---\n Documentation/git-remote.txt |    4 ++-\n builtin-remote.c             |   73 ++++++++++++++++++++++++++----------------\n 2 files changed, 48 insertions(+), 29 deletions(-)\n\ndiff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt\nindex c9c0e6f..0b6e67d 100644\n--- a/Documentation/git-remote.txt\n+++ b/Documentation/git-remote.txt\n@@ -16,7 +16,7 @@ SYNOPSIS\n 'git remote set-head' <name> [-a | -d | <branch>]\n 'git remote show' [-n] <name>\n 'git remote prune' [-n | --dry-run] <name>\n-'git remote update' [group]\n+'git remote update' [-p | --prune] [group]\n \n DESCRIPTION\n -----------\n@@ -125,6 +125,8 @@ the configuration parameter remotes.default will get used; if\n remotes.default is not defined, all remotes which do not have the\n configuration parameter remote.<name>.skipDefaultUpdate set to true will\n be updated.  (See linkgit:git-config[1]).\n++\n+With `--prune` option, prune all the remotes that are updated.\n \n \n DISCUSSION\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex 9ef846f..da46b5f 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -15,7 +15,7 @@ static const char * const builtin_remote_usage[] = {\n \t\"git remote set-head <name> [-a | -d | <branch>]\",\n \t\"git remote show [-n] <name>\",\n \t\"git remote prune [-n | --dry-run] <name>\",\n-\t\"git remote [-v | --verbose] update [group]\",\n+\t\"git remote [-v | --verbose] update [-p | --prune] [group]\",\n \tNULL\n };\n \n@@ -26,6 +26,7 @@ static const char * const builtin_remote_usage[] = {\n static int verbose;\n \n static int show_all(void);\n+static int prune_remote(const char *remote, int dry_run);\n \n static inline int postfixcmp(const char *string, const char *postfix)\n {\n@@ -1128,46 +1129,51 @@ static int prune(int argc, const char **argv)\n \t\tOPT__DRY_RUN(&dry_run),\n \t\tOPT_END()\n \t};\n-\tstruct ref_states states;\n-\tconst char *dangling_msg;\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-\tdangling_msg = (dry_run\n-\t\t\t? \" %s will become dangling!\\n\"\n-\t\t\t: \" %s has become dangling!\\n\");\n-\n-\tmemset(&states, 0, sizeof(states));\n \tfor (; argc; argc--, argv++) {\n-\t\tint i;\n+\t\tresult |= prune_remote(*argv, dry_run);\n+\t}\n+\treturn result;\n+}\n \n-\t\tget_remote_ref_states(*argv, &states, GET_REF_STATES);\n+static int prune_remote(const char *remote, int dry_run)\n+{\n+\tint result = 0;\n+\tstruct ref_states states;\n+\tconst char *dangling_msg = dry_run\n+\t\t? \" %s will become dangling!\\n\"\n+\t\t: \" %s has become dangling!\\n\";\n \n-\t\tif (states.stale.nr) {\n-\t\t\tprintf(\"Pruning %s\\n\", *argv);\n-\t\t\tprintf(\"URL: %s\\n\",\n-\t\t\t       states.remote->url_nr\n-\t\t\t       ? states.remote->url[0]\n-\t\t\t       : \"(no URL)\");\n-\t\t}\n+\tmemset(&states, 0, sizeof(states));\n+\tint i;\n \n-\t\tfor (i = 0; i < states.stale.nr; i++) {\n-\t\t\tconst char *refname = states.stale.items[i].util;\n+\tget_remote_ref_states(remote, &states, GET_REF_STATES);\n \n-\t\t\tif (!dry_run)\n-\t\t\t\tresult |= delete_ref(refname, NULL, 0);\n+\tif (states.stale.nr) {\n+\t\tprintf(\"Pruning %s\\n\", remote);\n+\t\tprintf(\"URL: %s\\n\",\n+\t\t       states.remote->url_nr\n+\t\t       ? states.remote->url[0]\n+\t\t       : \"(no URL)\");\n+\t}\n \n-\t\t\tprintf(\" * [%s] %s\\n\", dry_run ? \"would prune\" : \"pruned\",\n-\t\t\t       abbrev_ref(refname, \"refs/remotes/\"));\n-\t\t\twarn_dangling_symref(dangling_msg, refname);\n-\t\t}\n+\tfor (i = 0; i < states.stale.nr; i++) {\n+\t\tconst char *refname = states.stale.items[i].util;\n \n-\t\tfree_remote_ref_states(&states);\n+\t\tif (!dry_run)\n+\t\t\tresult |= delete_ref(refname, NULL, 0);\n+\n+\t\tprintf(\" * [%s] %s\\n\", dry_run ? \"would prune\" : \"pruned\",\n+\t\t       abbrev_ref(refname, \"refs/remotes/\"));\n+\t\twarn_dangling_symref(dangling_msg, refname);\n \t}\n \n+\tfree_remote_ref_states(&states);\n \treturn result;\n }\n \n@@ -1204,10 +1210,18 @@ static int get_remote_group(const char *key, const char *value, void *cb)\n \n static int update(int argc, const char **argv)\n {\n-\tint i, result = 0;\n+\tint i, result = 0, prune = 0;\n \tstruct string_list list = { NULL, 0, 0, 0 };\n \tstatic const char *default_argv[] = { NULL, \"default\", NULL };\n+\tstruct option options[] = {\n+\t\tOPT_GROUP(\"update specific options\"),\n+\t\tOPT_BOOLEAN('p', \"prune\", &prune,\n+\t\t\t    \"prune remotes after fecthing\"),\n+\t\tOPT_END()\n+\t};\n \n+\targc = parse_options(argc, argv, options, builtin_remote_usage,\n+\t\t\t     PARSE_OPT_KEEP_ARGV0);\n \tif (argc < 2) {\n \t\targc = 2;\n \t\targv = default_argv;\n@@ -1222,8 +1236,11 @@ static int update(int argc, const char **argv)\n \tif (!result && !list.nr  && argc == 2 && !strcmp(argv[1], \"default\"))\n \t\tresult = for_each_remote(get_one_remote_for_update, &list);\n \n-\tfor (i = 0; i < list.nr; i++)\n+\tfor (i = 0; i < list.nr; i++) {\n \t\tresult |= fetch_remote(list.items[i].string);\n+\t\tif (prune)\n+\t\t\tprune_remote(list.items[i].string, 0);\n+\t}\n \n \t/* all names were strdup()ed or strndup()ed */\n \tlist.strdup_strings = 1;\n-- \n1.6.2.1.470.gd21ca.dirty\n"},{"id":"110214","messageId":"9b18b3110904020634i17633645ue4ba91701ea243a1@mail.gmail.com","threadId":"18692","inReplyTo":"20090402123823.GA1756@pvv.org","subject":"Re: [PATCH] git remote update: New option --prune (-p)","fromName":"demerphq","fromEmail":"demerphq@gmail.com","sentAt":"2009-04-02T13:34:15Z","receivedAt":"2009-04-02T13:34:15Z","isPatch":true,"sender":{"key":"demerphq@gmail.com","avatar":null},"body":"2009/4/2 Finn Arne Gangstad <finnag@pvv.org>:\n> With the --prune (or -p) option, git remote update will also prune\n> all the remotes that it fetches.  Previously, you had to do a manual git\n> remote prune <remote> for each of the remotes you wanted to prune, and this\n> could be tedious with many remotes.\n\nYay!\n\nBut one question. It seem to me odd to put this as an option to git\nremote update, and not git remote prune.\n\nI mean, it seems weird that one must say:\n\n   git remote update --prune\n\nand one cannot say:\n\n   git remote prune --all\n\nespecially when there is a `git remote prune` already. It seems a bit\ncounterintuitive to find pruning actions under \"update\", but not all\nthat strange to find an all \"--all\" option for the \"prune\" action.\n\nAlthough to me having both be allowed and mean the same thing also makes sense.\n\nAnyway, thanks for this regardless, I am looking forward to this\nfunctionality. :-)\n\nCheers,\nyves\n\n\n-- \nperl -Mre=debug -e \"/just|another|perl|hacker/\"\n"},{"id":"110216","messageId":"20090402134414.GB26699@coredump.intra.peff.net","threadId":"18692","inReplyTo":"9b18b3110904020634i17633645ue4ba91701ea243a1@mail.gmail.com","subject":"Re: [PATCH] git remote update: New option --prune (-p)","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-04-02T13:44:14Z","receivedAt":"2009-04-02T13:44:14Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Apr 02, 2009 at 03:34:15PM +0200, demerphq wrote:\n\n> But one question. It seem to me odd to put this as an option to git\n> remote update, and not git remote prune.\n> \n> I mean, it seems weird that one must say:\n> \n>    git remote update --prune\n> \n> and one cannot say:\n> \n>    git remote prune --all\n\nBut \"git remote update\" actually respects \"remote groups\", so it is not\njust \"--all\". I think what you want is \"git remote prune <group>\".\n\n> especially when there is a `git remote prune` already. It seems a bit\n> counterintuitive to find pruning actions under \"update\", but not all\n> that strange to find an all \"--all\" option for the \"prune\" action.\n\nI think it makes sense under update as pruning is really just a\ndifferent (and perhaps slightly more dangerous) form of update.\nGenerally I would only want to run prune after having run update, so\ncombining them makes sense from a workflow perspective.\n\n> Although to me having both be allowed and mean the same thing also\n> makes sense.\n\nI think that would make sense, too.\n\n-Peff\n"},{"id":"110218","messageId":"9b18b3110904020717h3a0d4b34h7f4b2b83527e6743@mail.gmail.com","threadId":"18692","inReplyTo":"20090402134414.GB26699@coredump.intra.peff.net","subject":"Re: [PATCH] git remote update: New option --prune (-p)","fromName":"demerphq","fromEmail":"demerphq@gmail.com","sentAt":"2009-04-02T14:17:35Z","receivedAt":"2009-04-02T14:17:35Z","isPatch":true,"sender":{"key":"demerphq@gmail.com","avatar":null},"body":"2009/4/2 Jeff King <peff@peff.net>:\n> On Thu, Apr 02, 2009 at 03:34:15PM +0200, demerphq wrote:\n>\n>> But one question. It seem to me odd to put this as an option to git\n>> remote update, and not git remote prune.\n>>\n>> I mean, it seems weird that one must say:\n>>\n>>    git remote update --prune\n>>\n>> and one cannot say:\n>>\n>>    git remote prune --all\n>\n> But \"git remote update\" actually respects \"remote groups\", so it is not\n> just \"--all\". I think what you want is \"git remote prune <group>\".\n\nAre there any implicit groups defined, like \"all-remotes\" or\nsomething? It seems less than desirable to have to define such a group\nfor an operation that IMO is pretty reasonable to expect to happen\nregularly.\n\nI personally haven't found any use for defining  remote groups yet to\nbe honest. Its a granularity of operation that hasnt served much\npurpose for me yet. Although i could see it being useful in the\nfuture.\n\nGenerally tho I either want to update and prune one remote only, with\n\n   git fetch $remote; git prune $remote,\n\nor i want to update and prune all with something like:\n\n  git remote update; for r in $(git remote); do git remote prune $r; done;\n\nThis patch makes the latter better huffman encoded, but I'd kind of\nexpect both to be doable as single commands in terms of how often I\nwant to do them.\n\nMaybe git fetch --prune would be a nice complement to this patch.\n\n>> especially when there is a `git remote prune` already. It seems a bit\n>> counterintuitive to find pruning actions under \"update\", but not all\n>> that strange to find an all \"--all\" option for the \"prune\" action.\n>\n> I think it makes sense under update as pruning is really just a\n> different (and perhaps slightly more dangerous) form of update.\n> Generally I would only want to run prune after having run update, so\n> combining them makes sense from a workflow perspective.\n\nYeah, conceptually they approach the same point from different angles.\n\n>\n>> Although to me having both be allowed and mean the same thing also\n>> makes sense.\n>\n> I think that would make sense, too.\n\nAnd the solution that presents the least surprise to the most users.\n\nYves\n\n\n\n-- \nperl -Mre=debug -e \"/just|another|perl|hacker/\"\n"},{"id":"110220","messageId":"20090402143112.GA26974@coredump.intra.peff.net","threadId":"18692","inReplyTo":"9b18b3110904020717h3a0d4b34h7f4b2b83527e6743@mail.gmail.com","subject":"Re: [PATCH] git remote update: New option --prune (-p)","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-04-02T14:31:12Z","receivedAt":"2009-04-02T14:31:12Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Apr 02, 2009 at 04:17:35PM +0200, demerphq wrote:\n\n> > But \"git remote update\" actually respects \"remote groups\", so it is not\n> > just \"--all\". I think what you want is \"git remote prune <group>\".\n> \n> Are there any implicit groups defined, like \"all-remotes\" or\n> something? It seems less than desirable to have to define such a group\n> for an operation that IMO is pretty reasonable to expect to happen\n> regularly.\n\nYes. From \"git help remote\":\n\n       update\n           Fetch updates for a named set of remotes in the repository as\n           defined by remotes.<group>. If a named group is not specified on\n           the command line, the configuration parameter remotes.default will\n           get used; if remotes.default is not defined, all remotes which do\n           not have the configuration parameter\n           remote.<name>.skipDefaultUpdate set to true will be updated. (See\n           git-config(1)).\n\nSo without defining any other config, \"git remote update\" will by\ndefault update everything\n\n> I personally haven't found any use for defining  remote groups yet to\n> be honest. Its a granularity of operation that hasnt served much\n> purpose for me yet. Although i could see it being useful in the\n> future.\n\nI haven't either. I suspect it would be useful if you had a complex set\nof repo relationships, like an integration manager pulling from an\nupstream but also from other developers.\n\n> Generally tho I either want to update and prune one remote only, with\n> \n>    git fetch $remote; git prune $remote,\n\nIt might be useful if \"remote update\" treated an unconfigured group as a\nsimple remote. So that \"git remote update --prune $remote\" would do what\nyou wanted here.\n\nI could even see \"remote.*.autoprune\" config being useful so you could\navoid --prune. It is living dangerously, I suppose, for some workflows;\nbut I generally consider whatever is in my remote tracking branches to\nbe throwaway, and automatically pruning is not really dangerous.\n\n> or i want to update and prune all with something like:\n> \n>   git remote update; for r in $(git remote); do git remote prune $r; done;\n> \n> This patch makes the latter better huffman encoded, but I'd kind of\n> expect both to be doable as single commands in terms of how often I\n> want to do them.\n> \n> Maybe git fetch --prune would be a nice complement to this patch.\n\nI think we have tried to keep pruning out of fetch, as fetch does not\nnecessarily use or know about tracking branches. But the \"git remote\nupdate $remote\" proposal I gave above would do basically the same thing\n(except you would call it \"remote update\" instead of \"fetch\").\n\n-Peff\n"},{"id":"110224","messageId":"9b18b3110904020907i23f246aelccc2a0770acc2574@mail.gmail.com","threadId":"18692","inReplyTo":"20090402143112.GA26974@coredump.intra.peff.net","subject":"Re: [PATCH] git remote update: New option --prune (-p)","fromName":"demerphq","fromEmail":"demerphq@gmail.com","sentAt":"2009-04-02T16:07:33Z","receivedAt":"2009-04-02T16:07:33Z","isPatch":true,"sender":{"key":"demerphq@gmail.com","avatar":null},"body":"2009/4/2 Jeff King <peff@peff.net>:\n> On Thu, Apr 02, 2009 at 04:17:35PM +0200, demerphq wrote:\n>\n>> > But \"git remote update\" actually respects \"remote groups\", so it is not\n>> > just \"--all\". I think what you want is \"git remote prune <group>\".\n>>\n>> Are there any implicit groups defined, like \"all-remotes\" or\n>> something? It seems less than desirable to have to define such a group\n>> for an operation that IMO is pretty reasonable to expect to happen\n>> regularly.\n>\n> Yes. From \"git help remote\":\n>\n>       update\n>           Fetch updates for a named set of remotes in the repository as\n>           defined by remotes.<group>. If a named group is not specified on\n>           the command line, the configuration parameter remotes.default will\n>           get used; if remotes.default is not defined, all remotes which do\n>           not have the configuration parameter\n>           remote.<name>.skipDefaultUpdate set to true will be updated. (See\n>           git-config(1)).\n>\n> So without defining any other config, \"git remote update\" will by\n> default update everything\n\nEr, personally i find that documentation pretty cryptic. And when i\ncheck git config for group, i see this:\n\n       remotes.<group>\n           The list of remotes which are fetched by \"git remote update\n           <group>\". See git-remote(1).\n\nand\n\n       remote.<name>.skipDefaultUpdate\n           If true, this remote will be skipped by default when updating using\n           the update subcommand of git-remote(1).\n\nNeither of which really explain groups, how to define them properly,\n(the list is separated by what? and includes the remote name?) or\nwhether there are implicit groups. I mean, it seems logical that if\nyou can have user defined groups that there are some built in ones\ntoo, like \"all\" and \"none\" or perhaps groups defined by transport\n\"http\" or \"git\" for instance.\n\n>> I personally haven't found any use for defining  remote groups yet to\n>> be honest. Its a granularity of operation that hasnt served much\n>> purpose for me yet. Although i could see it being useful in the\n>> future.\n>\n> I haven't either. I suspect it would be useful if you had a complex set\n> of repo relationships, like an integration manager pulling from an\n> upstream but also from other developers.\n\nNow that you have called my attention to them in more detail i suspect\nill end up using them for a few things. Maybe ill try to write up a\ndoc patch once i have.\n\n>> Generally tho I either want to update and prune one remote only, with\n>>\n>>    git fetch $remote; git prune $remote,\n>\n> It might be useful if \"remote update\" treated an unconfigured group as a\n> simple remote. So that \"git remote update --prune $remote\" would do what\n> you wanted here.\n\nIt seems reasonable to me that names for groups and remotes should\nstay distinct and that remotes are treated as being groups which\ncontain only the remote of the same name. These would be yet more\nimplicit groups.\n\n>\n> I could even see \"remote.*.autoprune\" config being useful so you could\n> avoid --prune. It is living dangerously, I suppose, for some workflows;\n> but I generally consider whatever is in my remote tracking branches to\n> be throwaway, and automatically pruning is not really dangerous.\n\nMe too.\n\n>> or i want to update and prune all with something like:\n>>\n>>   git remote update; for r in $(git remote); do git remote prune $r; done;\n>>\n>> This patch makes the latter better huffman encoded, but I'd kind of\n>> expect both to be doable as single commands in terms of how often I\n>> want to do them.\n>>\n>> Maybe git fetch --prune would be a nice complement to this patch.\n>\n> I think we have tried to keep pruning out of fetch, as fetch does not\n> necessarily use or know about tracking branches. But the \"git remote\n> update $remote\" proposal I gave above would do basically the same thing\n> (except you would call it \"remote update\" instead of \"fetch\").\n\nOk, that makes sense.  I see why fetch would be left out. Thanks for explaining.\n\ncheers,\nYves\n\n\n\n\n-- \nperl -Mre=debug -e \"/just|another|perl|hacker/\"\n"},{"id":"110226","messageId":"20090402163213.GA28261@coredump.intra.peff.net","threadId":"18692","inReplyTo":"9b18b3110904020907i23f246aelccc2a0770acc2574@mail.gmail.com","subject":"Re: [PATCH] git remote update: New option --prune (-p)","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-04-02T16:32:13Z","receivedAt":"2009-04-02T16:32:13Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Apr 02, 2009 at 06:07:33PM +0200, demerphq wrote:\n\n> Er, personally i find that documentation pretty cryptic. And when i\n> check git config for group, i see this:\n> \n>        remotes.<group>\n>            The list of remotes which are fetched by \"git remote update\n>            <group>\". See git-remote(1).\n\nYeah, this should probably say \"separated by space\" or whatever (I\nactually don't even know). I would assume it contains the remote name; I\ncan't imagine what other thing it would include. But it wouldn't hurt to\nmake that more explicit.\n\nI'm sure a documentation patch would be welcome.\n\n>        remote.<name>.skipDefaultUpdate\n>            If true, this remote will be skipped by default when updating using\n>            the update subcommand of git-remote(1).\n>\n> Neither of which really explain groups, how to define them properly,\n> (the list is separated by what? and includes the remote name?) or\n> whether there are implicit groups. I mean, it seems logical that if\n> you can have user defined groups that there are some built in ones\n> too, like \"all\" and \"none\" or perhaps groups defined by transport\n> \"http\" or \"git\" for instance.\n\nI think what is confusing is that there is exactly one implicit group,\nand it is \"the default group\", which contains every remote that doesn't\nhave skipDefaultUpdate set. You refer to the \"default group\" by not\nmentioning any group.\n\nSo no, there aren't other implicit groups (AFAIK).\n\nYou can propose implicit groups, but I think they would have to have a\ncompelling use case over simply creating them manually. To avoid\nconflict with groups people have already defined, they would only be\nused if no remotes.$whatever config existed.\n\nI think having \"git remote update foo\" fall back to a group containing\nonly the remote \"foo\" when \"remotes.foo\" does not exist makes sense.\nI'm not sure that \"none\", \"http\", or \"git\" is all that useful in\npractice (the only thing I can think of for the latter two is that you\nmight use \"git\" versus \"http\" depending on restrictive firewall\nsettings).\n\nYou could give the unnamed \"default group\" a name (like \"all\"), but then\nyou risk conflict with existing \"remotes.all\". And in this case, it is\nhard to remain backwards compatible: \"git remote update\" will do\nsomething different now in the case that the user has configured\nremotes.all.\n\n-Peff\n"},{"id":"110230","messageId":"7vab6zexq7.fsf@gitster.siamese.dyndns.org","threadId":"18692","inReplyTo":"20090402134414.GB26699@coredump.intra.peff.net","subject":"Re: [PATCH] git remote update: New option --prune (-p)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-04-02T18:06:56Z","receivedAt":"2009-04-02T18:06:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> I think it makes sense under update as pruning is really just a\n> different (and perhaps slightly more dangerous) form of update.\n> Generally I would only want to run prune after having run update, so\n> combining them makes sense from a workflow perspective.\n\nI agree with you that \"oh by the way please prune as well\" makes perfect\nsense, but I actually would even go stronger than that---if we _were_\nadding this command today, I would probably make \"update\" prune by\ndefault, perhaps with an option to skip the pruning step.\n\nI gave the patch an only cursory look, so I wouldn't comment on the\nimplementation; two things I would look at in the code would be if it\nmakes two connections to the remote to learn the same information (which\nwould be bad) and if it skips the pruning stage if the update stage failed\n(which would probably be a sane precaution).\n"},{"id":"110237","messageId":"9b18b3110904021205t6b00e486k2d0717e252b01d14@mail.gmail.com","threadId":"18692","inReplyTo":"20090402163213.GA28261@coredump.intra.peff.net","subject":"Re: [PATCH] git remote update: New option --prune (-p)","fromName":"demerphq","fromEmail":"demerphq@gmail.com","sentAt":"2009-04-02T19:05:47Z","receivedAt":"2009-04-02T19:05:47Z","isPatch":true,"sender":{"key":"demerphq@gmail.com","avatar":null},"body":"2009/4/2 Jeff King <peff@peff.net>:\n> On Thu, Apr 02, 2009 at 06:07:33PM +0200, demerphq wrote:\n>\n>> Er, personally i find that documentation pretty cryptic. And when i\n>> check git config for group, i see this:\n>>\n>>        remotes.<group>\n>>            The list of remotes which are fetched by \"git remote update\n>>            <group>\". See git-remote(1).\n>\n> Yeah, this should probably say \"separated by space\" or whatever (I\n> actually don't even know). I would assume it contains the remote name; I\n> can't imagine what other thing it would include. But it wouldn't hurt to\n> make that more explicit.\n>\n> I'm sure a documentation patch would be welcome.\n\nIf/when i feel that i understand the subject sufficiently Ill make an\nattempt. :-)\n\n>>        remote.<name>.skipDefaultUpdate\n>>            If true, this remote will be skipped by default when updating using\n>>            the update subcommand of git-remote(1).\n>>\n>> Neither of which really explain groups, how to define them properly,\n>> (the list is separated by what? and includes the remote name?) or\n>> whether there are implicit groups. I mean, it seems logical that if\n>> you can have user defined groups that there are some built in ones\n>> too, like \"all\" and \"none\" or perhaps groups defined by transport\n>> \"http\" or \"git\" for instance.\n>\n> I think what is confusing is that there is exactly one implicit group,\n> and it is \"the default group\", which contains every remote that doesn't\n> have skipDefaultUpdate set. You refer to the \"default group\" by not\n> mentioning any group.\n\nYes well an implicit group \"default\" would be nice.\n\n>\n> So no, there aren't other implicit groups (AFAIK).\n>\n> You can propose implicit groups, but I think they would have to have a\n> compelling use case over simply creating them manually. To avoid\n> conflict with groups people have already defined, they would only be\n> used if no remotes.$whatever config existed.\n\nOr perhpas simply use syntax not likely or expected to be used in the\nname of a group. Like colon. Or something like that.\n\n>\n> I think having \"git remote update foo\" fall back to a group containing\n> only the remote \"foo\" when \"remotes.foo\" does not exist makes sense.\n> I'm not sure that \"none\", \"http\", or \"git\" is all that useful in\n> practice (the only thing I can think of for the latter two is that you\n> might use \"git\" versus \"http\" depending on restrictive firewall\n> settings).\n\nWell i was think of situations where somebody has coded something that\njust must have a group.  Thus 'none' would be essentially  a no-op in\nthis case. I know you can argue \"well dont do that\", but people tend\nto do silly things whatever they are told, and explicit arguments make\nfor less special cases in wrapper scripts and the like...\n\n>\n> You could give the unnamed \"default group\" a name (like \"all\"), but then\n> you risk conflict with existing \"remotes.all\".\n\nId much prefer the default group to be called default. Not \"all\".\nIdeally \"all\" would really be \"all\". :-)\n\n> And in this case, it is\n> hard to remain backwards compatible: \"git remote update\" will do\n> something different now in the case that the user has configured\n> remotes.all.\n\nWell, id have a thought a better approach is to use a character that\ncannot or is extremely unlikely to be used in an existing group\ndefinition and cannot be used in a remote definition. Like maybe\n\":all\" or something.\n\nOr maybe: `git config remote.implicitgroups true` could be used to enable it?\n\ncheers,\nYves\n\n\n-- \nperl -Mre=debug -e \"/just|another|perl|hacker/\"\n"},{"id":"110245","messageId":"20090402201803.GA5397@pvv.org","threadId":"18692","inReplyTo":"7vab6zexq7.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] git remote update: New option --prune (-p)","fromName":"Finn Arne Gangstad","fromEmail":"finnag@pvv.org","sentAt":"2009-04-02T20:18:03Z","receivedAt":"2009-04-02T20:18:03Z","isPatch":true,"sender":{"key":"finnag@pvv.org","avatar":"https://gravatar.com/avatar/b421ddd58c3f0f93aa473e17b98bb8d53c221fef741746bc8cb59fae4ec6d95e?d=mp&s=160"},"body":"On Thu, Apr 02, 2009 at 11:06:56AM -0700, Junio C Hamano wrote:\n> [...]\n> \n> I gave the patch an only cursory look, so I wouldn't comment on the\n> implementation; two things I would look at in the code would be if it\n> makes two connections to the remote to learn the same information (which\n> would be bad)\n\nHow bad? git remote update execs \"git fetch <remote>\" to do the\nfetching part, and after that the information is lost of course.  It\nmight be possible to do a --prune option to fetch instead, and just\nuse that directly.\n\n>  and if it skips the pruning stage if the update stage failed\n> (which would probably be a sane precaution).\n\nYes, this should be fixed.\n\n- Finn Arne\n"},{"id":"110247","messageId":"7vljqieq1r.fsf@gitster.siamese.dyndns.org","threadId":"18692","inReplyTo":"20090402201803.GA5397@pvv.org","subject":"Re: [PATCH] git remote update: New option --prune (-p)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-04-02T20:52:48Z","receivedAt":"2009-04-02T20:52:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Finn Arne Gangstad <finnag@pvv.org> writes:\n\n> On Thu, Apr 02, 2009 at 11:06:56AM -0700, Junio C Hamano wrote:\n>> [...]\n>> \n>> I gave the patch an only cursory look, so I wouldn't comment on the\n>> implementation; two things I would look at in the code would be if it\n>> makes two connections to the remote to learn the same information (which\n>> would be bad)\n>\n> How bad?\n\nI'd say only \"could be improved later\" bad.\n"},{"id":"110270","messageId":"20090403090036.GA23955@pvv.org","threadId":"18692","inReplyTo":"7vljqieq1r.fsf@gitster.siamese.dyndns.org","subject":"[PATCHv2 0/2] git remote update: New option --prune (-p)","fromName":"Finn Arne Gangstad","fromEmail":"finnag@pvv.org","sentAt":"2009-04-03T09:00:36Z","receivedAt":"2009-04-03T09:00:36Z","isPatch":false,"sender":{"key":"finnag@pvv.org","avatar":"https://gravatar.com/avatar/b421ddd58c3f0f93aa473e17b98bb8d53c221fef741746bc8cb59fae4ec6d95e?d=mp&s=160"},"body":"On Thu, Apr 02, 2009 at 01:52:48PM -0700, Junio C Hamano wrote:\n> Finn Arne Gangstad <finnag@pvv.org> writes:\n> \n> > On Thu, Apr 02, 2009 at 11:06:56AM -0700, Junio C Hamano wrote:\n> >> [...]\n> >> \n> >> I gave the patch an only cursory look, so I wouldn't comment on the\n> >> implementation; two things I would look at in the code would be if it\n> >> makes two connections to the remote to learn the same information (which\n> >> would be bad)\n> >\n> > How bad?\n> \n> I'd say only \"could be improved later\" bad.\n\nOk. I split the patch into two to make it easier to review.\n1/2 just splits out prune_remote() as a separate function, and does not\nchange any behavior.\n2/2 adds the new option to remote update.\n\nFinn Arne Gangstad (2):\n  builtin-remote.c: Split out prune_remote as a separate function.\n  git remote update: New option --prune\n\n Documentation/git-remote.txt |    4 ++-\n builtin-remote.c             |   76 ++++++++++++++++++++++++++----------------\n 2 files changed, 50 insertions(+), 30 deletions(-)\n\n- Finn Arne\n"},{"id":"110271","messageId":"20090403090237.GA5199@pvv.org","threadId":"18692","inReplyTo":"20090403090036.GA23955@pvv.org","subject":"[PATCHv2 1/2] builtin-remote.c: Split out prune_remote as a separate function.","fromName":"Finn Arne Gangstad","fromEmail":"finnag@pvv.org","sentAt":"2009-04-03T09:02:37Z","receivedAt":"2009-04-03T09:02:37Z","isPatch":false,"sender":{"key":"finnag@pvv.org","avatar":"https://gravatar.com/avatar/b421ddd58c3f0f93aa473e17b98bb8d53c221fef741746bc8cb59fae4ec6d95e?d=mp&s=160"},"body":"prune_remote will be used in update(), so this function was split\nout to avoid code duplication.\n\nSigned-off-by: Finn Arne Gangstad <finnag@pvv.org>\n---\n builtin-remote.c |   56 +++++++++++++++++++++++++++++------------------------\n 1 files changed, 31 insertions(+), 25 deletions(-)\n\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex 9ef846f..9804d6c 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -26,6 +26,7 @@ static const char * const builtin_remote_usage[] = {\n static int verbose;\n \n static int show_all(void);\n+static int prune_remote(const char *remote, int dry_run);\n \n static inline int postfixcmp(const char *string, const char *postfix)\n {\n@@ -1128,46 +1129,51 @@ static int prune(int argc, const char **argv)\n \t\tOPT__DRY_RUN(&dry_run),\n \t\tOPT_END()\n \t};\n-\tstruct ref_states states;\n-\tconst char *dangling_msg;\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-\tdangling_msg = (dry_run\n-\t\t\t? \" %s will become dangling!\\n\"\n-\t\t\t: \" %s has become dangling!\\n\");\n+\tfor (; argc; argc--, argv++)\n+\t\tresult |= prune_remote(*argv, dry_run);\n \n-\tmemset(&states, 0, sizeof(states));\n-\tfor (; argc; argc--, argv++) {\n-\t\tint i;\n+\treturn result;\n+}\n \n-\t\tget_remote_ref_states(*argv, &states, GET_REF_STATES);\n+static int prune_remote(const char *remote, int dry_run)\n+{\n+\tint result = 0;\n+\tstruct ref_states states;\n+\tconst char *dangling_msg = dry_run\n+\t\t? \" %s will become dangling!\\n\"\n+\t\t: \" %s has become dangling!\\n\";\n \n-\t\tif (states.stale.nr) {\n-\t\t\tprintf(\"Pruning %s\\n\", *argv);\n-\t\t\tprintf(\"URL: %s\\n\",\n-\t\t\t       states.remote->url_nr\n-\t\t\t       ? states.remote->url[0]\n-\t\t\t       : \"(no URL)\");\n-\t\t}\n+\tmemset(&states, 0, sizeof(states));\n+\tint i;\n \n-\t\tfor (i = 0; i < states.stale.nr; i++) {\n-\t\t\tconst char *refname = states.stale.items[i].util;\n+\tget_remote_ref_states(remote, &states, GET_REF_STATES);\n \n-\t\t\tif (!dry_run)\n-\t\t\t\tresult |= delete_ref(refname, NULL, 0);\n+\tif (states.stale.nr) {\n+\t\tprintf(\"Pruning %s\\n\", remote);\n+\t\tprintf(\"URL: %s\\n\",\n+\t\t       states.remote->url_nr\n+\t\t       ? states.remote->url[0]\n+\t\t       : \"(no URL)\");\n+\t}\n \n-\t\t\tprintf(\" * [%s] %s\\n\", dry_run ? \"would prune\" : \"pruned\",\n-\t\t\t       abbrev_ref(refname, \"refs/remotes/\"));\n-\t\t\twarn_dangling_symref(dangling_msg, refname);\n-\t\t}\n+\tfor (i = 0; i < states.stale.nr; i++) {\n+\t\tconst char *refname = states.stale.items[i].util;\n \n-\t\tfree_remote_ref_states(&states);\n+\t\tif (!dry_run)\n+\t\t\tresult |= delete_ref(refname, NULL, 0);\n+\n+\t\tprintf(\" * [%s] %s\\n\", dry_run ? \"would prune\" : \"pruned\",\n+\t\t       abbrev_ref(refname, \"refs/remotes/\"));\n+\t\twarn_dangling_symref(dangling_msg, refname);\n \t}\n \n+\tfree_remote_ref_states(&states);\n \treturn result;\n }\n \n-- \n1.6.2.1.471.gdeb91.dirty\n"},{"id":"110272","messageId":"20090403090344.GB5199@pvv.org","threadId":"18692","inReplyTo":"20090403090036.GA23955@pvv.org","subject":"[PATCHv2 2/2] git remote update: New option --prune","fromName":"Finn Arne Gangstad","fromEmail":"finnag@pvv.org","sentAt":"2009-04-03T09:03:44Z","receivedAt":"2009-04-03T09:03:44Z","isPatch":false,"sender":{"key":"finnag@pvv.org","avatar":"https://gravatar.com/avatar/b421ddd58c3f0f93aa473e17b98bb8d53c221fef741746bc8cb59fae4ec6d95e?d=mp&s=160"},"body":"With the --prune (or -p) option, git remote update will also prune\nall the remotes that it fetches.  Previously, you had to do a manual\ngit remote prune <remote> for each of the remotes you wanted to\nprune, and this could be tedious with many remotes.\n\nA single command will now update a set of remotes, and remove all\nstale branches: git remote update -p [group]\n\nSigned-off-by: Finn Arne Gangstad <finnag@pvv.org>\n---\n Documentation/git-remote.txt |    4 +++-\n builtin-remote.c             |   20 ++++++++++++++++----\n 2 files changed, 19 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt\nindex c9c0e6f..0b6e67d 100644\n--- a/Documentation/git-remote.txt\n+++ b/Documentation/git-remote.txt\n@@ -16,7 +16,7 @@ SYNOPSIS\n 'git remote set-head' <name> [-a | -d | <branch>]\n 'git remote show' [-n] <name>\n 'git remote prune' [-n | --dry-run] <name>\n-'git remote update' [group]\n+'git remote update' [-p | --prune] [group]\n \n DESCRIPTION\n -----------\n@@ -125,6 +125,8 @@ the configuration parameter remotes.default will get used; if\n remotes.default is not defined, all remotes which do not have the\n configuration parameter remote.<name>.skipDefaultUpdate set to true will\n be updated.  (See linkgit:git-config[1]).\n++\n+With `--prune` option, prune all the remotes that are updated.\n \n \n DISCUSSION\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex 9804d6c..c8e5b17 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -15,7 +15,7 @@ static const char * const builtin_remote_usage[] = {\n \t\"git remote set-head <name> [-a | -d | <branch>]\",\n \t\"git remote show [-n] <name>\",\n \t\"git remote prune [-n | --dry-run] <name>\",\n-\t\"git remote [-v | --verbose] update [group]\",\n+\t\"git remote [-v | --verbose] update [-p | --prune] [group]\",\n \tNULL\n };\n \n@@ -1210,10 +1210,18 @@ static int get_remote_group(const char *key, const char *value, void *cb)\n \n static int update(int argc, const char **argv)\n {\n-\tint i, result = 0;\n+\tint i, result = 0, prune = 0;\n \tstruct string_list list = { NULL, 0, 0, 0 };\n \tstatic const char *default_argv[] = { NULL, \"default\", NULL };\n+\tstruct option options[] = {\n+\t\tOPT_GROUP(\"update specific options\"),\n+\t\tOPT_BOOLEAN('p', \"prune\", &prune,\n+\t\t\t    \"prune remotes after fecthing\"),\n+\t\tOPT_END()\n+\t};\n \n+\targc = parse_options(argc, argv, options, builtin_remote_usage,\n+\t\t\t     PARSE_OPT_KEEP_ARGV0);\n \tif (argc < 2) {\n \t\targc = 2;\n \t\targv = default_argv;\n@@ -1228,8 +1236,12 @@ static int update(int argc, const char **argv)\n \tif (!result && !list.nr  && argc == 2 && !strcmp(argv[1], \"default\"))\n \t\tresult = for_each_remote(get_one_remote_for_update, &list);\n \n-\tfor (i = 0; i < list.nr; i++)\n-\t\tresult |= fetch_remote(list.items[i].string);\n+\tfor (i = 0; i < list.nr; i++) {\n+\t\tint err = fetch_remote(list.items[i].string);\n+\t\tresult |= err;\n+\t\tif (!err && prune)\n+\t\t\tresult |= prune_remote(list.items[i].string, 0);\n+\t}\n \n \t/* all names were strdup()ed or strndup()ed */\n \tlist.strdup_strings = 1;\n-- \n1.6.2.1.471.gdeb91.dirty\n"},{"id":"110397","messageId":"7veiw7v3d0.fsf@gitster.siamese.dyndns.org","threadId":"18692","inReplyTo":"20090403090344.GB5199@pvv.org","subject":"Re: [PATCHv2 2/2] git remote update: New option --prune","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-04-05T09:47:39Z","receivedAt":"2009-04-05T09:47:39Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thanks, queued (with a minor C90 fixup).\n"}]}