{"thread":{"id":"28558","subject":"[PATCH/RFC] remote: support --all for the prune-subcommand","startedAt":"2011-10-03T12:16:08Z","lastAt":"2011-10-12T21:36:18Z","messageCount":10,"participants":["Erik Faye-Lund","Jacob Helwig","Jeff King"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"176739","messageId":"1317644168-5808-1-git-send-email-kusmabite@gmail.com","threadId":"28558","inReplyTo":null,"subject":"[PATCH/RFC] remote: support --all for the prune-subcommand","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2011-10-03T12:16:08Z","receivedAt":"2011-10-03T12:16:08Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"While we're at it, wrap a long line to fit on a 80 char terminal.\n\nSigned-off-by: Erik Faye-Lund <kusmabite@gmail.com>\n---\n\nI recently needed to prune remote branches in a repo with a lot\nof remotes, and to my surprise \"git remote prune\" didn't support\nthe --all option. So I added it. Perhaps this is useful for other\npeople as well?\n\n Documentation/git-remote.txt |    2 +-\n builtin/remote.c             |   27 ++++++++++++++++++++-------\n 2 files changed, 21 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt\nindex 5a8c506..856cc7f 100644\n--- a/Documentation/git-remote.txt\n+++ b/Documentation/git-remote.txt\n@@ -19,7 +19,7 @@ SYNOPSIS\n 'git remote set-url --add' [--push] <name> <newurl>\n 'git remote set-url --delete' [--push] <name> <url>\n 'git remote' [-v | --verbose] 'show' [-n] <name>\n-'git remote prune' [-n | --dry-run] <name>\n+'git remote prune' [-n | --dry-run] (--all | <name>...)\n 'git remote' [-v | --verbose] 'update' [-p | --prune] [(<group> | <remote>)...]\n \n DESCRIPTION\ndiff --git a/builtin/remote.c b/builtin/remote.c\nindex f2a9c26..2e8407d 100644\n--- a/builtin/remote.c\n+++ b/builtin/remote.c\n@@ -14,7 +14,7 @@ static const char * const builtin_remote_usage[] = {\n \t\"git remote rm <name>\",\n \t\"git remote set-head <name> (-a | -d | <branch>)\",\n \t\"git remote [-v | --verbose] show [-n] <name>\",\n-\t\"git remote prune [-n | --dry-run] <name>\",\n+\t\"git remote prune [-n | --dry-run] (--all | <name>)\",\n \t\"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]\",\n \t\"git remote set-branches <name> [--add] <branch>...\",\n \t\"git remote set-url <name> <newurl> [<oldurl>]\",\n@@ -1222,22 +1222,35 @@ static int set_head(int argc, const char **argv)\n \treturn result;\n }\n \n+static int add_one_remote(struct remote *remote, void *remotes)\n+{\n+\tstring_list_append(remotes, remote->name);\n+\treturn 0;\n+}\n+\n static int prune(int argc, const char **argv)\n {\n-\tint dry_run = 0, result = 0;\n+\tstruct string_list remotes = STRING_LIST_INIT_NODUP;\n+\tint dry_run = 0, result = 0, all = 0, i;\n \tstruct option options[] = {\n+\t\tOPT_BOOLEAN(0, \"all\", &all, \"prune all remotes\"),\n \t\tOPT__DRY_RUN(&dry_run, \"dry run\"),\n \t\tOPT_END()\n \t};\n \n-\targc = parse_options(argc, argv, NULL, options, builtin_remote_prune_usage,\n-\t\t\t     0);\n+\targc = parse_options(argc, argv, NULL, options,\n+\t                     builtin_remote_prune_usage, 0);\n \n-\tif (argc < 1)\n+\tif (all)\n+\t\tfor_each_remote(add_one_remote, &remotes);\n+\telse if (argc < 1)\n \t\tusage_with_options(builtin_remote_prune_usage, options);\n+\telse\n+\t\tfor (; argc; argc--, argv++)\n+\t\t\tstring_list_append(&remotes, *argv);\n \n-\tfor (; argc; argc--, argv++)\n-\t\tresult |= prune_remote(*argv, dry_run);\n+\tfor (i = 0; i < remotes.nr; ++i)\n+\t\tresult |= prune_remote(remotes.items[i].string, dry_run);\n \n \treturn result;\n }\n-- \n1.7.6.msysgit.0.579.ga3d6f\n"},{"id":"176760","messageId":"20111003181329.GA4368@vfa-6h","threadId":"28558","inReplyTo":"1317644168-5808-1-git-send-email-kusmabite@gmail.com","subject":"Re: [PATCH/RFC] remote: support --all for the prune-subcommand","fromName":"Jacob Helwig","fromEmail":"jacob@technosorcery.net","sentAt":"2011-10-03T18:13:29Z","receivedAt":"2011-10-03T18:13:29Z","isPatch":true,"sender":{"key":"jacob@technosorcery.net","avatar":"https://gravatar.com/avatar/6116efbbb00b1c0268cd76ce802f2caefdd52245a729e5ad3cf09fd3cf778002?d=mp&s=160"},"body":"On Mon, 03 Oct 2011 14:16:08 +0200, Erik Faye-Lund wrote:\n> \n> While we're at it, wrap a long line to fit on a 80 char terminal.\n> \n> Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>\n> ---\n> \n> I recently needed to prune remote branches in a repo with a lot\n> of remotes, and to my surprise \"git remote prune\" didn't support\n> the --all option. So I added it. Perhaps this is useful for other\n> people as well?\n> \n\nCan't really comment on the implementation (especially since I didn't\nactually look at it), but having \"git remote prune --all\" work would be\n_tremendously_ helpful to me.  Thanks for doing this!\n\n-- \nJacob Helwig\nhttp://about.me/jhelwig\n"},{"id":"176805","messageId":"20111004070006.GA6824@sigill.intra.peff.net","threadId":"28558","inReplyTo":"1317644168-5808-1-git-send-email-kusmabite@gmail.com","subject":"Re: [PATCH/RFC] remote: support --all for the prune-subcommand","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-04T07:00:06Z","receivedAt":"2011-10-04T07:00:06Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Oct 03, 2011 at 02:16:08PM +0200, Erik Faye-Lund wrote:\n\n> I recently needed to prune remote branches in a repo with a lot\n> of remotes, and to my surprise \"git remote prune\" didn't support\n> the --all option. So I added it. Perhaps this is useful for other\n> people as well?\n\nYou could do:\n\n  git remote update --prune\n\nBut I thought we were trying to get away from remote doing fetch-like\nthings in the long term. Isn't the \"right\" way to do this these days:\n\n  git fetch --all --prune\n\n?\n\n-Peff\n"},{"id":"176808","messageId":"CABPQNSZrfxhyA3em8TN2=d7pAHopZMgRg47baKnDT9h14=rxkA@mail.gmail.com","threadId":"28558","inReplyTo":"20111004070006.GA6824@sigill.intra.peff.net","subject":"Re: [PATCH/RFC] remote: support --all for the prune-subcommand","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2011-10-04T07:10:40Z","receivedAt":"2011-10-04T07:10:40Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Tue, Oct 4, 2011 at 9:00 AM, Jeff King <peff@peff.net> wrote:\n> On Mon, Oct 03, 2011 at 02:16:08PM +0200, Erik Faye-Lund wrote:\n>\n>> I recently needed to prune remote branches in a repo with a lot\n>> of remotes, and to my surprise \"git remote prune\" didn't support\n>> the --all option. So I added it. Perhaps this is useful for other\n>> people as well?\n>\n> You could do:\n>\n>  git remote update --prune\n>\n> But I thought we were trying to get away from remote doing fetch-like\n> things in the long term. Isn't the \"right\" way to do this these days:\n>\n>  git fetch --all --prune\n>\n> ?\n>\n> -Peff\n>\n\nI wasn't aware that fetch could prune, but yeah, that seems much\nbetter to me. Perhaps a mention of this in the \"git remote prune\"\ndocumentation could steer other users in the right direction?\n"},{"id":"176809","messageId":"20111004071332.GA7308@sigill.intra.peff.net","threadId":"28558","inReplyTo":"CABPQNSZrfxhyA3em8TN2=d7pAHopZMgRg47baKnDT9h14=rxkA@mail.gmail.com","subject":"Re: [PATCH/RFC] remote: support --all for the prune-subcommand","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-04T07:13:32Z","receivedAt":"2011-10-04T07:13:32Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Oct 04, 2011 at 09:10:40AM +0200, Erik Faye-Lund wrote:\n\n> >  git fetch --all --prune\n> >\n> I wasn't aware that fetch could prune, but yeah, that seems much\n> better to me. Perhaps a mention of this in the \"git remote prune\"\n> documentation could steer other users in the right direction?\n\nYeah, that makes sense.\n\nThere is one slight difference: I think \"git remote prune\" will _just_\nprune, and not fetch into existing refs at all. I'm not sure exactly\nwhy you would want that, though. Presumably you run \"prune\" after you\njust fetched, anyway. Combining the two steps saves an extra network\nconnection.\n\n-Peff\n"},{"id":"176811","messageId":"CABPQNSZ-ELfFuxmKMqXCQaAgMZMRsZG3S5wWJLsjkYVvK6aGug@mail.gmail.com","threadId":"28558","inReplyTo":"20111004071332.GA7308@sigill.intra.peff.net","subject":"Re: [PATCH/RFC] remote: support --all for the prune-subcommand","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2011-10-04T07:18:03Z","receivedAt":"2011-10-04T07:18:03Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Tue, Oct 4, 2011 at 9:13 AM, Jeff King <peff@peff.net> wrote:\n> On Tue, Oct 04, 2011 at 09:10:40AM +0200, Erik Faye-Lund wrote:\n>\n>> >  git fetch --all --prune\n>> >\n>> I wasn't aware that fetch could prune, but yeah, that seems much\n>> better to me. Perhaps a mention of this in the \"git remote prune\"\n>> documentation could steer other users in the right direction?\n>\n> Yeah, that makes sense.\n>\n> There is one slight difference: I think \"git remote prune\" will _just_\n> prune, and not fetch into existing refs at all. I'm not sure exactly\n> why you would want that, though.\n\nHmm, you might want to do that on, say, a mobile network to save\nbandwidth; i.e throw away the stale branches, but not yet update the\nnon-stale ones because downloading the objects might take a long time\n(and/or be expensive).\n\nSo with that in mind, I actually think my patch makes sense in some\ncases, but it certainly is less useful that I originally though ;)\n\nA mention in the documentation seems like a good move no matter what, though.\n"},{"id":"176815","messageId":"CABPQNSb7NYTac5uWSegK9rmYz1n0yt1GJWHKUtLg1k_OYHdDNg@mail.gmail.com","threadId":"28558","inReplyTo":"CABPQNSZ-ELfFuxmKMqXCQaAgMZMRsZG3S5wWJLsjkYVvK6aGug@mail.gmail.com","subject":"Re: [PATCH/RFC] remote: support --all for the prune-subcommand","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2011-10-04T07:40:22Z","receivedAt":"2011-10-04T07:40:22Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Tue, Oct 4, 2011 at 9:18 AM, Erik Faye-Lund <kusmabite@gmail.com> wrote:\n> On Tue, Oct 4, 2011 at 9:13 AM, Jeff King <peff@peff.net> wrote:\n>> On Tue, Oct 04, 2011 at 09:10:40AM +0200, Erik Faye-Lund wrote:\n>>\n>>> >  git fetch --all --prune\n>>> >\n>>> I wasn't aware that fetch could prune, but yeah, that seems much\n>>> better to me. Perhaps a mention of this in the \"git remote prune\"\n>>> documentation could steer other users in the right direction?\n>>\n>> Yeah, that makes sense.\n>>\n>> There is one slight difference: I think \"git remote prune\" will _just_\n>> prune, and not fetch into existing refs at all. I'm not sure exactly\n>> why you would want that, though.\n>\n> Hmm, you might want to do that on, say, a mobile network to save\n> bandwidth; i.e throw away the stale branches, but not yet update the\n> non-stale ones because downloading the objects might take a long time\n> (and/or be expensive).\n>\n> So with that in mind, I actually think my patch makes sense in some\n> cases, but it certainly is less useful that I originally though ;)\n\nStrike that part; I hadn't had my morning coffee yet. It might make\nsense to have similar _functionality_, but having this as a flag to\n\"git fetch\" instead of \"git remote prune\" strikes me as the only sane\napproach.\n\nIn fact, I'm not sure I understand why we simply do not always prune\nby default. My guess would be backward compatibility, but this strikes\nme as one of these things where we should introduce a config variable\n(there's already one for git-gui: gui.pruneduringfetch), add a warning\nif unset, and flip the default at some future major release. After\nall, a remote branch isn't the user's branch - it's a cache/mirror\nsome other user's branch. If a user wants to keep another user's\nbranch, surely the most sane thing would be to make a local branch of\nit?\n"},{"id":"176818","messageId":"20111004075608.GC7308@sigill.intra.peff.net","threadId":"28558","inReplyTo":"CABPQNSb7NYTac5uWSegK9rmYz1n0yt1GJWHKUtLg1k_OYHdDNg@mail.gmail.com","subject":"Re: [PATCH/RFC] remote: support --all for the prune-subcommand","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-04T07:56:08Z","receivedAt":"2011-10-04T07:56:08Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Oct 04, 2011 at 09:40:22AM +0200, Erik Faye-Lund wrote:\n\n> > Hmm, you might want to do that on, say, a mobile network to save\n> > bandwidth; i.e throw away the stale branches, but not yet update the\n> > non-stale ones because downloading the objects might take a long time\n> > (and/or be expensive).\n> >\n> > So with that in mind, I actually think my patch makes sense in some\n> > cases, but it certainly is less useful that I originally though ;)\n> \n> Strike that part; I hadn't had my morning coffee yet. It might make\n> sense to have similar _functionality_, but having this as a flag to\n> \"git fetch\" instead of \"git remote prune\" strikes me as the only sane\n> approach.\n\nI agree that \"git fetch --prune-only\" (or something similar) would be a\nnatural way to do it.\n\n> In fact, I'm not sure I understand why we simply do not always prune\n> by default.\n\nI think the original rationale was that we didn't want fetch to be\n\"lossy\". That is, if I were using upstream's \"foo\" branch as part of my\nwork (to diff against, or whatever), then doing a \"git fetch\" to update\nshould not suddenly make it hard to do my work. And not just hard as in\n\"I notice that it's gone and I adapt my workflow\". But that you no\nlonger have _any_ record of where upstream's \"foo\" branch used to point,\nso even doing something like:\n\n  git rebase --onto new-foo foo my-topic\n\nis impossible.\n\nThese days we have reflogs, so you would hope to do something like:\n\n  git rebase --onto new-foo foo@{1} my-topic\n\nBut ref deletion also deletes the reflog completely, so that doesn't\nwork.\n\nThe right solution, IMHO, is that ref deletion should actually keep the\nreflog around in a graveyard of some sort. Entries would expire\nnaturally over time, as they do in regular reflogs. And then it becomes\na lot safer to prune on every fetch, because you still have 90 days look\nat the reflog.\n\nThere is still one sticky point, which is that your branch config may\nrefer to an upstream branch that gets pruned. That will break some\noperations (as well it should, as the branch is gone, and the user needs\nto adapt their config appropriately). It might be nice if we noticed\nwhen accessing a ref that it doesn't exist but has a deleted reflog, so\nwe can give the user better advice.\n\n> If a user wants to keep another user's branch, surely the most sane\n> thing would be to make a local branch of it?\n\nUnfortunately there are some management problems there. How do I keep my\nlocal branch up to date with what I fetch? I have to keep checking out\nand merging on every fetch (or use some plumbing), which is a pain. But\nif I don't, then when the upstream branch goes away, I still have no\nclue where its tip was right before it got pruned.\n\n-Peff\n"},{"id":"176826","messageId":"CABPQNSb7WACrr=7FsR8YVMC1-q3i0zRhQtXiV8VshfCJn3qgEA@mail.gmail.com","threadId":"28558","inReplyTo":"20111004075608.GC7308@sigill.intra.peff.net","subject":"Re: [PATCH/RFC] remote: support --all for the prune-subcommand","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2011-10-04T08:22:35Z","receivedAt":"2011-10-04T08:22:35Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Tue, Oct 4, 2011 at 9:56 AM, Jeff King <peff@peff.net> wrote:\n> On Tue, Oct 04, 2011 at 09:40:22AM +0200, Erik Faye-Lund wrote:\n>> In fact, I'm not sure I understand why we simply do not always prune\n>> by default.\n>\n> I think the original rationale was that we didn't want fetch to be\n> \"lossy\". That is, if I were using upstream's \"foo\" branch as part of my\n> work (to diff against, or whatever), then doing a \"git fetch\" to update\n> should not suddenly make it hard to do my work. And not just hard as in\n> \"I notice that it's gone and I adapt my workflow\". But that you no\n> longer have _any_ record of where upstream's \"foo\" branch used to point,\n> so even doing something like:\n>\n>  git rebase --onto new-foo foo my-topic\n>\n> is impossible.\n>\n\nFollowing that logic, a user cannot _ever_ safely prune a remote if he\nwants to work on some of the branches. Doing something like \"git\nremote foo -n\" to check if the branch would get pruned before doing a\nproper prune is prone to a race-condition; the branch could be deleted\non the remote between the dry-run and the actual pruning.\n\nBesides, the owner of the repo can just as easily have deleted the\nbranch and created a new one with the same name, causing the contents\nof the branch to be lost. This happens all the time with\n\"for-upstream\"-kind of branches, no?\n\n> These days we have reflogs, so you would hope to do something like:\n>\n>  git rebase --onto new-foo foo@{1} my-topic\n>\n> But ref deletion also deletes the reflog completely, so that doesn't\n> work.\n>\n\n...and this just makes the problem I pointed out above a lot worse.\n\nSo surely, the only sane thing is to make a local branch of what\nyou're interested in to be safe?\n\n> The right solution, IMHO, is that ref deletion should actually keep the\n> reflog around in a graveyard of some sort. Entries would expire\n> naturally over time, as they do in regular reflogs. And then it becomes\n> a lot safer to prune on every fetch, because you still have 90 days look\n> at the reflog.\n>\n\nFixing the reflog to expire for ref deletion rather than completely\ndeleting it sounds like a good move, indeed.\n\n>> If a user wants to keep another user's branch, surely the most sane\n>> thing would be to make a local branch of it?\n>\n> Unfortunately there are some management problems there. How do I keep my\n> local branch up to date with what I fetch? I have to keep checking out\n> and merging on every fetch (or use some plumbing), which is a pain. But\n> if I don't, then when the upstream branch goes away, I still have no\n> clue where its tip was right before it got pruned.\n\nHmm, good point. I tend to just do the dirty work every now and then\nmyself. But I only tend to track upstream and stale\ndevelopment-branches that I intend to pick up, so I'm probably not the\nbest user-example.\n\nWhile we're on the subject, an additional argument to change \"git\nfetch\" to always prune is that it's much much easier for user to grok\n\"last known state of <remote>'s branches\" than \"the union of all the\nbranches that were ever pulled from <remote>, unless --prune was\nspecified\". But that's not a technical one, and surely there's issues\nto resolve with the proposal before going in that direction.\n"},{"id":"177487","messageId":"20111012213618.GA4315@sigill.intra.peff.net","threadId":"28558","inReplyTo":"CABPQNSb7WACrr=7FsR8YVMC1-q3i0zRhQtXiV8VshfCJn3qgEA@mail.gmail.com","subject":"Re: [PATCH/RFC] remote: support --all for the prune-subcommand","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-12T21:36:18Z","receivedAt":"2011-10-12T21:36:18Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Oct 04, 2011 at 10:22:35AM +0200, Erik Faye-Lund wrote:\n\n> > I think the original rationale was that we didn't want fetch to be\n> > \"lossy\". That is, if I were using upstream's \"foo\" branch as part of my\n> > work (to diff against, or whatever), then doing a \"git fetch\" to update\n> > should not suddenly make it hard to do my work. And not just hard as in\n> > \"I notice that it's gone and I adapt my workflow\". But that you no\n> > longer have _any_ record of where upstream's \"foo\" branch used to point,\n> > so even doing something like:\n> >\n> >  git rebase --onto new-foo foo my-topic\n> >\n> > is impossible.\n> \n> Following that logic, a user cannot _ever_ safely prune a remote if he\n> wants to work on some of the branches. Doing something like \"git\n> remote foo -n\" to check if the branch would get pruned before doing a\n> proper prune is prone to a race-condition; the branch could be deleted\n> on the remote between the dry-run and the actual pruning.\n\nRight. And that's why we don't prune by default. In practice, it tends\nto be safe if you pick a reasonable time to prune, and the upstream is\nreasonable about their branches. But turning it on all the time takes\naway the \"pick a reasonable time\".\n\n> Besides, the owner of the repo can just as easily have deleted the\n> branch and created a new one with the same name, causing the contents\n> of the branch to be lost. This happens all the time with\n> \"for-upstream\"-kind of branches, no?\n\nThey can do that, but on the local side, you will just see a jump in\nhistory. But because we didn't _delete_ the ref on the local side, you\nwill retain your reflog.\n\nIOW, the reflog can save us from anything the upstream will do. And\nthat's what makes deletion so special: we delete the local reflog.\n\n> > The right solution, IMHO, is that ref deletion should actually keep the\n> > reflog around in a graveyard of some sort. Entries would expire\n> > naturally over time, as they do in regular reflogs. And then it becomes\n> > a lot safer to prune on every fetch, because you still have 90 days look\n> > at the reflog.\n> >\n> Fixing the reflog to expire for ref deletion rather than completely\n> deleting it sounds like a good move, indeed.\n\nThis is on my long-term todo list, but if somebody gets around to it\nbefore me, I won't be upset. :)\n\n> While we're on the subject, an additional argument to change \"git\n> fetch\" to always prune is that it's much much easier for user to grok\n> \"last known state of <remote>'s branches\" than \"the union of all the\n> branches that were ever pulled from <remote>, unless --prune was\n> specified\". But that's not a technical one, and surely there's issues\n> to resolve with the proposal before going in that direction.\n\nAgreed. Really, everything argument points towards auto-prune except the\nreflog-safety thing. I think once that is fixed, turning on pruning by\ndefault becomes a no-brainer.\n\n-Peff\n"}]}