Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setting a global hooks path causes "Cowardly refusing to install" everywhere #1198

Closed
janosh opened this issue Oct 29, 2019 · 15 comments
Labels

Comments

@janosh
Copy link

@janosh janosh commented Oct 29, 2019

I recently setup a global spell checking commit hook that lives in

git config --global core.hooksPath ~/dotfiles/gitHooks

Just noticed that due to this, attempting pre-commit install now fails with

[ERROR] Cowardly refusing to install hooks with `core.hooksPath` set.

in every repo.

Is there actually a reason to fail in the presence of global hooks? Local hooks are still executed unless they're being shadowed by a global hook of the same name, i.e. a global commit-msg hook would prevent a local commit-msg hook from running. In that case, it's the user's responsibility to make sure the global hook calls the local one if so desired.

If there is indeed no reason not to let global and local hooks coincide, fixing this might be as easy as modifying

def has_core_hookpaths_set():
-    _, out, _ = cmd_output_b('git', 'config', 'core.hooksPath', retcode=None)
+    _, out, _ = cmd_output_b('git', 'config', '--local', 'core.hooksPath', retcode=None)
    return bool(out.strip())

Happy to submit a PR for that.

@asottile

This comment has been minimized.

Copy link
Member

@asottile asottile commented Oct 29, 2019

pre-commit is nonfunctional with that setting set -- see #718 #663 pre-commit/pre-commit-hooks#250

you may find git's init.templateDir more amenable

@asottile asottile added the question label Oct 29, 2019
@asottile asottile closed this Oct 29, 2019
@janosh

This comment has been minimized.

Copy link
Author

@janosh janosh commented Oct 29, 2019

@asottile I think there's a misunderstanding here. None of the issue you mentioned concern global hooks.

I still don't see how those would be an issue except as explained above (which is user responsibility and doesn't concern pre-commit):

Local hooks are still executed unless they're being shadowed by a global hook of the same name, i.e. a global commit-msg hook would prevent a local commit-msg hook from running. In that case, it's the user's responsibility to make sure the global hook calls the local one if so desired.

@asottile

This comment has been minimized.

Copy link
Member

@asottile asottile commented Oct 29, 2019

with core.hooksPath set

$ rm -rf /tmp/x
$ mkdir -p /tmp/x/y
$ git clone -q git@github.com:asottile/astpretty /tmp/x/astpretty
$ cd /tmp/x/astpretty
$ pre-commit install
pre-commit installed at .git/hooks/pre-commit
$ git config --global core.hooksPath /tmp/x/y
$ git commit --allow-empty -m foo
[master 9f1af98] foo

with core.hooksPath unset

$ rm -rf /tmp/x
$ mkdir -p /tmp/x/y
$ git clone -q git@github.com:asottile/astpretty /tmp/x/astpretty
$ cd /tmp/x/astpretty
$ pre-commit install
pre-commit installed at .git/hooks/pre-commit
$ git commit --allow-empty -m foo
Trim Trailing Whitespace.............................(no files to check)Skipped
Fix End of Files.....................................(no files to check)Skipped
Fix double quoted strings............................(no files to check)Skipped
Check docstring is first.............................(no files to check)Skipped
Check Yaml...........................................(no files to check)Skipped
Debug Statements (Python)............................(no files to check)Skipped
Tests should end in _test.py.........................(no files to check)Skipped
Fix requirements.txt.................................(no files to check)Skipped
flake8...............................................(no files to check)Skipped
autopep8.............................................(no files to check)Skipped
Reorder python imports...............................(no files to check)Skipped
pyupgrade............................................(no files to check)Skipped
Add trailing commas..................................(no files to check)Skipped
[master db6914a] foo
@janosh

This comment has been minimized.

Copy link
Author

@janosh janosh commented Oct 29, 2019

So a global hook directory automatically shadows all local hooks?

@asottile

This comment has been minimized.

Copy link
Member

@asottile asottile commented Oct 29, 2019

that's what my output appears to show, yes -- that's just how git works it seems

this directly contradicts your claim above so I'm confused where you've gotten that from :S

@janosh

This comment has been minimized.

Copy link
Author

@janosh janosh commented Oct 29, 2019

I thought I read that about two weeks ago but apparently I misread or the source was mistaken. Can't remember/find the source now.

you may find git's init.templateDir more amenable

The problem with templates AFAIU them is that changes made to the template are not reflected in previously created repos, correct? Or could I place a symlink in the template directory and git would copy that symlink into each repo which would all point to a master file that's always up to date?

@asottile

This comment has been minimized.

Copy link
Member

@asottile asottile commented Oct 29, 2019

presumably that would work, yeah

@janosh

This comment has been minimized.

Copy link
Author

@janosh janosh commented Oct 30, 2019

The problem with templates AFAIU them is that changes made to the template are not reflected in previously created repos, correct? Or could I place a symlink in the template directory and git would copy that symlink into each repo which would all point to a master file that's always up to date?

This actually also doesn't help me because it doesn't retrofit the hook into existing repos.

In any case, I just did a little more testing and it turns out setting a global hooks directory only shadows local hooks if no local hooks path has been set (i.e. if it's still the default .git/hooks).

If a local hooks directory is set (it can even be set to the default location), local hooks are in fact called (which is why it didn't notice the behavior you showed above).

What was the reason to not just install the hooks in the user specified local hooks directory if one was specified and have pre-commit itself set it to the default .git/hooks otherwise? Seems to me like that would enable joint use of local and global hooks.

@asottile

This comment has been minimized.

Copy link
Member

@asottile asottile commented Oct 30, 2019

What was the reason to not just install the hooks in the user specified local hooks directory if one was specified and have pre-commit itself set it to the default .git/hooks otherwise? Seems to me like that would enable joint use of local and global hooks.

pre-commit is not going to muck with user's settings -- or install outside the working repository. This is why it cowardly refuses


could you demo what you're talking about? I still can't reproduce

@janosh

This comment has been minimized.

Copy link
Author

@janosh janosh commented Oct 30, 2019

pre-commit is not going to muck with user's settings

You mean git config --local core.hooksPath .git/hooks in case no local hooks path has been set yet? That's not strictly changing any settings, just applying the default.

or install outside the working repository

Why not? Setting a local hooks path outside the repo is very unusual and if a user goes to such lengths, they'll most likely have a good reason. Not sure what the point would be of second guessing the user here.

could you demo what you're talking about? I still can't reproduce

mkdir test && cd test
echo '#!/bin/sh\n\necho foobar' >> .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
git config --global core.hooksPath /tmp/x
git config --local core.hooksPath .git/hooks
git commit --allow-empty -m 'foobar?'
> foobar
> [master 00ce0f4] foobar?

As you can see in the above output, the local hook is called even with a global hooks path set.

@asottile

This comment has been minimized.

Copy link
Member

@asottile asottile commented Oct 30, 2019

pre-commit is not going to muck with user's settings

You mean git config --local core.hooksPath .git/hooks in case no local hooks path has been set yet? That's not strictly changing any settings, just applying the default.

it isn't applying the default, it's overriding whatever the user set

or install outside the working repository

Why not? Setting a local hooks path outside the repo is very unusual and if a user goes to such lengths, they'll most likely have a good reason. Not sure what the point would be of second guessing the user here.

A tool should not just silently write to paths it doesn't control, especially dotfiles :)

could you demo what you're talking about? I still can't reproduce

mkdir test && cd test
echo '#!/bin/sh\n\necho foobar' >> .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
git config --global core.hooksPath /tmp/x
git config --local core.hooksPath .git/hooks
git commit --allow-empty -m 'foobar?'
> foobar
> [master 00ce0f4] foobar?

As you can see in the above output, the local hook is called even with a global hooks path set.

well yes of course, the git config --local setting overrides the git config --global setting -- but they cannot live in harmony:

$ rm -rf /tmp/x/
$ mkdir -p /tmp/x/y
$ git init /tmp/x/x
Initialized empty Git repository in /tmp/x/x/.git/
$ cd /tmp/x/x
$ echo 'echo pre-commit' > .git/hooks/pre-commit; chmod +x .git/hooks/pre-commit
$ echo 'echo commit-msg' > /tmp/x/y/commit-msg; chmod +x /tmp/x/y/commit-msg
$ git config --global core.hooksPath /tmp/x/y
$ git config --local core.hooksPath .git/hooks
$ git commit -m "commit message" --allow-empty
pre-commit
[master (root-commit) 569547d] commit message

the "global hook" doesn't get run

@janosh

This comment has been minimized.

Copy link
Author

@janosh janosh commented Oct 30, 2019

it isn't applying the default, it's overriding whatever the user set

I feel like we're talking at cross purposes somehow. As I wrote above ("in case no local hooks path has been set yet"), if the user has already set a custom local hooks path, you wouldn't need to run this command at all since then local hooks will already not be shadowed by global ones. You only run git config --local core.hooksPath .git/hooks to make this setting explicit if the user did not already specify a different directory. Hence you wouldn't be overriding what the user set.

A tool should not just silently write to paths it doesn't control, especially dotfiles :)

Who said anything about silent? In that case, just tell the user and/or ask for confirmation. 😄

the "global hook" doesn't get run

I'm aware of that. But consider pre-commit's design choice right now. Failing "cowardly" as soon as a global hooks path is set makes it impossible to use for anyone who wants to have a bunch of global hooks that apply to repos without local hooks while repos that do have local hooks can implement custom behavior on a case-by-case basis.

@asottile

This comment has been minimized.

Copy link
Member

@asottile asottile commented Oct 30, 2019

pre-commit currently is entirely non-interactive and I'm definitely not changing that to accommodate this use case. It could maybe suggest the other command you're suggesting but I don't think the current outcome changes all that much so I'm not sure what you want. pre-commit itself is not going to git config (set) or write to core.hooksPath as I consider both of those unacceptable.

@janosh

This comment has been minimized.

Copy link
Author

@janosh janosh commented Oct 30, 2019

pre-commit itself is not going to git config (set) or write to core.hooksPath as I consider both of those unacceptable.

I see. Thanks for carrying on the conversation with me regardless! I appreciate that.

It could maybe suggest the other command you're suggesting

Which other command? I don't quite follow.

@asottile

This comment has been minimized.

Copy link
Member

@asottile asottile commented Oct 30, 2019

git config --local core.hooksPath .git/hooks (though even that's not necessarily correct in submodules, subtrees, etc.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.