{"thread":{"id":"28472","subject":"config-file includes","startedAt":"2011-09-23T19:58:29Z","lastAt":"2011-09-27T02:38:45Z","messageCount":8,"participants":["Jeff King","Nguyen Thai Ngoc Duy","David Aguilar","Junio C Hamano","Jay Soffian"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"176096","messageId":"20110923195829.GA27677@sigill.intra.peff.net","threadId":"28472","inReplyTo":null,"subject":"config-file includes","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-09-23T19:58:29Z","receivedAt":"2011-09-23T19:58:29Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Sep 23, 2011 at 03:33:41PM -0400, Jeff King wrote:\n\n> [1] I really wish we had an elegant way of versioning meta-information\n>     about a repository (like config, info/attributes, etc). I've hacked\n>     around this before by having a special meta-branch for each repo,\n>     checkout it out in an alternate directory, and then symlinking bits\n>     of it into .git. But that's kind of ugly, too.\n> \n>     I'm not sure what a good solution would look like. There's a real\n>     can of worms with respect to picking and choosing local versus\n>     remote bits of meta-information, with some security implications.\n\nHere's one solution I've given a little thought to. Comments welcome.\n\nI've sometimes wanted an \"include\" mechanism in git config files.\nPartially to just keep things tidier, partially to avoid\ncutting-and-pasting between some repo-specific config, and partially\nbecause I'd like a conditional inclusion mechanism[1]. I was thinking of\nsomething that would be syntactically compatible but semantically\nmeaningless in current versions of git, like:\n\n  [include]\n  path = /some/file\n  path = /some/other/file\n  path = ~/some/file/in/your/homedir\n\nYou could extend this to look in refs, with something like:\n\n  [include]\n  ref = meta:config\n\nwhich would resolve meta:config to a blob and examine it (i.e., it would\nlook at refs/heads/meta).\n\nSo the procedure for importing and updating config from a remote would\nlook like:\n\n  git clone project.git\n  cd project\n\n  # check that the upstream config looks good\n  git show origin/meta:config\n  # if so, use it\n  git branch meta origin/meta\n  git config --add include.ref meta:config\n\n  # later, check updates to upstream's config\n  git fetch\n  git diff meta origin/meta -- config\n  # looks ok, use it\n  git branch -f meta origin/meta\n\nAnd obviously if you wanted to streamline that, you could make \"meta\"\nand \"config\" well-known names and have clone and fetch interactively\nshow the config and say \"do you want this [y/N]?\" or something. Though I\nthink there is some value to doing it manually, as it gives projects the\nflexibility to have different config profiles in their meta branch.\n\nAnd if you really wanted to live dangerously, you could do:\n\n  git config --add include.ref origin/meta:config\n\nThat of course just covers \"config\". But I think you might be able to do\nsomething similar with core.attributesfile (which could be included from\nthe config).\n\n-Peff\n\n[1] I want conditional inclusion because sometimes the rules for config\n    entries changes from version to version. For example, I have\n    pager.diff set to a script in my ~/.gitconfig. But older versions of\n    git don't understand non-boolean values and barf. I'd really like to\n    do something like:\n\n    [include-ifdef \"has-pager-scripts\"]\n    path = ~/.gitconfig-pager\n\n    where \"has-pager-scripts\" would be a magic flag compiled into git\n    versions that understand that config.\n"},{"id":"176196","messageId":"CACsJy8BAVRAct=sxTpZ+b-ft1OjbY9oZG6uEXrcsTXw3CXnwSg@mail.gmail.com","threadId":"28472","inReplyTo":"20110923195829.GA27677@sigill.intra.peff.net","subject":"Re: config-file includes","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-09-26T10:45:58Z","receivedAt":"2011-09-26T10:45:58Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sat, Sep 24, 2011 at 5:58 AM, Jeff King <peff@peff.net> wrote:\n> Here's one solution I've given a little thought to. Comments welcome.\n>\n> I've sometimes wanted an \"include\" mechanism in git config files.\n> Partially to just keep things tidier, partially to avoid\n> cutting-and-pasting between some repo-specific config, and partially\n> because I'd like a conditional inclusion mechanism[1]. I was thinking of\n> something that would be syntactically compatible but semantically\n> meaningless in current versions of git, like:\n>\n>  [include]\n>  path = /some/file\n>  path = /some/other/file\n>  path = ~/some/file/in/your/homedir\n>\n> You could extend this to look in refs, with something like:\n>\n>  [include]\n>  ref = meta:config\n>\n> which would resolve meta:config to a blob and examine it (i.e., it would\n> look at refs/heads/meta).\n\nI had something similar [1], although I disregarded worktree content\ncompletely. One thing about this meta thing is fsck/prune must dig in\nconfig file in order not to accidentally remove something config file\nrefers to.\n\nAnother thing is, what if I want to exclude certain part of the included config?\n\n[1] http://thread.gmane.org/gmane.comp.version-control.git/163285/focus=163288\n\n> [1] I want conditional inclusion because sometimes the rules for config\n>    entries changes from version to version. For example, I have\n>    pager.diff set to a script in my ~/.gitconfig. But older versions of\n>    git don't understand non-boolean values and barf. I'd really like to\n>    do something like:\n>\n>    [include-ifdef \"has-pager-scripts\"]\n>    path = ~/.gitconfig-pager\n>\n>    where \"has-pager-scripts\" would be a magic flag compiled into git\n>    versions that understand that config.\n\nBut how far would you go with conditional expressions?\n-- \nDuy\n"},{"id":"176199","messageId":"20110926123620.GA30336@sigill.intra.peff.net","threadId":"28472","inReplyTo":"CACsJy8BAVRAct=sxTpZ+b-ft1OjbY9oZG6uEXrcsTXw3CXnwSg@mail.gmail.com","subject":"Re: config-file includes","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-09-26T12:36:20Z","receivedAt":"2011-09-26T12:36:20Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Sep 26, 2011 at 08:45:58PM +1000, Nguyen Thai Ngoc Duy wrote:\n\n> > You could extend this to look in refs, with something like:\n> >\n> >  [include]\n> >  ref = meta:config\n> >\n> > which would resolve meta:config to a blob and examine it (i.e., it would\n> > look at refs/heads/meta).\n> \n> I had something similar [1], although I disregarded worktree content\n> completely.\n\nThanks, I had totally missed that thread.\n\nMaybe it wasn't clear from my proposal, but I intend to disregard the\nworktree entirely, too. The include.path was about including stuff from\nthe local filesystem, not necessarily your worktree.\n\n> One thing about this meta thing is fsck/prune must dig in\n> config file in order not to accidentally remove something config file\n> refers to.\n\nIt is only a connectivity problem if you put a raw sha1 in the config.\nIt seems much more sensible to me to use a real ref. That solves the\nfsck issue, and it makes it easier to manipulate the contents using git.\n\n> Another thing is, what if I want to exclude certain part of the included config?\n\n  git show origin/meta:config ;# review upstream\n  git checkout meta origin/meta\n  $EDITOR config\n  git commit -a -m 'tweak my config based on upstream'\n  git config include.ref meta:config\n\n  [weeks later]\n  git fetch ;# oh, new config from upstream\n  git log -p origin/meta@{1}...origin/meta ;# looks good to me\n  git checkout meta\n  git merge origin/meta\n\nJunio raised a good point in the thread you referenced: why is this any\nbetter than the project just shipping a \"./setup-config\" script that you\nrun (and re-run when there is an update). Two things I can think of:\n\n  1. Carrying it in the project tree (as opposed to a separate ref) is\n     annoying. It bloats your project tree, and any changes you make\n     get tangled up in the changes you're making to the project itself.\n     To me, they're logically separate entities.\n\n     You can still keep a separate \"meta\" ref that has the setup-config\n     script in it, though. That wouldn't need git support at all.\n     But...\n\n  2. Using a script to deploy the config makes it annoying to track\n     changes. If I make local tweaks to what upstream suggests for the\n     config, I would want those tracked by git. And when upstream makes\n     a change, I want to do a 3-way merge. So either my script must be\n     clever in deploying, or I must never touch the deployed .git/config\n     file, and instead edit the setup-config script. Even then, how does\n     it handle changes in .git/config that happen naturally (e.g.,\n     branch config written by git).\n\nIf we had even a mechanism to include regular files, you could do\nsomething like:\n\n       # make our local tweaked version of config\n       git checkout meta\n       $EDITOR config\n       git commit -a -m 'tweak config based on upstream'\n\n       # now deploy it\n       cp config .git/tracked-config\n\n       # and reference it\n       git config include.path tracked-config\n\n       # Weeks later, update and redeploy. Don't touch tracked-config in\n       # the meantime, as your changes will be overwritten (or copy it\n       # back after checkout, commit changes, then pull)\n       git checkout meta\n       git pull\n       cp config .git/tracked-config\n\nwhich is really quite similar to the \"include.ref\" I showed earlier,\nexcept you can skip the annoying \"deploy\" step. Which is a minor\nconvenience if you are actually keeping your own local config branch,\nand a slightly larger one if you want to do the dangerous \"just look at\norigin/meta for config\" thing.\n\n> > [1] I want conditional inclusion because sometimes the rules for config\n> >    entries changes from version to version. For example, I have\n> >    pager.diff set to a script in my ~/.gitconfig. But older versions of\n> >    git don't understand non-boolean values and barf. I'd really like to\n> >    do something like:\n> >\n> >    [include-ifdef \"has-pager-scripts\"]\n> >    path = ~/.gitconfig-pager\n> >\n> >    where \"has-pager-scripts\" would be a magic flag compiled into git\n> >    versions that understand that config.\n> \n> But how far would you go with conditional expressions?\n\nI agree it could become hairy in the general case. That's why I called\nit \"include-ifdef\" and not \"include-if\". That would serve my use case. I\nhave no desire to support\n\n  [include-if \"2 + 2 >= 4\"]\n\n-Peff\n"},{"id":"176247","messageId":"20110926192126.GA55743@gmail.com","threadId":"28472","inReplyTo":"CACsJy8BAVRAct=sxTpZ+b-ft1OjbY9oZG6uEXrcsTXw3CXnwSg@mail.gmail.com","subject":"Re: config-file includes","fromName":"David Aguilar","fromEmail":"davvid@gmail.com","sentAt":"2011-09-26T19:21:27Z","receivedAt":"2011-09-26T19:21:27Z","isPatch":false,"sender":{"key":"davvid@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13196?v=4"},"body":"On Mon, Sep 26, 2011 at 08:45:58PM +1000, Nguyen Thai Ngoc Duy wrote:\n> On Sat, Sep 24, 2011 at 5:58 AM, Jeff King <peff@peff.net> wrote:\n> \n> Another thing is, what if I want to exclude certain part of the included config?\n> \n> [1] http://thread.gmane.org/gmane.comp.version-control.git/163285/focus=163288\n> \n> > [1] I want conditional inclusion because sometimes the rules for config\n> >    entries changes from version to version. For example, I have\n> >    pager.diff set to a script in my ~/.gitconfig. But older versions of\n> >    git don't understand non-boolean values and barf. I'd really like to\n> >    do something like:\n> >\n> >    [include-ifdef \"has-pager-scripts\"]\n> >    path = ~/.gitconfig-pager\n> >\n> >    where \"has-pager-scripts\" would be a magic flag compiled into git\n> >    versions that understand that config.\n> \n> But how far would you go with conditional expressions?\n> -- \n> Duy\n\nThis syntax is simple yet would solve one problem I run into\noften.  It could be used for the case where some settings\n(e.g. diff.tool, merge.tool) are different on OS X and Linux.\n\n[include-ifdef \"darwin\"]\n\tpath = ~/.gitconfig-darwin\n-- \n\t\t\t\t\tDavid\n"},{"id":"176254","messageId":"20110926200553.GA492@sigill.intra.peff.net","threadId":"28472","inReplyTo":"20110926192126.GA55743@gmail.com","subject":"Re: config-file includes","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-09-26T20:05:53Z","receivedAt":"2011-09-26T20:05:53Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Sep 26, 2011 at 09:21:27PM +0200, David Aguilar wrote:\n\n> > >    [include-ifdef \"has-pager-scripts\"]\n> > >    path = ~/.gitconfig-pager\n> > >\n> > >    where \"has-pager-scripts\" would be a magic flag compiled into git\n> > >    versions that understand that config.\n> > \n> > But how far would you go with conditional expressions?\n> \n> This syntax is simple yet would solve one problem I run into\n> often.  It could be used for the case where some settings\n> (e.g. diff.tool, merge.tool) are different on OS X and Linux.\n> \n> [include-ifdef \"darwin\"]\n> \tpath = ~/.gitconfig-darwin\n\nThanks for another concrete example.\n\nI'm not sure how that would be implemented, though. I don't think git\nknows that it is compiled for darwin. Would it just be running \"uname\n-s\" behind the scenes? Should it happen at runtime, or as part of the\ncompile process?\n\nWe could allow arbitrary shell code like:\n\n  [include-if \"test `uname -s` -eq Darwin\"]\n\nVery flexible, though it makes me think we are getting a little\noverboard.  And it's an extra shell invocation whenever we read the\nconfig, which is ugly.\n\n-Peff\n"},{"id":"176259","messageId":"7vmxdr100n.fsf@alter.siamese.dyndns.org","threadId":"28472","inReplyTo":"20110926200553.GA492@sigill.intra.peff.net","subject":"Re: config-file includes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-09-26T21:12:08Z","receivedAt":"2011-09-26T21:12:08Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> We could allow arbitrary shell code like:\n>\n>   [include-if \"test `uname -s` -eq Darwin\"]\n>\n> Very flexible, though it makes me think we are getting a little\n> overboard.  And it's an extra shell invocation whenever we read the\n> config, which is ugly.\n\nLet's not go there. It is not even like we only ever call git_config()\nonce in the lifetime of a process.\n"},{"id":"176298","messageId":"CAG+J_Dw3B0qReTevph725sPatpKDzikC=W0XTvKo4GsYLVcL4w@mail.gmail.com","threadId":"28472","inReplyTo":"20110926200553.GA492@sigill.intra.peff.net","subject":"Re: config-file includes","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2011-09-27T02:13:44Z","receivedAt":"2011-09-27T02:13:44Z","isPatch":false,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"On Mon, Sep 26, 2011 at 4:05 PM, Jeff King <peff@peff.net> wrote:\n>> [include-ifdef \"darwin\"]\n>>       path = ~/.gitconfig-darwin\n>\n> Thanks for another concrete example.\n>\n> I'm not sure how that would be implemented, though. I don't think git\n> knows that it is compiled for darwin. Would it just be running \"uname\n> -s\" behind the scenes? Should it happen at runtime, or as part of the\n> compile process?\n>\n> We could allow arbitrary shell code like:\n>\n>  [include-if \"test `uname -s` -eq Darwin\"]\n>\n> Very flexible, though it makes me think we are getting a little\n> overboard.  And it's an extra shell invocation whenever we read the\n> config, which is ugly.\n\nI would think git could just learn a few useful defines at the time of\ncompile, such as e.g. OS_Darwin would be more than sufficient.\n\nI can also give you another use use case. I keep all my work repos\nunder ~Work/ and I want my user.email on all those to be my work email\naddy, and all other repos on my system I want to use my personal email\naddress. So my ~/.gitconfig has my personal email address and then 99%\nof the time I forget to configure the repos under ~/Work correctly.\nThat said, I'm not sure how the config include would help this...\n\nj.\n"},{"id":"176299","messageId":"20110927023845.GC6920@sigill.intra.peff.net","threadId":"28472","inReplyTo":"CAG+J_Dw3B0qReTevph725sPatpKDzikC=W0XTvKo4GsYLVcL4w@mail.gmail.com","subject":"Re: config-file includes","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-09-27T02:38:45Z","receivedAt":"2011-09-27T02:38:45Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Sep 26, 2011 at 10:13:44PM -0400, Jay Soffian wrote:\n\n> > We could allow arbitrary shell code like:\n> >\n> >  [include-if \"test `uname -s` -eq Darwin\"]\n> >\n> > Very flexible, though it makes me think we are getting a little\n> > overboard.  And it's an extra shell invocation whenever we read the\n> > config, which is ugly.\n> \n> I would think git could just learn a few useful defines at the time of\n> compile, such as e.g. OS_Darwin would be more than sufficient.\n\nYeah, I think that is probably more sane. We don't collect the\ninformation now, but it probably wouldn't be that hard (at the very\nworst, it would probably just involve running \"uname\" at build time).\n\n> I can also give you another use use case. I keep all my work repos\n> under ~Work/ and I want my user.email on all those to be my work email\n> addy, and all other repos on my system I want to use my personal email\n> address. So my ~/.gitconfig has my personal email address and then 99%\n> of the time I forget to configure the repos under ~/Work correctly.\n> That said, I'm not sure how the config include would help this...\n\nYou would need to provide git with some condition about which address\nshould be used. It sounds like the repo directory is the best bet. So\nmaybe something like:\n\n  [include-ifrepo \"/home/jsoffian/Work/*\"]\n\nor something. Maybe that's too gross. I dunno.\n\nFWIW, this hack would work even with current git:\n\n  cat >bin/git <<\\EOF\n  #!/bin/sh\n  case \"`git rev-parse --show-toplevel`\" in\n  \"$HOME/Work/*\")\n          set -- -c user.email=whatever \"$@\"\n          ;;\n  esac\n  exec /path/to/real/git \"$@\"\n  EOF\n\nwhich would actually work with most of the conditionals that have been\nmentioned in this thread. But it's kind of nasty.\n\n-Peff\n"}]}