{"thread":{"id":"28877","subject":"[RFC/PATCH] remote: add new sync command","startedAt":"2011-11-07T16:07:12Z","lastAt":"2011-11-30T11:47:24Z","messageCount":26,"participants":["Felipe Contreras","Jeff King","Junio C Hamano","Jakub Narebski"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"179041","messageId":"1320682032-12698-1-git-send-email-felipe.contreras@gmail.com","threadId":"28877","inReplyTo":null,"subject":"[RFC/PATCH] remote: add new sync command","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2011-11-07T16:07:12Z","receivedAt":"2011-11-07T16:07:12Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"This is useful to mirror all the branches in the current repo to\nanother.\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n Documentation/git-remote.txt |   17 +++++++\n builtin/remote.c             |  108 ++++++++++++++++++++++++++++++++++++++++++\n t/t5505-remote.sh            |   15 ++++++\n 3 files changed, 140 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt\nindex 5a8c506..643fc8b 100644\n--- a/Documentation/git-remote.txt\n+++ b/Documentation/git-remote.txt\n@@ -21,6 +21,7 @@ SYNOPSIS\n 'git remote' [-v | --verbose] 'show' [-n] <name>\n 'git remote prune' [-n | --dry-run] <name>\n 'git remote' [-v | --verbose] 'update' [-p | --prune] [(<group> | <remote>)...]\n+'git remote sync' <name> [-a | --all] [-n | --new] [-p | --prune] [-f | --force] [--dry-run]\n \n DESCRIPTION\n -----------\n@@ -169,6 +170,22 @@ be updated.  (See linkgit:git-config[1]).\n +\n With `--prune` option, prune all the remotes that are updated.\n \n+'sync'::\n+\n+Synchronizes local branches with certain remote. This is useful to backup all\n+the branches in a local repository to a remote one, regardless of what upstream\n+is configured for each branch.\n++\n+With `--prune`, remote branches will be deleted if they are not also locally.\n++\n+With `--new`, local branches that are not yet in the remote will be pushed too.\n++\n+With `--all`, basically both `--prune` and `--new` will be selected.\n++\n+With `--force`, existing branches will be forced to update, like `git push\n+--force`.\n++\n+With `--dry-run`, all the changes will be reported, but not really happen.\n \n DISCUSSION\n ----------\ndiff --git a/builtin/remote.c b/builtin/remote.c\nindex e1285be..b3b9b19 100644\n--- a/builtin/remote.c\n+++ b/builtin/remote.c\n@@ -64,6 +64,11 @@ static const char * const builtin_remote_update_usage[] = {\n \tNULL\n };\n \n+static const char * const builtin_remote_sync_usage[] = {\n+\t\"git remote sync <name> [-a|--all] [-n|--new] [-p|--prune] [<options>]\",\n+\tNULL\n+};\n+\n static const char * const builtin_remote_seturl_usage[] = {\n \t\"git remote set-url [--push] <name> <newurl> [<oldurl>]\",\n \t\"git remote set-url --add <name> <newurl>\",\n@@ -1492,6 +1497,107 @@ static int set_url(int argc, const char **argv)\n \treturn 0;\n }\n \n+struct action {\n+\tstruct string_list *list;\n+\tint type;\n+};\n+\n+static int ref_cb(const char *refname,\n+\tconst unsigned char *sha1, int flags, void *cb_data)\n+{\n+\tstruct action *action = cb_data;\n+\tstruct string_list_item *item;\n+\tif (strcmp(refname, \"HEAD\") == 0)\n+\t\treturn 0;\n+\titem = string_list_insert(action->list, refname);\n+\titem->util = (void *)((long)item->util | action->type);\n+\treturn 0;\n+}\n+\n+static int for_each_in_remote_ref(const char *name, each_ref_fn fn, void *cb_data)\n+{\n+\tchar prefix[1000];\n+\tsprintf(prefix, \"refs/remotes/%s/\", name);\n+\treturn for_each_ref_in(prefix, fn, cb_data);\n+}\n+\n+static int do_sync(int argc, const char **argv)\n+{\n+\tconst char *remotename;\n+\tstruct string_list list;\n+\tstruct action action;\n+\tstruct remote *remote;\n+\tstruct transport *transport;\n+\tint i, r, nonff;\n+\tchar **refspec;\n+\tint refspec_nr = 0;\n+\tint prune = 0, new = 0, all = 0, flags = 0;\n+\n+\tstruct option options[] = {\n+\t\tOPT_BOOLEAN('p', \"prune\", &prune, \"prune remote branches\"),\n+\t\tOPT_BOOLEAN('n', \"new\", &new, \"push new branches\"),\n+\t\tOPT_BOOLEAN('a', \"all\", &all, \"synchronize everything\"),\n+\t\tOPT_BIT(0, \"dry-run\", &flags, \"dry run\", TRANSPORT_PUSH_DRY_RUN),\n+\t\tOPT_BIT('f', \"force\", &flags, \"force updates\", TRANSPORT_PUSH_FORCE),\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, NULL, options, builtin_remote_sync_usage,\n+\t\t\t     PARSE_OPT_KEEP_ARGV0);\n+\tif (argc < 2 || argc > 2)\n+\t\tusage_with_options(builtin_remote_sync_usage, options);\n+\n+\tif (all)\n+\t\tprune = new = 1;\n+\n+\tremotename = argv[1];\n+\tif (!remote_is_configured(remotename))\n+\t\tdie(\"No such remote '%s'\", remotename);\n+\n+\tmemset(&list, 0, sizeof(list));\n+\n+\taction.list = &list;\n+\n+\taction.type = 1;\n+\tfor_each_in_remote_ref(remotename, ref_cb, &action);\n+\n+\taction.type = 2;\n+\tfor_each_branch_ref(ref_cb, &action);\n+\n+\trefspec = xmalloc(sizeof(*refspec) * list.nr);\n+\n+\tfor (i = 0; i < list.nr; i++) {\n+\t\tconst char *str = list.items[i].string;\n+\t\tchar *t = NULL;\n+\n+\t\tswitch ((long)list.items[i].util) {\n+\t\tcase 1:\n+\t\t\tif (prune)\n+\t\t\t\tasprintf(&t, \":%s\", str);\n+\t\t\tbreak;\n+\t\tcase 2:\n+\t\t\tif (new)\n+\t\t\t\tt = strdup(str);\n+\t\t\tbreak;\n+\t\tcase 3:\n+\t\t\tt = strdup(str);\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (t)\n+\t\t\trefspec[refspec_nr++] = t;\n+\t}\n+\n+\tremote = remote_get(remotename);\n+\ttransport = transport_get(remote, NULL);\n+\tr = transport_push(transport, refspec_nr, (const char **)refspec, flags, &nonff);\n+\n+\tfor (i = 0; i < refspec_nr; i++)\n+\t\tfree(refspec[i]);\n+\n+\tstring_list_clear(&list, 0);\n+\n+\treturn r;\n+}\n+\n static int get_one_entry(struct remote *remote, void *priv)\n {\n \tstruct string_list *list = priv;\n@@ -1581,6 +1687,8 @@ int cmd_remote(int argc, const char **argv, const char *prefix)\n \t\tresult = prune(argc, argv);\n \telse if (!strcmp(argv[0], \"update\"))\n \t\tresult = update(argc, argv);\n+\telse if (!strcmp(argv[0], \"sync\"))\n+\t\tresult = do_sync(argc, argv);\n \telse {\n \t\terror(\"Unknown subcommand: %s\", argv[0]);\n \t\tusage_with_options(builtin_remote_usage, options);\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex e8af615..13378c5 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -997,4 +997,19 @@ test_expect_success 'remote set-url --delete baz' '\n \tcmp expect actual\n '\n \n+test_expect_success 'remote sync' '\n+\tsetup_repository sync-origin &&\n+\t(cd sync-origin &&\n+\t git branch another &&\n+\t git config receive.denyCurrentBranch ignore) &&\n+\tgit clone sync-origin sync &&\n+\t(cd sync &&\n+\t git branch -a > /tmp/a &&\n+\t git remote sync origin &&\n+\t git commit --allow-empty -m \"Test\" &&\n+\t git checkout side &&\n+\t git commit --allow-empty -m \"Test\" &&\n+\t git remote sync -a origin)\n+'\n+\n test_done\n-- \n1.7.7\n"},{"id":"179052","messageId":"20111107172218.GB3621@sigill.intra.peff.net","threadId":"28877","inReplyTo":"1320682032-12698-1-git-send-email-felipe.contreras@gmail.com","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-07T17:22:18Z","receivedAt":"2011-11-07T17:22:18Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Nov 07, 2011 at 06:07:12PM +0200, Felipe Contreras wrote:\n\n> This is useful to mirror all the branches in the current repo to\n> another.\n> [...]\n> +'sync'::\n> +\n> +Synchronizes local branches with certain remote. This is useful to backup all\n> +the branches in a local repository to a remote one, regardless of what upstream\n> +is configured for each branch.\n> ++\n> +With `--prune`, remote branches will be deleted if they are not also locally.\n> ++\n> +With `--new`, local branches that are not yet in the remote will be pushed too.\n> ++\n> +With `--all`, basically both `--prune` and `--new` will be selected.\n> ++\n> +With `--force`, existing branches will be forced to update, like `git push\n> +--force`.\n> ++\n> +With `--dry-run`, all the changes will be reported, but not really happen.\n\nWhy is this in \"git remote\", and not \"git push\"?  The former is usually\nabout managing the configuration of remotes, not about actually doing\nthe ref transfer (the \"-f\" flag excepted, but that is clearly just\ncalling out to \"fetch\").\n\nAnd how does this differ from \"git push --mirror\"? It looks like you\nhave more options for what pushing all versus pruning, but wouldn't it\nbe better for \"git push\" to grow those options?\n\n-Peff\n"},{"id":"179060","messageId":"CAMP44s358k4EsCg+K6MeLEU4eLbb4mWyX9AdAf4P9CHvf9Lrwg@mail.gmail.com","threadId":"28877","inReplyTo":"20111107172218.GB3621@sigill.intra.peff.net","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2011-11-07T18:35:07Z","receivedAt":"2011-11-07T18:35:07Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"On Mon, Nov 7, 2011 at 7:22 PM, Jeff King <peff@peff.net> wrote:\n> On Mon, Nov 07, 2011 at 06:07:12PM +0200, Felipe Contreras wrote:\n>\n>> This is useful to mirror all the branches in the current repo to\n>> another.\n>> [...]\n>> +'sync'::\n>> +\n>> +Synchronizes local branches with certain remote. This is useful to backup all\n>> +the branches in a local repository to a remote one, regardless of what upstream\n>> +is configured for each branch.\n>> ++\n>> +With `--prune`, remote branches will be deleted if they are not also locally.\n>> ++\n>> +With `--new`, local branches that are not yet in the remote will be pushed too.\n>> ++\n>> +With `--all`, basically both `--prune` and `--new` will be selected.\n>> ++\n>> +With `--force`, existing branches will be forced to update, like `git push\n>> +--force`.\n>> ++\n>> +With `--dry-run`, all the changes will be reported, but not really happen.\n>\n> Why is this in \"git remote\", and not \"git push\"?  The former is usually\n> about managing the configuration of remotes, not about actually doing\n> the ref transfer (the \"-f\" flag excepted, but that is clearly just\n> calling out to \"fetch\").\n\nI don't know, seems logical to me what 'git remote sync' does, but\n'git push sync'? That sounds weird, and there are no 'git push foo'\ncommands.\n\n> And how does this differ from \"git push --mirror\"? It looks like you\n> have more options for what pushing all versus pruning, but wouldn't it\n> be better for \"git push\" to grow those options?\n\nBut how? --mirror is just an option, I want a separate command, with\nit's own options.\n\nCheers.\n\n-- \nFelipe Contreras\n"},{"id":"179061","messageId":"20111107183938.GA5155@sigill.intra.peff.net","threadId":"28877","inReplyTo":"CAMP44s358k4EsCg+K6MeLEU4eLbb4mWyX9AdAf4P9CHvf9Lrwg@mail.gmail.com","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-07T18:39:38Z","receivedAt":"2011-11-07T18:39:38Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Nov 07, 2011 at 08:35:07PM +0200, Felipe Contreras wrote:\n\n> I don't know, seems logical to me what 'git remote sync' does, but\n> 'git push sync'? That sounds weird, and there are no 'git push foo'\n> commands.\n\nWhat I don't understand is why it is not:\n\n  git push --mirror <URL|remote>\n\n> > And how does this differ from \"git push --mirror\"? It looks like you\n> > have more options for what pushing all versus pruning, but wouldn't it\n> > be better for \"git push\" to grow those options?\n> \n> But how? --mirror is just an option, I want a separate command, with\n> it's own options.\n\nThat's what I don't understand from your proposal. Your command is just\npushing something to the remote, right? Why isn't \"push\" the command,\nand your sync options become options to push?\n\nCan you step back and describe the problem you're trying to solve? Maybe\nwe're not connecting there.\n\n-Peff\n"},{"id":"179074","messageId":"CAMP44s0M-qnZeHCUadSJJCYO=t881sUOi11G3fCG2vaAakPyBQ@mail.gmail.com","threadId":"28877","inReplyTo":"20111107183938.GA5155@sigill.intra.peff.net","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2011-11-07T20:51:10Z","receivedAt":"2011-11-07T20:51:10Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"On Mon, Nov 7, 2011 at 8:39 PM, Jeff King <peff@peff.net> wrote:\n> On Mon, Nov 07, 2011 at 08:35:07PM +0200, Felipe Contreras wrote:\n>\n>> I don't know, seems logical to me what 'git remote sync' does, but\n>> 'git push sync'? That sounds weird, and there are no 'git push foo'\n>> commands.\n>\n> What I don't understand is why it is not:\n>\n>  git push --mirror <URL|remote>\n\nBecause that pushes *everything*.\n\n>> > And how does this differ from \"git push --mirror\"? It looks like you\n>> > have more options for what pushing all versus pruning, but wouldn't it\n>> > be better for \"git push\" to grow those options?\n>>\n>> But how? --mirror is just an option, I want a separate command, with\n>> it's own options.\n>\n> That's what I don't understand from your proposal. Your command is just\n> pushing something to the remote, right? Why isn't \"push\" the command,\n> and your sync options become options to push?\n\nHow exactly? --sync-prune, --sync-new, --sync-all? But actually, I was\nthinking on adding an option to sync the other way around; to get all\nthe remote branches and have them locally.\n\n> Can you step back and describe the problem you're trying to solve? Maybe\n> we're not connecting there.\n\nWell, I usually have quite a lot of branches in my local repositories,\nlike a dozen of so. And I like to back them up in some remote\nrepository, however, not all the branches all the time. git push\n--mirror not only pushes branches, but also tags (and I don't want\nthat), and even other refs. Does that clarifies things?\n\n-- \nFelipe Contreras\n"},{"id":"179075","messageId":"20111107210134.GA7380@sigill.intra.peff.net","threadId":"28877","inReplyTo":"CAMP44s0M-qnZeHCUadSJJCYO=t881sUOi11G3fCG2vaAakPyBQ@mail.gmail.com","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-07T21:01:34Z","receivedAt":"2011-11-07T21:01:34Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Nov 07, 2011 at 10:51:10PM +0200, Felipe Contreras wrote:\n\n> > What I don't understand is why it is not:\n> >\n> >  git push --mirror <URL|remote>\n> \n> Because that pushes *everything*.\n\nAhh, I think I see. It is doing --mirror, but only on a reduced refspec?\n\nIn that case, is there a reason that:\n\n  git push --prune <URL|remote> refs/heads/*\n\nwould not do what you want (note that \"--prune\" does not exist, but I\nthink it should).\n\n> > That's what I don't understand from your proposal. Your command is just\n> > pushing something to the remote, right? Why isn't \"push\" the command,\n> > and your sync options become options to push?\n> \n> How exactly? --sync-prune, --sync-new, --sync-all? But actually, I was\n> thinking on adding an option to sync the other way around; to get all\n> the remote branches and have them locally.\n\nIf I understand correctly, you have three modes:\n\n  1. update remote refs with local values, prune anything remote that we\n     don't have locally (--sync-prune)\n\n  2. update remote refs with local values, including pushing anything\n     new that we don't have locally (--sync-new)\n\n  3. push new and prune (i.e., 1 and 2 together)\n\nIf we had \"git push --prune\" as above, those would be:\n\n  1. git push --prune <remote> :\n\n     I.e., use the \"matching\" refspec to not push new things, but turn\n     on pruning.\n\n  2. git push <remote> refs/heads/*\n\n     Turn off pruning, but use an explicit refspec, not just \"matching\",\n     which will push all local branches.\n\n  3. git push --prune <remote> refs/heads/*\n\n     Turn on both features.\n\n> Well, I usually have quite a lot of branches in my local repositories,\n> like a dozen of so. And I like to back them up in some remote\n> repository, however, not all the branches all the time. git push\n> --mirror not only pushes branches, but also tags (and I don't want\n> that), and even other refs. Does that clarifies things?\n\nThat makes sense. But I think it fits in with git's current UI to do\nthis via a combination of push options and refspecs. Even if we want to\nwrap it in some \"git remote\" command for convenience, I think what\nyou're asking should be implemented as part of \"git push\".\n\n-Peff\n"},{"id":"179078","messageId":"7vhb2f1v7g.fsf@alter.siamese.dyndns.org","threadId":"28877","inReplyTo":"20111107210134.GA7380@sigill.intra.peff.net","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-11-07T21:25:23Z","receivedAt":"2011-11-07T21:25:23Z","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> That makes sense. But I think it fits in with git's current UI to do\n> this via a combination of push options and refspecs. Even if we want to\n> wrap it in some \"git remote\" command for convenience, I think what\n> you're asking should be implemented as part of \"git push\".\n\nYeah, I think it makes sense to give --prune to \"push\" just like \"fetch\"\nalready has. These two are the primary (and in the ideal world, only)\noperations that talk to the outside world. \"remote add -f\" might have been\na tempting \"convenience\" feature, but I personally think it probably was a\nmistake for the exact reason that letting anything but \"push\" and \"fetch\"\ntalk to the outside world just invites more confusion. There does not have\nto be 47 different ways to do the same thing.\n"},{"id":"179079","messageId":"20111107213123.GA10965@sigill.intra.peff.net","threadId":"28877","inReplyTo":"7vhb2f1v7g.fsf@alter.siamese.dyndns.org","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-07T21:31:23Z","receivedAt":"2011-11-07T21:31:23Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Nov 07, 2011 at 01:25:23PM -0800, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > That makes sense. But I think it fits in with git's current UI to do\n> > this via a combination of push options and refspecs. Even if we want to\n> > wrap it in some \"git remote\" command for convenience, I think what\n> > you're asking should be implemented as part of \"git push\".\n> \n> Yeah, I think it makes sense to give --prune to \"push\" just like \"fetch\"\n> already has. These two are the primary (and in the ideal world, only)\n> operations that talk to the outside world. \"remote add -f\" might have been\n> a tempting \"convenience\" feature, but I personally think it probably was a\n> mistake for the exact reason that letting anything but \"push\" and \"fetch\"\n> talk to the outside world just invites more confusion. There does not have\n> to be 47 different ways to do the same thing.\n\nI don't mind \"add -f\" too much, which is at least very clear that it is\nsimply a convenience feature for \"git remote add foo && git fetch foo\".\nBut the other \"git remote\" features like \"set-head -a\", which can't be\ndone any other way, or the \"auto-check-what-the-remote-has\" feature of\n\"git remote show\" are a little gross.\n\nAnyway, I think we are on the same page; this feature (and btw, I think\nthis is a great feature that we should have) should go into \"push\".\n\n-Peff\n"},{"id":"179146","messageId":"CAMP44s0vsQ5sfx8arrRDo+-g9Zff_MmCz5t+yghwCMx_pL4Xzg@mail.gmail.com","threadId":"28877","inReplyTo":"7vhb2f1v7g.fsf@alter.siamese.dyndns.org","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2011-11-08T16:43:25Z","receivedAt":"2011-11-08T16:43:25Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"On Mon, Nov 7, 2011 at 11:25 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Jeff King <peff@peff.net> writes:\n>\n>> That makes sense. But I think it fits in with git's current UI to do\n>> this via a combination of push options and refspecs. Even if we want to\n>> wrap it in some \"git remote\" command for convenience, I think what\n>> you're asking should be implemented as part of \"git push\".\n>\n> Yeah, I think it makes sense to give --prune to \"push\" just like \"fetch\"\n> already has. These two are the primary (and in the ideal world, only)\n> operations that talk to the outside world. \"remote add -f\" might have been\n> a tempting \"convenience\" feature, but I personally think it probably was a\n> mistake for the exact reason that letting anything but \"push\" and \"fetch\"\n> talk to the outside world just invites more confusion. There does not have\n> to be 47 different ways to do the same thing.\n\nWhat about 'git remote update'?\n\n-- \nFelipe Contreras\n"},{"id":"179148","messageId":"CAMP44s089xbEo4VT8rqgS=BJMUu=qsb8Hm5z8bTR2akU8-5QhA@mail.gmail.com","threadId":"28877","inReplyTo":"20111107210134.GA7380@sigill.intra.peff.net","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2011-11-08T17:31:09Z","receivedAt":"2011-11-08T17:31:09Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"On Mon, Nov 7, 2011 at 11:01 PM, Jeff King <peff@peff.net> wrote:\n> On Mon, Nov 07, 2011 at 10:51:10PM +0200, Felipe Contreras wrote:\n>\n>> > What I don't understand is why it is not:\n>> >\n>> >  git push --mirror <URL|remote>\n>>\n>> Because that pushes *everything*.\n>\n> Ahh, I think I see. It is doing --mirror, but only on a reduced refspec?\n>\n> In that case, is there a reason that:\n>\n>  git push --prune <URL|remote> refs/heads/*\n>\n> would not do what you want (note that \"--prune\" does not exist, but I\n> think it should).\n\nI guess that should work.\n\n>> > That's what I don't understand from your proposal. Your command is just\n>> > pushing something to the remote, right? Why isn't \"push\" the command,\n>> > and your sync options become options to push?\n>>\n>> How exactly? --sync-prune, --sync-new, --sync-all? But actually, I was\n>> thinking on adding an option to sync the other way around; to get all\n>> the remote branches and have them locally.\n>\n> If I understand correctly, you have three modes:\n>\n>  1. update remote refs with local values, prune anything remote that we\n>     don't have locally (--sync-prune)\n>\n>  2. update remote refs with local values, including pushing anything\n>     new that we don't have locally (--sync-new)\n\nAnything new that we don't have *remotely*.\n\n>  3. push new and prune (i.e., 1 and 2 together)\n\nYeap.\n\n> If we had \"git push --prune\" as above, those would be:\n>\n>  1. git push --prune <remote> :\n>\n>     I.e., use the \"matching\" refspec to not push new things, but turn\n>     on pruning.\n\nI guess so, but \":\" seems a bit obscure.\n\n>  2. git push <remote> refs/heads/*\n>\n>     Turn off pruning, but use an explicit refspec, not just \"matching\",\n>     which will push all local branches.\n\nIsn't refs/heads/* the same as --all? BTW. I think --all is confusing,\nshould be --branches, or something.\n\n>  3. git push --prune <remote> refs/heads/*\n>\n>     Turn on both features.\n\nMaybe 'git push' options should be reorganized (for 1.8.0):\n\n--all -> --branches\n--tags (same)\n--mirror -> --all\n--update = :\n--prune (new)\n\nIn the meantime, we could add --update and --prune, which would not conflict.\n\n>> Well, I usually have quite a lot of branches in my local repositories,\n>> like a dozen of so. And I like to back them up in some remote\n>> repository, however, not all the branches all the time. git push\n>> --mirror not only pushes branches, but also tags (and I don't want\n>> that), and even other refs. Does that clarifies things?\n>\n> That makes sense. But I think it fits in with git's current UI to do\n> this via a combination of push options and refspecs. Even if we want to\n> wrap it in some \"git remote\" command for convenience, I think what\n> you're asking should be implemented as part of \"git push\".\n\nPerhaps. I will give that a try, let's see how the code ends up.\n\nBut then, maybe similar options should be added to 'git fetch' to do\nthe same in the opposite direction, and that's where things get a bit\nugly:\n\n--all -> rename to --all-remotes?\n--prune -> rename to --prune-tracking?\n--prune-local (new; prune local branches that don't exist on the remote)\n--all (new; similar to 'git push --all' [--mirror])\n--tags (same)\n--update (new; similar to 'git push --update')\n--branches (new; similar to 'git push --branches')\n\nSomehow I fell there should be a 'sync' command somewhere to\ndifferentiate these options from normal 'git fetch/push' commands.\n\nCheers.\n\n-- \nFelipe Contreras\n"},{"id":"179150","messageId":"7vvcquy05c.fsf@alter.siamese.dyndns.org","threadId":"28877","inReplyTo":"CAMP44s0vsQ5sfx8arrRDo+-g9Zff_MmCz5t+yghwCMx_pL4Xzg@mail.gmail.com","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-11-08T17:49:51Z","receivedAt":"2011-11-08T17:49:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Felipe Contreras <felipe.contreras@gmail.com> writes:\n\n> On Mon, Nov 7, 2011 at 11:25 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Jeff King <peff@peff.net> writes:\n>>\n>>> That makes sense. But I think it fits in with git's current UI to do\n>>> this via a combination of push options and refspecs. Even if we want to\n>>> wrap it in some \"git remote\" command for convenience, I think what\n>>> you're asking should be implemented as part of \"git push\".\n>>\n>> Yeah, I think it makes sense to give --prune to \"push\" just like \"fetch\"\n>> already has. These two are the primary (and in the ideal world, only)\n>> operations that talk to the outside world. \"remote add -f\" might have been\n>> a tempting \"convenience\" feature, but I personally think it probably was a\n>> mistake for the exact reason that letting anything but \"push\" and \"fetch\"\n>> talk to the outside world just invites more confusion. There does not have\n>> to be 47 different ways to do the same thing.\n>\n> What about 'git remote update'?\n\nIf you asked, I would have to say that is probably a worse mistake in the\nhindsight. I am guessing that back them \"remote\" command might have been a\ntool meant only for the read-only customers and the verb \"update\" may have\nmade sense as \"update me from the upstream\", but these days \"remote\" also\nhelps the aspect of pushing things out (e.g. \"set-url --push\"), so \"update\"\nthat does not specify the direction is totally an inappropriate verb.\n\nYou _could_ argue that adding subcommands and options related to pushing\nto \"git remote\" was a mistake. I don't care too much which side you would\nchoose to blame, but taken as the whole, in the current set of options,\nsubcommands and what \"git remote\" command does, \"update\" is a complete\nmisnomer.\n"},{"id":"179151","messageId":"CAMP44s0bm+bydNnMWPHpz8B8wMf6XN9LTiiCD-nrYSHGAV5c5Q@mail.gmail.com","threadId":"28877","inReplyTo":"7vvcquy05c.fsf@alter.siamese.dyndns.org","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2011-11-08T17:59:54Z","receivedAt":"2011-11-08T17:59:54Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"On Tue, Nov 8, 2011 at 7:49 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Felipe Contreras <felipe.contreras@gmail.com> writes:\n>\n>> On Mon, Nov 7, 2011 at 11:25 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>>> Jeff King <peff@peff.net> writes:\n>>>\n>>>> That makes sense. But I think it fits in with git's current UI to do\n>>>> this via a combination of push options and refspecs. Even if we want to\n>>>> wrap it in some \"git remote\" command for convenience, I think what\n>>>> you're asking should be implemented as part of \"git push\".\n>>>\n>>> Yeah, I think it makes sense to give --prune to \"push\" just like \"fetch\"\n>>> already has. These two are the primary (and in the ideal world, only)\n>>> operations that talk to the outside world. \"remote add -f\" might have been\n>>> a tempting \"convenience\" feature, but I personally think it probably was a\n>>> mistake for the exact reason that letting anything but \"push\" and \"fetch\"\n>>> talk to the outside world just invites more confusion. There does not have\n>>> to be 47 different ways to do the same thing.\n>>\n>> What about 'git remote update'?\n>\n> If you asked, I would have to say that is probably a worse mistake in the\n> hindsight. I am guessing that back them \"remote\" command might have been a\n> tool meant only for the read-only customers and the verb \"update\" may have\n> made sense as \"update me from the upstream\", but these days \"remote\" also\n> helps the aspect of pushing things out (e.g. \"set-url --push\"), so \"update\"\n> that does not specify the direction is totally an inappropriate verb.\n>\n> You _could_ argue that adding subcommands and options related to pushing\n> to \"git remote\" was a mistake. I don't care too much which side you would\n> choose to blame, but taken as the whole, in the current set of options,\n> subcommands and what \"git remote\" command does, \"update\" is a complete\n> misnomer.\n\nPerhaps these 'git remote' commands should be removed in 1.8 then.\n\n-- \nFelipe Contreras\n"},{"id":"179152","messageId":"20111108181442.GA17317@sigill.intra.peff.net","threadId":"28877","inReplyTo":"CAMP44s089xbEo4VT8rqgS=BJMUu=qsb8Hm5z8bTR2akU8-5QhA@mail.gmail.com","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-08T18:14:42Z","receivedAt":"2011-11-08T18:14:42Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Nov 08, 2011 at 07:31:09PM +0200, Felipe Contreras wrote:\n\n> >  2. update remote refs with local values, including pushing anything\n> >     new that we don't have locally (--sync-new)\n> \n> Anything new that we don't have *remotely*.\n\nSorry, yeah.\n\n> >  1. git push --prune <remote> :\n> >\n> >     I.e., use the \"matching\" refspec to not push new things, but turn\n> >     on pruning.\n> \n> I guess so, but \":\" seems a bit obscure.\n\nYeah, it is. It's also the default, so you could just do:\n\n  git push --prune <remote>\n\nAlthough some people have argued for changing the default in future\nversions. I don't know what the status of that is.\n\n> >  2. git push <remote> refs/heads/*\n> >\n> >     Turn off pruning, but use an explicit refspec, not just \"matching\",\n> >     which will push all local branches.\n> \n> Isn't refs/heads/* the same as --all? BTW. I think --all is confusing,\n> should be --branches, or something.\n\nDoesn't --all mean all refs, including tags and branches? I thought that\nwas the thing you were avoiding. We could add syntactic sugar to make\n--branches mean \"refs/heads/*\". But I do worry that pseudo-options like\nthat just end up creating more confusion (I seem to recall there being a\nlot of confusion about \"--tags\", which is more or less the same thing).\n\n-Peff\n"},{"id":"179193","messageId":"7vobwmvuei.fsf@alter.siamese.dyndns.org","threadId":"28877","inReplyTo":"CAMP44s0bm+bydNnMWPHpz8B8wMf6XN9LTiiCD-nrYSHGAV5c5Q@mail.gmail.com","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-11-09T03:36:53Z","receivedAt":"2011-11-09T03:36:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Felipe Contreras <felipe.contreras@gmail.com> writes:\n\n> Perhaps these 'git remote' commands should be removed in 1.8 then.\n\nIt is true that it was a long-term goal to deprecate many parts of the\n\"git remote\" script that started as a hack to scratch itches \"git fetch\"\nin the older days did not directly scratch for people, e.g. fetching from\nmultiple remotes in one go.\n\nI do not think 1.7.X series to 1.8 is a big enough jump to remove\nduplicated features, though.\n"},{"id":"179310","messageId":"m3wrb7lzg8.fsf@localhost.localdomain","threadId":"28877","inReplyTo":"7vobwmvuei.fsf@alter.siamese.dyndns.org","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2011-11-11T10:35:19Z","receivedAt":"2011-11-11T10:35:19Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n> Felipe Contreras <felipe.contreras@gmail.com> writes:\n> \n> > Perhaps these 'git remote' commands should be removed in 1.8 then.\n> \n> It is true that it was a long-term goal to deprecate many parts of the\n> \"git remote\" script that started as a hack to scratch itches \"git fetch\"\n> in the older days did not directly scratch for people, e.g. fetching from\n> multiple remotes in one go.\n> \n> I do not think 1.7.X series to 1.8 is a big enough jump to remove\n> duplicated features, though.\n \nI am using \"git remote update\" to fetch a _subset_ of remotes;\ndoes \"git fetch\" offers such feature already?\n\n-- \nJakub Narębski\n"},{"id":"179311","messageId":"CAMP44s2RjcFtdO2jft0Hg9RtqK-DRK47gX8By-dBFSBcSA+yFA@mail.gmail.com","threadId":"28877","inReplyTo":"20111108181442.GA17317@sigill.intra.peff.net","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2011-11-11T12:30:48Z","receivedAt":"2011-11-11T12:30:48Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"On Tue, Nov 8, 2011 at 8:14 PM, Jeff King <peff@peff.net> wrote:\n> On Tue, Nov 08, 2011 at 07:31:09PM +0200, Felipe Contreras wrote:\n>\n>> >  1. git push --prune <remote> :\n>> >\n>> >     I.e., use the \"matching\" refspec to not push new things, but turn\n>> >     on pruning.\n>>\n>> I guess so, but \":\" seems a bit obscure.\n>\n> Yeah, it is. It's also the default, so you could just do:\n>\n>  git push --prune <remote>\n\nThat would work only if not configured otherwise; remote.<foo>.push,\npush.default\n\n> Although some people have argued for changing the default in future\n> versions. I don't know what the status of that is.\n\nIMO the default doesn't matter, it should be easy for everyone.\n\n>> >  2. git push <remote> refs/heads/*\n>> >\n>> >     Turn off pruning, but use an explicit refspec, not just \"matching\",\n>> >     which will push all local branches.\n>>\n>> Isn't refs/heads/* the same as --all? BTW. I think --all is confusing,\n>> should be --branches, or something.\n>\n> Doesn't --all mean all refs, including tags and branches?\n\nNope, only branches, try it. I also found it strange. And what is\nmore, you can't use --all and --tags at the same time. Totally\nstrange.\n\nAlso, --all doesn't push other refs (say refs/foobar/test)\n\nI think this area has been neglected.\n\n> I thought that was the thing you were avoiding.\n\n--all + --tags is not the same as --mirror (refs/foobar/* is pushed\nonly by --mirror).\n\nAnd yes, in this particular use-case that's what I am trying to avoid,\nbut in other use-cases (like creating a new repo and pushing\n*everything*), a *true* --all would be nice.\n\n> We could add syntactic sugar to make\n> --branches mean \"refs/heads/*\". But I do worry that pseudo-options like\n> that just end up creating more confusion (I seem to recall there being a\n> lot of confusion about \"--tags\", which is more or less the same thing).\n\nBut it's not, that could explain part of the confusion. I think these\nwould be totally intuitive.\n\n --branches\n --tags\n --other\n --all\n --update\n --prune\n\nBut what about 'git fetch'? You didn't comment anything. I think we\nshould try to be consistent in these imaginary future options, maybe\nto devise a transition, or at least to identify good names for the new\noptions.\n\nCheers.\n\n-- \nFelipe Contreras\n"},{"id":"179320","messageId":"7vvcqqr4wg.fsf@alter.siamese.dyndns.org","threadId":"28877","inReplyTo":"m3wrb7lzg8.fsf@localhost.localdomain","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-11-11T16:38:07Z","receivedAt":"2011-11-11T16:38:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narebski <jnareb@gmail.com> writes:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n>> Felipe Contreras <felipe.contreras@gmail.com> writes:\n>> \n>> > Perhaps these 'git remote' commands should be removed in 1.8 then.\n>> \n>> It is true that it was a long-term goal to deprecate many parts of the\n>> \"git remote\" script that started as a hack to scratch itches \"git fetch\"\n>> in the older days did not directly scratch for people, e.g. fetching from\n>> multiple remotes in one go.\n>> \n>> I do not think 1.7.X series to 1.8 is a big enough jump to remove\n>> duplicated features, though.\n>  \n> I am using \"git remote update\" to fetch a _subset_ of remotes;\n> does \"git fetch\" offers such feature already?\n\nHeh, look at builtin/remote.c::update() and report what you see.  It just\ncalls into \"git fetch\" and let the command fetch either from a single\nrepository or from a remote group. \"git remote update\" is not even aware\nof the remote groups; the expansion is done by \"git fetch\".\n\nWhoever added \"multiple repositories\" feature to \"git fetch\" in order to\nsupport \"remote update <group>\" apparently under-documented it.\n"},{"id":"179322","messageId":"20111111181352.GA16055@sigill.intra.peff.net","threadId":"28877","inReplyTo":"CAMP44s2RjcFtdO2jft0Hg9RtqK-DRK47gX8By-dBFSBcSA+yFA@mail.gmail.com","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-11T18:13:52Z","receivedAt":"2011-11-11T18:13:52Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Nov 11, 2011 at 02:30:48PM +0200, Felipe Contreras wrote:\n\n> > Doesn't --all mean all refs, including tags and branches?\n> \n> Nope, only branches, try it. I also found it strange. And what is\n> more, you can't use --all and --tags at the same time. Totally\n> strange.\n\nYeah, you're right. Sorry for my confusion.\n\nSo in that sense, it is poorly named, and \"--branches\" (or \"--heads\")\nwould be more accurate. At the same time, it is probably more likely\nwhat the user wants to do (you almost never want to push \"refs/remotes\",\nfor example). So I am a little hesitant to suggest changing it, even\nwith a warning and deprecation period.\n\n> And yes, in this particular use-case that's what I am trying to avoid,\n> but in other use-cases (like creating a new repo and pushing\n> *everything*), a *true* --all would be nice.\n\nRight. It looks like that is just spelled \"--mirror\" (which gives you\npruning also), or \"refs/*:refs/*\" (without pruning). The latter is even\nmore flexible, as you could do \"refs/*:refs/foo/*\" to keep several\nrelated backups in one upstream repo.\n\nJust to get back to the original patch for a second: are we in agreement\nthat what you want to do with \"sync\" is almost possible now (modulo a\nseparate --prune option), and that there is a separate issue of making\nfriendlier syntax for a few common refspecs?\n\n> > We could add syntactic sugar to make\n> > --branches mean \"refs/heads/*\". But I do worry that pseudo-options like\n> > that just end up creating more confusion (I seem to recall there being a\n> > lot of confusion about \"--tags\", which is more or less the same thing).\n> \n> But it's not, that could explain part of the confusion. I think these\n> would be totally intuitive.\n> \n>  --branches\n>  --tags\n>  --other\n>  --all\n>  --update\n>  --prune\n\nMy problem with them syntactically is that you have option-looking\nthings that are really not flags, but rather syntactic placeholders for\nrefspecs. So you have:\n\n  git push --prune remote --branches\n\nwhich looks wrong from the perspective of usual option-parsing rules.\nAnd does:\n\n  git push remote --prune --branches\n\nwork? Or:\n\n  git push --prune --branches remote\n\n?\n\nI think we could make them all work if we want. But somehow the syntaxes\njust look wrong to me. Using a non-dashed placeholder for special\nrefspecs makes more sense to me like:\n\n  git push --prune remote BRANCHES\n\nand then it really is just a special way of spelling \"refs/heads/*\". But\nthen, I also think it's good for users to understand that the options\nare refspecs, and what that means. It's not a hard concept, and then\nwhen they inevitably say \"how can I do BRANCHES, except put the result\nsomewhere else in the remote namespace\", it's a very natural extension\nto learn about the right-hand side o the refspec.\n\nOf course I also think BRANCHES looks ugly, and people should just learn\n\"refs/heads/*\".\n\nI dunno. Maybe my brain is fried from knowing too much about how git\nworks. I don't have much of an \"ordinary user\" perspective anymore.\n\n> But what about 'git fetch'? You didn't comment anything. I think we\n> should try to be consistent in these imaginary future options, maybe\n> to devise a transition, or at least to identify good names for the new\n> options.\n\nYeah, fetch makes it harder because the options may have subtly\ndifferent meanings. Using non-option placeholders would work around\nthat. You would still have options for pruning, which to me is not\nreally a refspec, but an option that acts on the refspecs.\n\n>From the list in your previous email, you wrote:\n\n> --prune -> rename to --prune-tracking?\n> --prune-local (new; prune local branches that don't exist on the remote)\n\nI think --prune wouldn't need renaming. If you fetch into tracking\nbranches, then pruning would prune tracking branches. If you fetch as a\nmirror (refs/*:refs/*), then you would prune everything.\n\nAnd \"--prune-local\" doesn't seem like a fetch operation to me. Either\nyou are mirroring, and --prune already handles it as above. Or you are\ninterested in getting rid of branches whose upstream has gone away. But\nthat's not a fetch operation; that's a branch operation.\n\n-Peff\n"},{"id":"179336","messageId":"201111112300.31798.jnareb@gmail.com","threadId":"28877","inReplyTo":"7vvcqqr4wg.fsf@alter.siamese.dyndns.org","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2011-11-11T22:00:31Z","receivedAt":"2011-11-11T22:00:31Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"On Fri, 11 Nov 2011, Junio C Hamano wrote:\n> Jakub Narebski <jnareb@gmail.com> writes:\n>> Junio C Hamano <gitster@pobox.com> writes:\n>>> Felipe Contreras <felipe.contreras@gmail.com> writes:\n>>>> \n>>>> Perhaps these 'git remote' commands should be removed in 1.8 then.\n>>> \n>>> It is true that it was a long-term goal to deprecate many parts of the\n>>> \"git remote\" script that started as a hack to scratch itches \"git fetch\"\n>>> in the older days did not directly scratch for people, e.g. fetching from\n>>> multiple remotes in one go.\n>>> \n>>> I do not think 1.7.X series to 1.8 is a big enough jump to remove\n>>> duplicated features, though.\n>>  \n>> I am using \"git remote update\" to fetch a _subset_ of remotes;\n>> does \"git fetch\" offers such feature already?\n> \n> Heh, look at builtin/remote.c::update() and report what you see.  It just\n> calls into \"git fetch\" and let the command fetch either from a single\n> repository or from a remote group. \"git remote update\" is not even aware\n> of the remote groups; the expansion is done by \"git fetch\".\n> \n> Whoever added \"multiple repositories\" feature to \"git fetch\" in order to\n> support \"remote update <group>\" apparently under-documented it.\n\nWell, it is documented in git-fetch(1), though in slightly piecemeal\nfashion.\n\nOne difference is that \"git remote update\" defaults to \"default\" group\nif it is defined, and to \"--all\" if it isn't.  With \"git fetch --multiple\"\nyou have to specify it explicitly (\"git fetch --multiple\" is a no-op,\nI think).\n\n-- \nJakub Narebski\nPoland\n"},{"id":"179363","messageId":"CAMP44s06p+KyJAu4ddiCa8CFRq5eogbqxxJU16Z-SUb3GSp67Q@mail.gmail.com","threadId":"28877","inReplyTo":"20111111181352.GA16055@sigill.intra.peff.net","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2011-11-12T22:07:19Z","receivedAt":"2011-11-12T22:07:19Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"On Fri, Nov 11, 2011 at 8:13 PM, Jeff King <peff@peff.net> wrote:\n> On Fri, Nov 11, 2011 at 02:30:48PM +0200, Felipe Contreras wrote:\n>\n>> > Doesn't --all mean all refs, including tags and branches?\n>>\n>> Nope, only branches, try it. I also found it strange. And what is\n>> more, you can't use --all and --tags at the same time. Totally\n>> strange.\n>\n> Yeah, you're right. Sorry for my confusion.\n>\n> So in that sense, it is poorly named, and \"--branches\" (or \"--heads\")\n> would be more accurate. At the same time, it is probably more likely\n> what the user wants to do (you almost never want to push \"refs/remotes\",\n> for example).\n\nBut you do want to push tags, and --all --tags doesn't sound right; if\nI'm pushing everything, why do I specify I want to push more stuff.\nAnd then, why it --all --tags disallowed?\n\n> So I am a little hesitant to suggest changing it, even\n> with a warning and deprecation period.\n\nIt is confusing and wrong, what more reason do you need?\n\n>> And yes, in this particular use-case that's what I am trying to avoid,\n>> but in other use-cases (like creating a new repo and pushing\n>> *everything*), a *true* --all would be nice.\n>\n> Right. It looks like that is just spelled \"--mirror\" (which gives you\n> pruning also), or \"refs/*:refs/*\" (without pruning). The latter is even\n> more flexible, as you could do \"refs/*:refs/foo/*\" to keep several\n> related backups in one upstream repo.\n\nSo, we agree that --all is the same as 'refs/heads/*'. Therefore we\nalready have this mixture of refspecs and options.\n\n> Just to get back to the original patch for a second: are we in agreement\n> that what you want to do with \"sync\" is almost possible now (modulo a\n> separate --prune option), and that there is a separate issue of making\n> friendlier syntax for a few common refspecs?\n\nYes.\n\n>> > We could add syntactic sugar to make\n>> > --branches mean \"refs/heads/*\". But I do worry that pseudo-options like\n>> > that just end up creating more confusion (I seem to recall there being a\n>> > lot of confusion about \"--tags\", which is more or less the same thing).\n>>\n>> But it's not, that could explain part of the confusion. I think these\n>> would be totally intuitive.\n>>\n>>  --branches\n>>  --tags\n>>  --other\n>>  --all\n>>  --update\n>>  --prune\n>\n> My problem with them syntactically is that you have option-looking\n> things that are really not flags, but rather syntactic placeholders for\n> refspecs.\n\nWe already have those: --all -> 'ref/heads/*', --tags -> 'refs/tags/*'.\n\n> So you have:\n>\n>  git push --prune remote --branches\n>\n> which looks wrong from the perspective of usual option-parsing rules.\n> And does:\n>\n>  git push remote --prune --branches\n>\n> work? Or:\n>\n>  git push --prune --branches remote\n>\n> ?\n>\n> I think we could make them all work if we want. But somehow the syntaxes\n> just look wrong to me. Using a non-dashed placeholder for special\n> refspecs makes more sense to me like:\n\nI don't see any problem with making them all work.\n\n>  git push --prune remote BRANCHES\n>\n> and then it really is just a special way of spelling \"refs/heads/*\". But\n> then, I also think it's good for users to understand that the options\n> are refspecs, and what that means. It's not a hard concept, and then\n> when they inevitably say \"how can I do BRANCHES, except put the result\n> somewhere else in the remote namespace\", it's a very natural extension\n> to learn about the right-hand side o the refspec.\n>\n> Of course I also think BRANCHES looks ugly, and people should just learn\n> \"refs/heads/*\".\n\nLook, I'm all in favor of people learning stuff, but I have been\ninvolved in Git since basically day 1, and up to this day I was (am?)\nnot familiar with refspecs, I don't use them regularly, and never\nreally had a need to, and that's fine. People are already complaining\nabout the learning curve of git, and what you are suggesting is that:\n\nInstead of doing:\n% git push remote --branches --tags\n\nThey should do:\n% git push remote 'refs/heads/*' 'refs/tags/*'\n\nI disagree, I think refspecs should remain as plumbing, and there must\nbe a porcelain way to achieve the options I proposed.\n\n> I dunno. Maybe my brain is fried from knowing too much about how git\n> works. I don't have much of an \"ordinary user\" perspective anymore.\n\nMaybe :)\n\n>> But what about 'git fetch'? You didn't comment anything. I think we\n>> should try to be consistent in these imaginary future options, maybe\n>> to devise a transition, or at least to identify good names for the new\n>> options.\n>\n> Yeah, fetch makes it harder because the options may have subtly\n> different meanings. Using non-option placeholders would work around\n> that. You would still have options for pruning, which to me is not\n> really a refspec, but an option that acts on the refspecs.\n>\n> From the list in your previous email, you wrote:\n>\n>> --prune -> rename to --prune-tracking?\n>> --prune-local (new; prune local branches that don't exist on the remote)\n>\n> I think --prune wouldn't need renaming. If you fetch into tracking\n> branches, then pruning would prune tracking branches. If you fetch as a\n> mirror (refs/*:refs/*), then you would prune everything.\n\nI'm not going to investigate the subtleties of these different setups,\nI'm going to put my common user hat and ask; how do I fetch as a\nmirror?\n\n> And \"--prune-local\" doesn't seem like a fetch operation to me. Either\n> you are mirroring, and --prune already handles it as above. Or you are\n> interested in getting rid of branches whose upstream has gone away. But\n> that's not a fetch operation; that's a branch operation.\n\nThis would make things more confusing to the user.\n\nSay on one side I do this push?\n% git push test --prune 'refs/heads/*' 'refs/tags/*'\n\nWhat do I do in the other side to synchronize the repo?\n% git fetch test --prune-local 'refs/heads/*:refs/heads/*'\n'refs/tags/*:refs/tags/*'\n\nI would prefer this of course:\n% git fetch test --all --prune-local\n\nBut you are saying it should be:\n% git fetch test 'refs/heads/*:refs/heads/*' 'refs/tags/*:refs/tags/*'\n% git branch --prune-remote test\n\nThat doesn't sound right to me; mixing branch operations with a specific remote?\n\nAgain, I think conceptually it's much easier to think about these\noperations to be related to a specific remote, sure, fetch and push\nmostly deal with specific remotes, but even more 'git remote'.\n\n-- \nFelipe Contreras\n"},{"id":"179425","messageId":"20111114122556.GB19746@sigill.intra.peff.net","threadId":"28877","inReplyTo":"CAMP44s06p+KyJAu4ddiCa8CFRq5eogbqxxJU16Z-SUb3GSp67Q@mail.gmail.com","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-14T12:25:56Z","receivedAt":"2011-11-14T12:25:56Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Nov 13, 2011 at 12:07:19AM +0200, Felipe Contreras wrote:\n\n> > So in that sense, it is poorly named, and \"--branches\" (or \"--heads\")\n> > would be more accurate. At the same time, it is probably more likely\n> > what the user wants to do (you almost never want to push \"refs/remotes\",\n> > for example).\n> \n> But you do want to push tags, and --all --tags doesn't sound right; if\n> I'm pushing everything, why do I specify I want to push more stuff.\n> And then, why it --all --tags disallowed?\n\nI agree that \"--all --tags\" looks silly. I don't know why it's\ndisallowed; from my reading, it should be a perfectly sensible\noperation. You might try digging in the history or the mailing list.\n\n> > So I am a little hesitant to suggest changing it, even\n> > with a warning and deprecation period.\n> \n> It is confusing and wrong, what more reason do you need?\n\nBecause I am worried that \"--all\" pushing refs/remotes will also be\nconfusing; it's not what most people are going to want.\n\nIf your suggestion is to deprecate the name \"--all\" and start calling it\n\"--branches\" or \"--heads\", then that is an improvement. But making\n\"refs/*:refs/*\" easier to accidentally use might not be.\n\n> > Right. It looks like that is just spelled \"--mirror\" (which gives you\n> > pruning also), or \"refs/*:refs/*\" (without pruning). The latter is even\n> > more flexible, as you could do \"refs/*:refs/foo/*\" to keep several\n> > related backups in one upstream repo.\n> \n> So, we agree that --all is the same as 'refs/heads/*'. Therefore we\n> already have this mixture of refspecs and options.\n\nTrue. I wonder why there has been so much confusion over \"--tags\", and\nso little over \"--all\".\n\n> > and then it really is just a special way of spelling \"refs/heads/*\". But\n> > then, I also think it's good for users to understand that the options\n> > are refspecs, and what that means. It's not a hard concept, and then\n> > when they inevitably say \"how can I do BRANCHES, except put the result\n> > somewhere else in the remote namespace\", it's a very natural extension\n> > to learn about the right-hand side o the refspec.\n> >\n> > Of course I also think BRANCHES looks ugly, and people should just learn\n> > \"refs/heads/*\".\n> \n> Look, I'm all in favor of people learning stuff, but I have been\n> involved in Git since basically day 1, and up to this day I was (am?)\n> not familiar with refspecs, I don't use them regularly, and never\n> really had a need to, and that's fine. People are already complaining\n> about the learning curve of git, and what you are suggesting is that:\n> \n> Instead of doing:\n> % git push remote --branches --tags\n> \n> They should do:\n> % git push remote 'refs/heads/*' 'refs/tags/*'\n\nSorry, I should have been more clear with what I wrote. My \"of\ncourse...\" was more of a tangential \"well, this is so far from what my\ngut tells me is reasonable that I'm not sure my definition of ugly is\neven relevant here\".\n\nFor me personally as a user, I prefer learning how a tool actually works\nat its core (in this case, refspecs), and then applying syntactic sugar\nto simplify usage. But I also respect that not everybody feels that way.\n\n> I'm not going to investigate the subtleties of these different setups,\n> I'm going to put my common user hat and ask; how do I fetch as a\n> mirror?\n\nThe problem with that question is that you haven't defined mirror. Does\nthat mean you just want pruning, or does it mean that you want your\nlocal ref namespace to match that of the remote?\n\nGit should be able to do each of those cases. And I think it's fine to\nhave a less cumbersome syntax to specify them. But it's also important\nthat we don't over-simplify the terms so much that they get option A\nwhen they wanted B.\n\nBTW, right now there is \"git remote add --mirror ...\", which sets up the\nfetch refspec for you (in this case, mirror is \"make your refs look like\nthe remote's\"). Perhaps rather than adding syntactic sugar to fetch, it\nwould be best to channel users into configuring a remote that selects\nfrom one of a few common setups (including different types of mirrors).\n\nIt's not as flexible (I can't do a one-off mirrored push without using\nactual refspecs), but my guess is that most users would want to set up\nan actual remote, and picking from a set of configuration recipes would\nbe the ideal interface for them.\n\n> > And \"--prune-local\" doesn't seem like a fetch operation to me. Either\n> > you are mirroring, and --prune already handles it as above. Or you are\n> > interested in getting rid of branches whose upstream has gone away. But\n> > that's not a fetch operation; that's a branch operation.\n> \n> This would make things more confusing to the user.\n> \n> Say on one side I do this push?\n> % git push test --prune 'refs/heads/*' 'refs/tags/*'\n> \n> What do I do in the other side to synchronize the repo?\n> % git fetch test --prune-local 'refs/heads/*:refs/heads/*'\n> 'refs/tags/*:refs/tags/*'\n\nNo, you would just do \"--prune\", because your refspecs are _already_\nindicating that you are writing into the local namespace, and anything\nyou have locally would be deleted by the prune operation. I.e., there is\nno need for --prune-local in this scenario; --prune already does what we\nwant.\n\n> I would prefer this of course:\n> % git fetch test --all --prune-local\n> \n> But you are saying it should be:\n> % git fetch test 'refs/heads/*:refs/heads/*' 'refs/tags/*:refs/tags/*'\n> % git branch --prune-remote test\n> \n> That doesn't sound right to me; mixing branch operations with a specific remote?\n\nI was trying to outline a situation where \"--prune\" wouldn't be\nsufficient, which is:\n\n  : we make some topic branch based on another branch\n  $ git checkout -b topic-Y origin/topic-X\n\n  : later, we (or someone else) deletes topic-X upstream\n  $ git push origin :topic-X\n\n  : now we fetch using the regular default refspecs, which put\n  : everything in a separate remote. But we ask to prune, so that\n  : deleted branches will go away.\n  $ git fetch --prune origin\n\nNow origin/topic-X doesn't exist, even though it's configured as the\nupstream of topic-Y. Fetch doesn't enter into the picture, because it is\nconfigured to only touch items in refs/remotes/.\n\nAs a user, how do I resolve the situation? I might say topic-Y is\nobsolete and get rid of it. I might rebase it onto another branch. Or I\nmight declare it to have no upstream. But all of those are branch\noperations, not fetch operations.\n\nSo what I was trying to say was that either your fetch refspecs tell\nfetch to write into your local branch namespace, or not. If they do,\nthen --prune is sufficient (with no -local variant required). If not,\nthen touching your local branch namespace is outside the scope of fetch.\n\n-Peff\n"},{"id":"179428","messageId":"CAMP44s1G9jJyiis7z7XbPvW925E-u=0_-h9jJKkj2wyPS9o5ig@mail.gmail.com","threadId":"28877","inReplyTo":"20111114122556.GB19746@sigill.intra.peff.net","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2011-11-14T13:57:07Z","receivedAt":"2011-11-14T13:57:07Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"On Mon, Nov 14, 2011 at 2:25 PM, Jeff King <peff@peff.net> wrote:\n> On Sun, Nov 13, 2011 at 12:07:19AM +0200, Felipe Contreras wrote:\n>\n>> > So in that sense, it is poorly named, and \"--branches\" (or \"--heads\")\n>> > would be more accurate. At the same time, it is probably more likely\n>> > what the user wants to do (you almost never want to push \"refs/remotes\",\n>> > for example).\n>>\n>> But you do want to push tags, and --all --tags doesn't sound right; if\n>> I'm pushing everything, why do I specify I want to push more stuff.\n>> And then, why it --all --tags disallowed?\n>\n> I agree that \"--all --tags\" looks silly. I don't know why it's\n> disallowed; from my reading, it should be a perfectly sensible\n> operation. You might try digging in the history or the mailing list.\n\nYeah, I might do that.\n\n>> > So I am a little hesitant to suggest changing it, even\n>> > with a warning and deprecation period.\n>>\n>> It is confusing and wrong, what more reason do you need?\n>\n> Because I am worried that \"--all\" pushing refs/remotes will also be\n> confusing; it's not what most people are going to want.\n>\n> If your suggestion is to deprecate the name \"--all\" and start calling it\n> \"--branches\" or \"--heads\", then that is an improvement. But making\n> \"refs/*:refs/*\" easier to accidentally use might not be.\n\nThat's what I meant; replace --all with --branches (remember heads is\na plumbing name).\n\n>> > and then it really is just a special way of spelling \"refs/heads/*\". But\n>> > then, I also think it's good for users to understand that the options\n>> > are refspecs, and what that means. It's not a hard concept, and then\n>> > when they inevitably say \"how can I do BRANCHES, except put the result\n>> > somewhere else in the remote namespace\", it's a very natural extension\n>> > to learn about the right-hand side o the refspec.\n>> >\n>> > Of course I also think BRANCHES looks ugly, and people should just learn\n>> > \"refs/heads/*\".\n>>\n>> Look, I'm all in favor of people learning stuff, but I have been\n>> involved in Git since basically day 1, and up to this day I was (am?)\n>> not familiar with refspecs, I don't use them regularly, and never\n>> really had a need to, and that's fine. People are already complaining\n>> about the learning curve of git, and what you are suggesting is that:\n>>\n>> Instead of doing:\n>> % git push remote --branches --tags\n>>\n>> They should do:\n>> % git push remote 'refs/heads/*' 'refs/tags/*'\n>\n> Sorry, I should have been more clear with what I wrote. My \"of\n> course...\" was more of a tangential \"well, this is so far from what my\n> gut tells me is reasonable that I'm not sure my definition of ugly is\n> even relevant here\".\n>\n> For me personally as a user, I prefer learning how a tool actually works\n> at its core (in this case, refspecs), and then applying syntactic sugar\n> to simplify usage. But I also respect that not everybody feels that way.\n>\n>> I'm not going to investigate the subtleties of these different setups,\n>> I'm going to put my common user hat and ask; how do I fetch as a\n>> mirror?\n>\n> The problem with that question is that you haven't defined mirror. Does\n> that mean you just want pruning, or does it mean that you want your\n> local ref namespace to match that of the remote?\n\nExactly, no mirror has been defined, because I don't want a mirror. A\nmirror is supposed to have all the refs in sync all the time; that's\nnot what I want.\n\n> Git should be able to do each of those cases. And I think it's fine to\n> have a less cumbersome syntax to specify them. But it's also important\n> that we don't over-simplify the terms so much that they get option A\n> when they wanted B.\n>\n> BTW, right now there is \"git remote add --mirror ...\", which sets up the\n> fetch refspec for you (in this case, mirror is \"make your refs look like\n> the remote's\"). Perhaps rather than adding syntactic sugar to fetch, it\n> would be best to channel users into configuring a remote that selects\n> from one of a few common setups (including different types of mirrors).\n\nBut that assumes that they would want the same refspec operation *all\nthe time* which is not the case (at least for me). Sometimes I want to\nupdate only existing branches, sometimes I want to fetch new branches\ntoo, sometimes I want to prune local branches, sometimes not.\n\n> It's not as flexible (I can't do a one-off mirrored push without using\n> actual refspecs), but my guess is that most users would want to set up\n> an actual remote, and picking from a set of configuration recipes would\n> be the ideal interface for them.\n\nI don't think so. I doubt users would like a refspec that will delete\ntheir local branches *always*; sometimes they would want to prune the\nremote tracking branches.\n\n>> > And \"--prune-local\" doesn't seem like a fetch operation to me. Either\n>> > you are mirroring, and --prune already handles it as above. Or you are\n>> > interested in getting rid of branches whose upstream has gone away. But\n>> > that's not a fetch operation; that's a branch operation.\n>>\n>> This would make things more confusing to the user.\n>>\n>> Say on one side I do this push?\n>> % git push test --prune 'refs/heads/*' 'refs/tags/*'\n>>\n>> What do I do in the other side to synchronize the repo?\n>> % git fetch test --prune-local 'refs/heads/*:refs/heads/*'\n>> 'refs/tags/*:refs/tags/*'\n>\n> No, you would just do \"--prune\", because your refspecs are _already_\n> indicating that you are writing into the local namespace, and anything\n> you have locally would be deleted by the prune operation. I.e., there is\n> no need for --prune-local in this scenario; --prune already does what we\n> want.\n\nThat's very risky. The user might forget that this is a mirror repo,\nand delete the local branches unintentionally. Plus, it would be then\nimpossible to prune remote tracking branches.\n\n>> I would prefer this of course:\n>> % git fetch test --all --prune-local\n>>\n>> But you are saying it should be:\n>> % git fetch test 'refs/heads/*:refs/heads/*' 'refs/tags/*:refs/tags/*'\n>> % git branch --prune-remote test\n>>\n>> That doesn't sound right to me; mixing branch operations with a specific remote?\n>\n> I was trying to outline a situation where \"--prune\" wouldn't be\n> sufficient, which is:\n>\n>  : we make some topic branch based on another branch\n>  $ git checkout -b topic-Y origin/topic-X\n>\n>  : later, we (or someone else) deletes topic-X upstream\n>  $ git push origin :topic-X\n>\n>  : now we fetch using the regular default refspecs, which put\n>  : everything in a separate remote. But we ask to prune, so that\n>  : deleted branches will go away.\n>  $ git fetch --prune origin\n>\n> Now origin/topic-X doesn't exist, even though it's configured as the\n> upstream of topic-Y. Fetch doesn't enter into the picture, because it is\n> configured to only touch items in refs/remotes/.\n\nThat's only by default.\n\n> As a user, how do I resolve the situation? I might say topic-Y is\n> obsolete and get rid of it. I might rebase it onto another branch. Or I\n> might declare it to have no upstream. But all of those are branch\n> operations, not fetch operations.\n\nYes, but that has nothing to do with the operation I want to achieve:\ngit remote sync. By which I mean synchronize the local branches with\nthe branches of a certain remote.\n\nNote that in this sync operation, the upstream branch is irrelevant.\n\n> So what I was trying to say was that either your fetch refspecs tell\n> fetch to write into your local branch namespace, or not. If they do,\n> then --prune is sufficient (with no -local variant required). If not,\n> then touching your local branch namespace is outside the scope of fetch.\n\nI don't want this to be a *permanent* configuration. I see this\nsimilar to --force. You can achieve the same by adding a + at the\nbeginning of the refspec, but this is something that should be\nactivated on a per-command basis, thus the option. I think this should\nbe the same.\n\nCheers.\n\n-- \nFelipe Contreras\n"},{"id":"179802","messageId":"20111121214450.GA20338@sigill.intra.peff.net","threadId":"28877","inReplyTo":"CAMP44s1G9jJyiis7z7XbPvW925E-u=0_-h9jJKkj2wyPS9o5ig@mail.gmail.com","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-21T21:44:50Z","receivedAt":"2011-11-21T21:44:50Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Nov 14, 2011 at 03:57:07PM +0200, Felipe Contreras wrote:\n\n> >> I'm not going to investigate the subtleties of these different setups,\n> >> I'm going to put my common user hat and ask; how do I fetch as a\n> >> mirror?\n> >\n> > The problem with that question is that you haven't defined mirror. Does\n> > that mean you just want pruning, or does it mean that you want your\n> > local ref namespace to match that of the remote?\n> \n> Exactly, no mirror has been defined, because I don't want a mirror. A\n> mirror is supposed to have all the refs in sync all the time; that's\n> not what I want.\n\nI didn't mean \"you didn't define a mirror in your config\". I meant \"your\nquestion is not well-defined, because you haven't defined the term\n'mirror'\". IOW, I can't answer your question without knowing exactly\nwhat you meant.\n\n> > BTW, right now there is \"git remote add --mirror ...\", which sets up the\n> > fetch refspec for you (in this case, mirror is \"make your refs look like\n> > the remote's\"). Perhaps rather than adding syntactic sugar to fetch, it\n> > would be best to channel users into configuring a remote that selects\n> > from one of a few common setups (including different types of mirrors).\n> \n> But that assumes that they would want the same refspec operation *all\n> the time* which is not the case (at least for me). Sometimes I want to\n> update only existing branches, sometimes I want to fetch new branches\n> too, sometimes I want to prune local branches, sometimes not.\n\nOK, then that means it must be a fetch command-line thing, not a\nconfigured thing. Though note that even leaving prune out, I don't think\ngit does what you want (e.g., how are you fetching only to update\nexisting branches?).\n\n> > No, you would just do \"--prune\", because your refspecs are _already_\n> > indicating that you are writing into the local namespace, and anything\n> > you have locally would be deleted by the prune operation. I.e., there is\n> > no need for --prune-local in this scenario; --prune already does what we\n> > want.\n> \n> That's very risky. The user might forget that this is a mirror repo,\n> and delete the local branches unintentionally. Plus, it would be then\n> impossible to prune remote tracking branches.\n\nSorry, but I don't see how \"--prune\" is supposed to know what to prune\nexcept through the refspecs that have been provided to it (either in\nconfiguration or on the command line). So what is:\n\n  git fetch --prune <remote> refs/*:refs/*\n\n_supposed_ to do, if not prune your local namespace?\n\nI don't buy the \"it's too risky\" argument. You have configured a remote\nthat will fetch and overwrite your local branches already, if you ever\nrun \"git fetch foo\". But somehow running \"git fetch --prune foo\" is too\nrisky, because you might forget that it will delete all of your\nbranches?\n\n> > As a user, how do I resolve the situation? I might say topic-Y is\n> > obsolete and get rid of it. I might rebase it onto another branch. Or I\n> > might declare it to have no upstream. But all of those are branch\n> > operations, not fetch operations.\n> \n> Yes, but that has nothing to do with the operation I want to achieve:\n> git remote sync. By which I mean synchronize the local branches with\n> the branches of a certain remote.\n\nRight. I was only trying to explain a case where you would want to prune\nin the local namespace, when fetch is not configured to touch the local\nnamespace. Which is the only use case I could think of for something\nnamed --prune-local. But let's forget it. My point was that it is not\nrelated to fetch, and I was just guessing at what you might want from\n--prune-local.\n\n> > So what I was trying to say was that either your fetch refspecs tell\n> > fetch to write into your local branch namespace, or not. If they do,\n> > then --prune is sufficient (with no -local variant required). If not,\n> > then touching your local branch namespace is outside the scope of fetch.\n> \n> I don't want this to be a *permanent* configuration. I see this\n> similar to --force. You can achieve the same by adding a + at the\n> beginning of the refspec, but this is something that should be\n> activated on a per-command basis, thus the option. I think this should\n> be the same.\n\nThen you can tweak what is pruned on a per-command basis by providing\nalternate refspecs. Right now that would probably mean:\n\n  git fetch --prune <remote> refs/*:refs/*\n\nor\n\n  git fetch --prune <remote> refs/heads/*:refs/remotes/<remote>/*\n\nbut as we discussed earlier in the thread, those can be made less scary\nwith syntactic sugar.\n\n-Peff\n"},{"id":"179810","messageId":"CAMP44s3StLjb9KgBkRrG4nPqJD_ZjeSyFUwuP4A3b+mJKBgHWQ@mail.gmail.com","threadId":"28877","inReplyTo":"20111121214450.GA20338@sigill.intra.peff.net","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2011-11-21T23:47:36Z","receivedAt":"2011-11-21T23:47:36Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"On Mon, Nov 21, 2011 at 11:44 PM, Jeff King <peff@peff.net> wrote:\n> On Mon, Nov 14, 2011 at 03:57:07PM +0200, Felipe Contreras wrote:\n>\n>> >> I'm not going to investigate the subtleties of these different setups,\n>> >> I'm going to put my common user hat and ask; how do I fetch as a\n>> >> mirror?\n>> >\n>> > The problem with that question is that you haven't defined mirror. Does\n>> > that mean you just want pruning, or does it mean that you want your\n>> > local ref namespace to match that of the remote?\n>>\n>> Exactly, no mirror has been defined, because I don't want a mirror. A\n>> mirror is supposed to have all the refs in sync all the time; that's\n>> not what I want.\n>\n> I didn't mean \"you didn't define a mirror in your config\". I meant \"your\n> question is not well-defined, because you haven't defined the term\n> 'mirror'\". IOW, I can't answer your question without knowing exactly\n> what you meant.\n\nI wasn't the one that brought the mirror up, you did:\n\n> I think --prune wouldn't need renaming. If you fetch into tracking\n> branches, then pruning would prune tracking branches. If you fetch as a\n> mirror (refs/*:refs/*), then you would prune everything.\n\nSo you should know what you meant :)\n\n>> > BTW, right now there is \"git remote add --mirror ...\", which sets up the\n>> > fetch refspec for you (in this case, mirror is \"make your refs look like\n>> > the remote's\"). Perhaps rather than adding syntactic sugar to fetch, it\n>> > would be best to channel users into configuring a remote that selects\n>> > from one of a few common setups (including different types of mirrors).\n>>\n>> But that assumes that they would want the same refspec operation *all\n>> the time* which is not the case (at least for me). Sometimes I want to\n>> update only existing branches, sometimes I want to fetch new branches\n>> too, sometimes I want to prune local branches, sometimes not.\n>\n> OK, then that means it must be a fetch command-line thing, not a\n> configured thing. Though note that even leaving prune out, I don't think\n> git does what you want (e.g., how are you fetching only to update\n> existing branches?).\n\nIt should be possible to do a git fetch, so the remote tracking\nbranches are updated, and then compare those with the local ones. This\nmight not feel natural under 'git fetch' which is why I decided to use\n'git remote sync'.\n\n>> > No, you would just do \"--prune\", because your refspecs are _already_\n>> > indicating that you are writing into the local namespace, and anything\n>> > you have locally would be deleted by the prune operation. I.e., there is\n>> > no need for --prune-local in this scenario; --prune already does what we\n>> > want.\n>>\n>> That's very risky. The user might forget that this is a mirror repo,\n>> and delete the local branches unintentionally. Plus, it would be then\n>> impossible to prune remote tracking branches.\n>\n> Sorry, but I don't see how \"--prune\" is supposed to know what to prune\n> except through the refspecs that have been provided to it (either in\n> configuration or on the command line). So what is:\n\nThat's why I suggested --prune-local.\n\n>  git fetch --prune <remote> refs/*:refs/*\n>\n> _supposed_ to do, if not prune your local namespace?\n\nI thought 'git fetch --prune <remote_mirror>' would not prune the\nlocal branches, but now I see that it does (currently), so nevermind.\n\n>> > As a user, how do I resolve the situation? I might say topic-Y is\n>> > obsolete and get rid of it. I might rebase it onto another branch. Or I\n>> > might declare it to have no upstream. But all of those are branch\n>> > operations, not fetch operations.\n>>\n>> Yes, but that has nothing to do with the operation I want to achieve:\n>> git remote sync. By which I mean synchronize the local branches with\n>> the branches of a certain remote.\n>\n> Right. I was only trying to explain a case where you would want to prune\n> in the local namespace, when fetch is not configured to touch the local\n> namespace. Which is the only use case I could think of for something\n> named --prune-local. But let's forget it. My point was that it is not\n> related to fetch, and I was just guessing at what you might want from\n> --prune-local.\n\nBasically 'git fetch --prune <remote> refs/*:refs/*', when the remote\nis not configured as a mirror. But it would be nice to prune the\nbranches without having to update the local ones (for whatever\nreason).\n\n>> > So what I was trying to say was that either your fetch refspecs tell\n>> > fetch to write into your local branch namespace, or not. If they do,\n>> > then --prune is sufficient (with no -local variant required). If not,\n>> > then touching your local branch namespace is outside the scope of fetch.\n>>\n>> I don't want this to be a *permanent* configuration. I see this\n>> similar to --force. You can achieve the same by adding a + at the\n>> beginning of the refspec, but this is something that should be\n>> activated on a per-command basis, thus the option. I think this should\n>> be the same.\n>\n> Then you can tweak what is pruned on a per-command basis by providing\n> alternate refspecs. Right now that would probably mean:\n>\n>  git fetch --prune <remote> refs/*:refs/*\n>\n> or\n>\n>  git fetch --prune <remote> refs/heads/*:refs/remotes/<remote>/*\n>\n> but as we discussed earlier in the thread, those can be made less scary\n> with syntactic sugar.\n\nIndeed, but those commands will also update the local branches.\n\n-- \nFelipe Contreras\n"},{"id":"180139","messageId":"20111130070111.GE5317@sigill.intra.peff.net","threadId":"28877","inReplyTo":"CAMP44s3StLjb9KgBkRrG4nPqJD_ZjeSyFUwuP4A3b+mJKBgHWQ@mail.gmail.com","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-30T07:01:11Z","receivedAt":"2011-11-30T07:01:11Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Nov 22, 2011 at 01:47:36AM +0200, Felipe Contreras wrote:\n\n> > I didn't mean \"you didn't define a mirror in your config\". I meant \"your\n> > question is not well-defined, because you haven't defined the term\n> > 'mirror'\". IOW, I can't answer your question without knowing exactly\n> > what you meant.\n> \n> I wasn't the one that brought the mirror up, you did:\n\nYes, because that is the most related concept in current git. But I\nthought you were asking from the perspective of a clueless user, and I\ndon't know what that clueless user meant by \"mirror\".\n\nAnyway, I don't think it's important.\n\nI read over your whole message, and I feel like our discussion isn't\nreally moving towards an actual goal. Junio and I both mentioned that in\nthe long-term, features like this should be part of \"push\", not\n\"remote\". Do you want to try revising your patch in that direction?\nThat will give us something concrete to talk about (and hopefully\napply).\n\n-Peff\n"},{"id":"180151","messageId":"CAMP44s2WxveGAmzaz8kwKRxia1TBWYwxwPBdb14K93TKr1sfsA@mail.gmail.com","threadId":"28877","inReplyTo":"20111130070111.GE5317@sigill.intra.peff.net","subject":"Re: [RFC/PATCH] remote: add new sync command","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2011-11-30T11:47:24Z","receivedAt":"2011-11-30T11:47:24Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"On Wed, Nov 30, 2011 at 9:01 AM, Jeff King <peff@peff.net> wrote:\n> On Tue, Nov 22, 2011 at 01:47:36AM +0200, Felipe Contreras wrote:\n>\n>> > I didn't mean \"you didn't define a mirror in your config\". I meant \"your\n>> > question is not well-defined, because you haven't defined the term\n>> > 'mirror'\". IOW, I can't answer your question without knowing exactly\n>> > what you meant.\n>>\n>> I wasn't the one that brought the mirror up, you did:\n>\n> Yes, because that is the most related concept in current git. But I\n> thought you were asking from the perspective of a clueless user, and I\n> don't know what that clueless user meant by \"mirror\".\n\nI don't think common users know, or should care about, what a \"mirror\" is.\n\n> Anyway, I don't think it's important.\n\nMe neither.\n\n> I read over your whole message, and I feel like our discussion isn't\n> really moving towards an actual goal. Junio and I both mentioned that in\n> the long-term, features like this should be part of \"push\", not\n> \"remote\". Do you want to try revising your patch in that direction?\n\nYes, I can try that for 'git push', but my worry is about 'git fetch'.\nTo me it's really clear that what I am trying to achieve is more\ncomplicated than a simple push/fetch.\n\nYou still haven't replied to my solution to synchronize the local\nbranches, which to first do a 'git fetch' so we have the remote\nbranches tracked locally, and go through each one of them and do\nsomething to the local ones. This solution works, is simple, and\nallows all kinds of options, but IMO it's not part of 'git fetch'.\n\n> That will give us something concrete to talk about (and hopefully\n> apply).\n\nYes, but that's basically 'git push --prune', which I think is the\nonly thing we have agreed. But what about the rest?\n\nI feel you are trying to ignore the fact that 'refs/heads/*' is not\nuser-friendly, neither is BRANCHES, or :, and 'git fetch' would be\neven more cumbersome.\n\nThe user-friendliness of git is one of the biggest complains people\nhave, and while it makes sense to keep certain operations under\npush/fetch, there's only so much pureness we can have before things\nbecome too complicated for the users. The fact of the matter is that\nthese particular remote synchronization operations are much easier to\npicture mentally in a group like 'git remote sync'. That not only\nworks for all the cases, including 'git fetch', but it's\nnon-intrusive, and most importantly: user-friendly.\n\nCheers.\n\n-- \nFelipe Contreras\n"}]}