From: Jeff King <hidden> Date: 2016-06-15 22:52:06
On Fri, Sep 23, 2011 at 03:33:41PM -0400, Jeff King wrote:
[1] I really wish we had an elegant way of versioning meta-information
about a repository (like config, info/attributes, etc). I've hacked
around this before by having a special meta-branch for each repo,
checkout it out in an alternate directory, and then symlinking bits
of it into .git. But that's kind of ugly, too.
I'm not sure what a good solution would look like. There's a real
can of worms with respect to picking and choosing local versus
remote bits of meta-information, with some security implications.
Here's one solution I've given a little thought to. Comments welcome.
I've sometimes wanted an "include" mechanism in git config files.
Partially to just keep things tidier, partially to avoid
cutting-and-pasting between some repo-specific config, and partially
because I'd like a conditional inclusion mechanism[1]. I was thinking of
something that would be syntactically compatible but semantically
meaningless in current versions of git, like:
[include]
path = /some/file
path = /some/other/file
path = ~/some/file/in/your/homedir
You could extend this to look in refs, with something like:
[include]
ref = meta:config
which would resolve meta:config to a blob and examine it (i.e., it would
look at refs/heads/meta).
So the procedure for importing and updating config from a remote would
look like:
git clone project.git
cd project
# check that the upstream config looks good
git show origin/meta:config
# if so, use it
git branch meta origin/meta
git config --add include.ref meta:config
# later, check updates to upstream's config
git fetch
git diff meta origin/meta -- config
# looks ok, use it
git branch -f meta origin/meta
And obviously if you wanted to streamline that, you could make "meta"
and "config" well-known names and have clone and fetch interactively
show the config and say "do you want this [y/N]?" or something. Though I
think there is some value to doing it manually, as it gives projects the
flexibility to have different config profiles in their meta branch.
And if you really wanted to live dangerously, you could do:
git config --add include.ref origin/meta:config
That of course just covers "config". But I think you might be able to do
something similar with core.attributesfile (which could be included from
the config).
-Peff
[1] I want conditional inclusion because sometimes the rules for config
entries changes from version to version. For example, I have
pager.diff set to a script in my ~/.gitconfig. But older versions of
git don't understand non-boolean values and barf. I'd really like to
do something like:
[include-ifdef "has-pager-scripts"]
path = ~/.gitconfig-pager
where "has-pager-scripts" would be a magic flag compiled into git
versions that understand that config.
On Sat, Sep 24, 2011 at 5:58 AM, Jeff King [off-list ref] wrote:
Here's one solution I've given a little thought to. Comments welcome.
I've sometimes wanted an "include" mechanism in git config files.
Partially to just keep things tidier, partially to avoid
cutting-and-pasting between some repo-specific config, and partially
because I'd like a conditional inclusion mechanism[1]. I was thinking of
something that would be syntactically compatible but semantically
meaningless in current versions of git, like:
[include]
path = /some/file
path = /some/other/file
path = ~/some/file/in/your/homedir
You could extend this to look in refs, with something like:
[include]
ref = meta:config
which would resolve meta:config to a blob and examine it (i.e., it would
look at refs/heads/meta).
I had something similar [1], although I disregarded worktree content
completely. One thing about this meta thing is fsck/prune must dig in
config file in order not to accidentally remove something config file
refers to.
Another thing is, what if I want to exclude certain part of the included config?
[1] http://thread.gmane.org/gmane.comp.version-control.git/163285/focus=163288
[1] I want conditional inclusion because sometimes the rules for config
entries changes from version to version. For example, I have
pager.diff set to a script in my ~/.gitconfig. But older versions of
git don't understand non-boolean values and barf. I'd really like to
do something like:
[include-ifdef "has-pager-scripts"]
path = ~/.gitconfig-pager
where "has-pager-scripts" would be a magic flag compiled into git
versions that understand that config.
But how far would you go with conditional expressions?
--
Duy
From: Jeff King <hidden> Date: 2016-06-15 22:52:06
On Mon, Sep 26, 2011 at 08:45:58PM +1000, Nguyen Thai Ngoc Duy wrote:
quoted
You could extend this to look in refs, with something like:
[include]
ref = meta:config
which would resolve meta:config to a blob and examine it (i.e., it would
look at refs/heads/meta).
I had something similar [1], although I disregarded worktree content
completely.
Thanks, I had totally missed that thread.
Maybe it wasn't clear from my proposal, but I intend to disregard the
worktree entirely, too. The include.path was about including stuff from
the local filesystem, not necessarily your worktree.
One thing about this meta thing is fsck/prune must dig in
config file in order not to accidentally remove something config file
refers to.
It is only a connectivity problem if you put a raw sha1 in the config.
It seems much more sensible to me to use a real ref. That solves the
fsck issue, and it makes it easier to manipulate the contents using git.
Another thing is, what if I want to exclude certain part of the included config?
git show origin/meta:config ;# review upstream
git checkout meta origin/meta
$EDITOR config
git commit -a -m 'tweak my config based on upstream'
git config include.ref meta:config
[weeks later]
git fetch ;# oh, new config from upstream
git log -p origin/meta@{1}...origin/meta ;# looks good to me
git checkout meta
git merge origin/meta
Junio raised a good point in the thread you referenced: why is this any
better than the project just shipping a "./setup-config" script that you
run (and re-run when there is an update). Two things I can think of:
1. Carrying it in the project tree (as opposed to a separate ref) is
annoying. It bloats your project tree, and any changes you make
get tangled up in the changes you're making to the project itself.
To me, they're logically separate entities.
You can still keep a separate "meta" ref that has the setup-config
script in it, though. That wouldn't need git support at all.
But...
2. Using a script to deploy the config makes it annoying to track
changes. If I make local tweaks to what upstream suggests for the
config, I would want those tracked by git. And when upstream makes
a change, I want to do a 3-way merge. So either my script must be
clever in deploying, or I must never touch the deployed .git/config
file, and instead edit the setup-config script. Even then, how does
it handle changes in .git/config that happen naturally (e.g.,
branch config written by git).
If we had even a mechanism to include regular files, you could do
something like:
# make our local tweaked version of config
git checkout meta
$EDITOR config
git commit -a -m 'tweak config based on upstream'
# now deploy it
cp config .git/tracked-config
# and reference it
git config include.path tracked-config
# Weeks later, update and redeploy. Don't touch tracked-config in
# the meantime, as your changes will be overwritten (or copy it
# back after checkout, commit changes, then pull)
git checkout meta
git pull
cp config .git/tracked-config
which is really quite similar to the "include.ref" I showed earlier,
except you can skip the annoying "deploy" step. Which is a minor
convenience if you are actually keeping your own local config branch,
and a slightly larger one if you want to do the dangerous "just look at
origin/meta for config" thing.
quoted
[1] I want conditional inclusion because sometimes the rules for config
entries changes from version to version. For example, I have
pager.diff set to a script in my ~/.gitconfig. But older versions of
git don't understand non-boolean values and barf. I'd really like to
do something like:
[include-ifdef "has-pager-scripts"]
path = ~/.gitconfig-pager
where "has-pager-scripts" would be a magic flag compiled into git
versions that understand that config.
But how far would you go with conditional expressions?
I agree it could become hairy in the general case. That's why I called
it "include-ifdef" and not "include-if". That would serve my use case. I
have no desire to support
[include-if "2 + 2 >= 4"]
-Peff
[1] I want conditional inclusion because sometimes the rules for config
entries changes from version to version. For example, I have
pager.diff set to a script in my ~/.gitconfig. But older versions of
git don't understand non-boolean values and barf. I'd really like to
do something like:
[include-ifdef "has-pager-scripts"]
path = ~/.gitconfig-pager
where "has-pager-scripts" would be a magic flag compiled into git
versions that understand that config.
But how far would you go with conditional expressions?
--
Duy
This syntax is simple yet would solve one problem I run into
often. It could be used for the case where some settings
(e.g. diff.tool, merge.tool) are different on OS X and Linux.
[include-ifdef "darwin"]
path = ~/.gitconfig-darwin
--
David
From: Jeff King <hidden> Date: 2016-06-15 22:52:07
On Mon, Sep 26, 2011 at 09:21:27PM +0200, David Aguilar wrote:
quoted
quoted
[include-ifdef "has-pager-scripts"]
path = ~/.gitconfig-pager
where "has-pager-scripts" would be a magic flag compiled into git
versions that understand that config.
But how far would you go with conditional expressions?
This syntax is simple yet would solve one problem I run into
often. It could be used for the case where some settings
(e.g. diff.tool, merge.tool) are different on OS X and Linux.
[include-ifdef "darwin"]
path = ~/.gitconfig-darwin
Thanks for another concrete example.
I'm not sure how that would be implemented, though. I don't think git
knows that it is compiled for darwin. Would it just be running "uname
-s" behind the scenes? Should it happen at runtime, or as part of the
compile process?
We could allow arbitrary shell code like:
[include-if "test `uname -s` -eq Darwin"]
Very flexible, though it makes me think we are getting a little
overboard. And it's an extra shell invocation whenever we read the
config, which is ugly.
-Peff
Thanks for another concrete example.
I'm not sure how that would be implemented, though. I don't think git
knows that it is compiled for darwin. Would it just be running "uname
-s" behind the scenes? Should it happen at runtime, or as part of the
compile process?
We could allow arbitrary shell code like:
[include-if "test `uname -s` -eq Darwin"]
Very flexible, though it makes me think we are getting a little
overboard. And it's an extra shell invocation whenever we read the
config, which is ugly.
I would think git could just learn a few useful defines at the time of
compile, such as e.g. OS_Darwin would be more than sufficient.
I can also give you another use use case. I keep all my work repos
under ~Work/ and I want my user.email on all those to be my work email
addy, and all other repos on my system I want to use my personal email
address. So my ~/.gitconfig has my personal email address and then 99%
of the time I forget to configure the repos under ~/Work correctly.
That said, I'm not sure how the config include would help this...
j.
From: Jeff King <hidden> Date: 2016-06-15 22:52:07
On Mon, Sep 26, 2011 at 10:13:44PM -0400, Jay Soffian wrote:
quoted
We could allow arbitrary shell code like:
[include-if "test `uname -s` -eq Darwin"]
Very flexible, though it makes me think we are getting a little
overboard. And it's an extra shell invocation whenever we read the
config, which is ugly.
I would think git could just learn a few useful defines at the time of
compile, such as e.g. OS_Darwin would be more than sufficient.
Yeah, I think that is probably more sane. We don't collect the
information now, but it probably wouldn't be that hard (at the very
worst, it would probably just involve running "uname" at build time).
I can also give you another use use case. I keep all my work repos
under ~Work/ and I want my user.email on all those to be my work email
addy, and all other repos on my system I want to use my personal email
address. So my ~/.gitconfig has my personal email address and then 99%
of the time I forget to configure the repos under ~/Work correctly.
That said, I'm not sure how the config include would help this...
You would need to provide git with some condition about which address
should be used. It sounds like the repo directory is the best bet. So
maybe something like:
[include-ifrepo "/home/jsoffian/Work/*"]
or something. Maybe that's too gross. I dunno.
FWIW, this hack would work even with current git:
cat >bin/git <<\EOF
#!/bin/sh
case "`git rev-parse --show-toplevel`" in
"$HOME/Work/*")
set -- -c user.email=whatever "$@"
;;
esac
exec /path/to/real/git "$@"
EOF
which would actually work with most of the conditionals that have been
mentioned in this thread. But it's kind of nasty.
-Peff