{"thread":{"id":"61187","subject":"Inconsistent/buggy behaviour of \"git config --add\"","startedAt":"2024-03-23T16:39:38Z","lastAt":"2024-03-25T18:56:59Z","messageCount":6,"participants":["Tim Landscheidt","Junio C Hamano","brian m. carlson","Patrick Steinhardt"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"491302","messageId":"87o7b5dj8h.fsf@vagabond.tim-landscheidt.de","threadId":"61187","inReplyTo":null,"subject":"Inconsistent/buggy behaviour of \"git config --add\"","fromName":"Tim Landscheidt","fromEmail":"tim@tim-landscheidt.de","sentAt":"2024-03-23T16:07:58Z","receivedAt":"2024-03-23T16:39:38Z","isPatch":false,"sender":{"key":"tim@tim-landscheidt.de","avatar":null},"body":"Hi,\n\nwith Git 2.44.0 on Fedora 39, the behaviour of \"git config\n--add\", i. e., adding multiple lines to a configuration key,\nis inconsistent and/or buggy:\n\n| # git config section.key value0\n| # git config --add section.key value1\n| # cat .git/config\n| [core]\n|         repositoryformatversion = 0\n|         filemode = true\n|         bare = false\n|         logallrefupdates = true\n| [section]\n|         key = value0\n|         key = value1\n| # git config section.key --add value2\n| # cat .git/config\n| [core]\n|         repositoryformatversion = 0\n|         filemode = true\n|         bare = false\n|         logallrefupdates = true\n| [section]\n|         key = value0\n|         key = value1\n|         key = --add\n| # git config section.key --add\n| warning: section.key has multiple values\n| error: cannot overwrite multiple values with a single value\n|        Use a regexp, --add or --replace-all to change section.key.\n| #\n\nSo on one hand, \"--add\" must be given before the key to add\na line, but if on the other hand one passes the option after\nthe key and before the value, it is literally taken as the\nvalue and the value does not seem to be interpreted as a\nvalue-pattern, either.  However, if the value is missing,\nGit correctly recognizes that this does not make sense.\n\nMy expectation of least surprise is that \"git config\nsection.key --add value\" should be equivalent to \"git config\n--add section.key value\".\n\nIf that is not possible, I would expect \"git config\nsection.key --add value2\" to mean \"change the values of\nsection.key to '--add' where they currently match the\nvalue-pattern of 'value2'\".\n\nTim\n"},{"id":"491307","messageId":"xmqq8r28ygwi.fsf@gitster.g","threadId":"61187","inReplyTo":"87o7b5dj8h.fsf@vagabond.tim-landscheidt.de","subject":"Re: Inconsistent/buggy behaviour of \"git config --add\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-03-23T17:52:45Z","receivedAt":"2024-03-23T17:52:53Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Tim Landscheidt <tim@tim-landscheidt.de> writes:\n\n> | # git config section.key value0\n> | # git config --add section.key value1\n\nThe action verb --add comes immediately after \"git config\" (and\npossibly file-option and type option), so this is a request to\nappend \"key = value1\" in the \"[section]\" (if there is no existing\nsection.key, then \"[section]\" would have to be created at the same\ntime, but in this case there already is one).\n\n> | # cat .git/config\n> | [core]\n> |         repositoryformatversion = 0\n> |         filemode = true\n> |         bare = false\n> |         logallrefupdates = true\n> | [section]\n> |         key = value0\n> |         key = value1\n\nSo this makes perfect sense.\n\n> | # git config section.key --add value2\n\nNo action verb immediately after \"git config\" (possibly after\nfile-option and type option).  This should be taken as\n\n    git config <name> <value> <value-pattern>\n\nwhere\n\n    <name> = section.key\n    <value> = --add\n    <value-pattern> = value2\n\nAs we lack --replace-all, the default behaviour is to replace a\nsingle existing entry of \"section.key\" with existing value \"value2\",\nwith the new value \"--add\", or if there is no such existing entry,\nadd one such entry.\n\n> | # cat .git/config\n> | [core]\n> |         repositoryformatversion = 0\n> |         filemode = true\n> |         bare = false\n> |         logallrefupdates = true\n> | [section]\n> |         key = value0\n> |         key = value1\n> |         key = --add\n\nwhich seems to be what the code did.\n\n> | # git config section.key --add\n\nNo action verb immediately after \"git config\" (possibly after\nfile-option and type option).  This should be taken as\n\n    git config <name> <value>\n\nwhere\n\n    <name> = section.key\n    <value> = --add\n\nand is an attempt to replace existing section.key with the new value\n\"--add\", but because we have already three such entries, we get \n\n> | warning: section.key has multiple values\n> | error: cannot overwrite multiple values with a single value\n> |        Use a regexp, --add or --replace-all to change section.key.\n> | #\n\nwhich sounds sensible.\n\n> So on one hand, \"--add\" must be given before the key to add\n> a line, but if on the other hand one passes the option after\n> the key and before the value, it is literally taken as the\n> value and the value does not seem to be interpreted as a\n> value-pattern, either.  However, if the value is missing,\n> Git correctly recognizes that this does not make sense.\n\nNot really.  I agree that the \"git config\" syntax is messy, but I\nfollowed your example with \"git config --help\" (especially its\nSYNOPSIS section) in hand, and reached the above explanation, which\nyour conjecutre does not quite match.\n\n> My expectation of least surprise is that \"git config\n> section.key --add value\" should be equivalent to \"git config\n> --add section.key value\".\n\nYou cannot have \"--add\" as a value by doing so.\n\n> If that is not possible, I would expect \"git config\n> section.key --add value2\" to mean \"change the values of\n> section.key to '--add' where they currently match the\n> value-pattern of 'value2'\".\n\nI think your expectation needs to be updated in this particular\ncase, but there is a discussion to revamp the UI started elsewhere,\nwhich stops the double-dashed action verbs and instead trigger\ndifferent actions as subcommands of \"git config\", which will\nhopefully make things easier to understand.\n"},{"id":"491375","messageId":"87o7b3xxta.fsf@vagabond.tim-landscheidt.de","threadId":"61187","inReplyTo":"xmqq8r28ygwi.fsf@gitster.g","subject":"Re: Inconsistent/buggy behaviour of \"git config --add\"","fromName":"Tim Landscheidt","fromEmail":"tim@tim-landscheidt.de","sentAt":"2024-03-24T18:57:21Z","receivedAt":"2024-03-24T18:57:32Z","isPatch":false,"sender":{"key":"tim@tim-landscheidt.de","avatar":null},"body":"Junio C Hamano <gitster@pobox.com> wrote:\n\n> […]\n\n>> So on one hand, \"--add\" must be given before the key to add\n>> a line, but if on the other hand one passes the option after\n>> the key and before the value, it is literally taken as the\n>> value and the value does not seem to be interpreted as a\n>> value-pattern, either.  However, if the value is missing,\n>> Git correctly recognizes that this does not make sense.\n\n> Not really.  I agree that the \"git config\" syntax is messy, but I\n> followed your example with \"git config --help\" (especially its\n> SYNOPSIS section) in hand, and reached the above explanation, which\n> your conjecutre does not quite match.\n\nI respectfully disagree (somewhat).  git-config(1) reads:\n\n| […]\n\n|        Multiple lines can be added to an option by using\n|        the --add option. If you want to update or unset an\n|        option which can occur on multiple lines, a\n|        value-pattern (which is an extended regular\n|        expression, unless the --fixed-value option is\n|        given) needs to be given. Only the existing values\n|        that match the pattern are updated or unset. If you\n|        want to handle the lines that do not match the\n|        pattern, just prepend a single exclamation mark in\n|        front (see also the section called “EXAMPLES”), but\n|        note that this only works when the --fixed-value\n|        option is not in use.\n\n| […]\n\n|        --replace-all\n|            Default behavior is to replace at most one\n|            line. This replaces all lines matching the key\n|            (and optionally the value-pattern).\n\nThis says quite clearly if one wants to /add/ a value,\n\"--add\" must be given; the default is to /replace/ an\nexisting value.\n\nThe only indication that this might be false is the\ndescription of \"--add\" itself which gives another and\ndifferent explanation for the behaviour of \"--replace-all\":\n\n|        --add\n|            Adds a new line to the option without altering\n|            any existing values. This is the same as\n|            providing ^$ as the value-pattern in\n|            --replace-all.\n\n| […]\n\nSo the first section states that \"only the existing values\nthat match the pattern are updated or unset\", and here it\nsays that if there are no matches, a new line is added.\n\n>> My expectation of least surprise is that \"git config\n>> section.key --add value\" should be equivalent to \"git config\n>> --add section.key value\".\n\n> You cannot have \"--add\" as a value by doing so.\n\n> […]\n\nThe standard way to achieve this would be to use \"--\",\ni. e. \"git config section.key --add -- --add\" (apparently\neven part of POSIX as \"Utility Syntax Guidelines\", but also\ncommonly used elsewhere in Git).\n\nTim\n"},{"id":"491387","messageId":"ZgDF3uIEYNbawplE@tapette.crustytoothpaste.net","threadId":"61187","inReplyTo":"87o7b3xxta.fsf@vagabond.tim-landscheidt.de","subject":"Re: Inconsistent/buggy behaviour of \"git config --add\"","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2024-03-25T00:31:26Z","receivedAt":"2024-03-25T00:31:29Z","isPatch":false,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On 2024-03-24 at 18:57:21, Tim Landscheidt wrote:\n> Junio C Hamano <gitster@pobox.com> wrote:\n> >> My expectation of least surprise is that \"git config\n> >> section.key --add value\" should be equivalent to \"git config\n> >> --add section.key value\".\n> \n> > You cannot have \"--add\" as a value by doing so.\n> \n> > […]\n> \n> The standard way to achieve this would be to use \"--\",\n> i. e. \"git config section.key --add -- --add\" (apparently\n> even part of POSIX as \"Utility Syntax Guidelines\", but also\n> commonly used elsewhere in Git).\n\nPOSIX mandates that all options come before all non-option arguments.\nSo by that rule, `git config section.key --add value` means that `--add`\nis a non-option argument, not the option `--add`.\n\nCertainly some GNU tools do break the rule, and Git begrudgingly allows\nit in some cases, but in utilities in general, it isn't allowed.  Many\nnon-Linux OSes and non-GNU tools don't allow options to appear after\nnon-option arguments at all.\n-- \nbrian m. carlson (they/them or he/him)\nToronto, Ontario, CA\n"},{"id":"491395","messageId":"ZgEnqE23PYVCNeKc@tanuki","threadId":"61187","inReplyTo":"87o7b3xxta.fsf@vagabond.tim-landscheidt.de","subject":"Re: Inconsistent/buggy behaviour of \"git config --add\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-03-25T07:28:40Z","receivedAt":"2024-03-25T07:28:46Z","isPatch":false,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Sun, Mar 24, 2024 at 06:57:21PM +0000, Tim Landscheidt wrote:\n> Junio C Hamano <gitster@pobox.com> wrote:\n[snip]\n> >> My expectation of least surprise is that \"git config\n> >> section.key --add value\" should be equivalent to \"git config\n> >> --add section.key value\".\n> \n> > You cannot have \"--add\" as a value by doing so.\n> \n> > […]\n> \n> The standard way to achieve this would be to use \"--\",\n> i. e. \"git config section.key --add -- --add\" (apparently\n> even part of POSIX as \"Utility Syntax Guidelines\", but also\n> commonly used elsewhere in Git).\n\nI think the whole design of git-config(1) is just not great, and I'm not\nsurprised at all that folks run into issues like the one you describe\nhere. I agree that it is quite surprising that modes like \"--add\" look\nlike a flag, but don't really behave like one in the general case.\n\nThis is part of the reason why I have recently proposed to convert this\ncommand to use proper subcommands [1]. This introduces things like `git\nconfig set`, `git config list`, `git config get`, `git config unset`\nthat (in my opinion) behave a lot more obvious. Also, I certainly agree\nwith you that those subcommands should respect \"--\" as many other of our\nGit commands already do.\n\nI plan to reroll this patch series soonish. Please feel free to provide\nyour feedback on it so that we can iterate on the proposed UI/UX and\nmake it match user's expectations better.\n\nPatrick\n\n[1]: https://lore.kernel.org/git/cover.1710198711.git.ps@pks.im/\n"},{"id":"491490","messageId":"xmqqy1a6jg1z.fsf@gitster.g","threadId":"61187","inReplyTo":"ZgEnqE23PYVCNeKc@tanuki","subject":"Re: Inconsistent/buggy behaviour of \"git config --add\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-03-25T18:56:56Z","receivedAt":"2024-03-25T18:56:59Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> I plan to reroll this patch series soonish. Please feel free to provide\n> your feedback on it so that we can iterate on the proposed UI/UX and\n> make it match user's expectations better.\n\n;-)\n"}]}