threads / discuss / 30449

Arguments to git hooks

Subject: Arguments to git hooks

## tl;dr

9 messages between May 6, 2012 and May 14, 2012.

replies: 8people: 4as markdown or json

jaseem abid· May 6, 2012, 18:35 UTC · lore
Hello all,

I am trying to write a hook '.git/hooks/commit-msg' to be run before every commit.

How can I pass arguments to the script? Now by default the only arg I am getting is `.git/COMMIT_EDITMSG'`. I would love to get the list of files I tried to commit also into the script so that I can run a lint program on it before committing it. How can I get this done?

V/r,

-- Jaseem Abid http://jaseemabid.github.com

Marcus Karlsson· May 6, 2012, 19:12 UTC · re: jaseem abid · lore

Re: Arguments to git hooks

On Mon, May 07, 2012 at 12:05:51AM +0530, jaseem abid wrote:
Show 11 quoted lines
> Hello all,
> 
> I am trying to write a hook '.git/hooks/commit-msg' to be run before
> every commit.
> 
> How can I pass arguments to the script? Now by default the only arg I
> am getting is `.git/COMMIT_EDITMSG'`. I would love to get the list of
> files I tried to commit also into the script so that I can run a lint
> program on it before committing it. How can I get this done?
> 
> V/r,

As far as I can see that's the only argument that git-commit passes on to the commit-msg hook. Can't you just call something like git-status from the hook or do you need the information passed specifically as an argument?

	Marcus
jaseem abid· May 6, 2012, 19:18 UTC · re: Marcus Karlsson · lore

Re: Arguments to git hooks

On Mon, May 7, 2012 at 12:42 AM, Marcus Karlsson <mk@acc.umu.se> wrote:
> As far as I can see that's the only argument that git-commit passes on
> to the commit-msg hook. Can't you just call something like git-status
> from the hook or do you need the information passed specifically as an
> argument?

I can always get last commit from `.git/COMMIT_EDITMSG'` - a fixed file. Isn't passing that as an argument a bit pointless? I want files I tried to commit specifically passed in as an argument.

Are you suggesting me to run some plumbing command, parse the result and get the required data ? Is there an easier way to get this done?

-- 
Jaseem Abid
http://jaseemabid.github.com
Marcus Karlsson· May 6, 2012, 21:11 UTC · re: jaseem abid · lore

Re: Arguments to git hooks

On Mon, May 07, 2012 at 12:48:35AM +0530, jaseem abid wrote:
Show 8 quoted lines
> On Mon, May 7, 2012 at 12:42 AM, Marcus Karlsson <mk@acc.umu.se> wrote:
> > As far as I can see that's the only argument that git-commit passes on
> > to the commit-msg hook. Can't you just call something like git-status
> > from the hook or do you need the information passed specifically as an
> > argument?
> 
> I can always get last commit from `.git/COMMIT_EDITMSG'` - a fixed
> file. Isn't passing that as an argument a bit pointless?

That's a good question. I don't know. If someone else knows the reason I sure would like to find out.

> I want files I tried to commit specifically passed in as an argument.

There are many different reasons to use hooks. If everything that a hook could potentially need was passed to it as an argument then a lot of data would often end up unused. Better to supply as little as possible and only do more work when it's actually needed.

> Are you suggesting me to run some plumbing command, parse the result
> and get the required data ? Is there an easier way to get this done?

I wouldn't go as deep as the plumbing, I think git status --porcelain should work just fine, the output is fairly easy to parse.

	Marcus
jaseem abid· May 6, 2012, 21:40 UTC · re: Marcus Karlsson · lore

Re: Arguments to git hooks

On Mon, May 7, 2012 at 2:41 AM, Marcus Karlsson <mk@acc.umu.se> wrote:
> There are many different reasons to use hooks. If everything that a hook
> could potentially need was passed to it as an argument then a lot of
> data would often end up unused. Better to supply as little as possible
> and only do more work when it's actually needed.

That seems like a good reason not to pass all of the data, but isn't the file names the most primary thing somebody can ask for?

Show 5 quoted lines
>> Are you suggesting me to run some plumbing command, parse the result
>> and get the required data ? Is there an easier way to get this done?
>
> I wouldn't go as deep as the plumbing, I think git status --porcelain
> should work just fine, the output is fairly easy to parse.

I have always wondered why 'git status --porcelain' is giving a 'plumbing' style output. Any docs on this somewhere?

-- 
Jaseem Abid
http://jaseemabid.github.com
Jeff King· May 7, 2012, 07:21 UTC · re: jaseem abid · lore

Re: Arguments to git hooks

On Mon, May 07, 2012 at 03:10:07AM +0530, jaseem abid wrote:
Show 8 quoted lines
> On Mon, May 7, 2012 at 2:41 AM, Marcus Karlsson <mk@acc.umu.se> wrote:
> > There are many different reasons to use hooks. If everything that a hook
> > could potentially need was passed to it as an argument then a lot of
> > data would often end up unused. Better to supply as little as possible
> > and only do more work when it's actually needed.
> 
> That seems like a good reason not to pass all of the data, but isn't
> the file names the most primary thing somebody can ask for?

Yes, although keep in mind that the list of files does not necessarily fit onto the command line. We would have to feed it over stdin, and then you would have parsing/quoting issues.

But you can get the exact same list from "git diff-index --cached --name-only", and it is exactly as hard to parse as stdin would be (and you can even decide to use "-z" to eliminate the quoting issues).

So asking the user to call the plumbing command is more efficient and more flexible, but not actually any harder to use.

Show 5 quoted lines
> > I wouldn't go as deep as the plumbing, I think git status --porcelain
> > should work just fine, the output is fairly easy to parse.
> 
> I have always wondered why 'git status --porcelain' is giving a
> 'plumbing' style output. Any docs on this somewhere?

It is plumbing. The porcelain is meant to be "output suitable for reading by porcelains". Although I was the person who named "git status --porcelain", it is not a convention I think is particularly good; I named it to be consistent with other git commands which have a "--porcelain" mode.

-Peff
Jeff King· May 7, 2012, 07:15 UTC · re: jaseem abid · lore

Re: Arguments to git hooks

On Mon, May 07, 2012 at 12:05:51AM +0530, jaseem abid wrote:
Show 7 quoted lines
> I am trying to write a hook '.git/hooks/commit-msg' to be run before
> every commit.
> 
> How can I pass arguments to the script? Now by default the only arg I
> am getting is `.git/COMMIT_EDITMSG'`. I would love to get the list of
> files I tried to commit also into the script so that I can run a lint
> program on it before committing it. How can I get this done?
It sounds like you want the "pre-commit" hook rather than "commit-msg".

But that aside, the solution is to use plumbing commands to examine the state. You probably want "git diff-index --cached --name-only" to get the list of files that are being committed.

-Peff
Andrew Sayers· May 7, 2012, 22:17 UTC · re: jaseem abid · lore

Re: Arguments to git hooks

On 06/05/12 19:35, jaseem abid wrote:
Show 9 quoted lines
> Hello all,
> 
> I am trying to write a hook '.git/hooks/commit-msg' to be run before
> every commit.
> 
> How can I pass arguments to the script? Now by default the only arg I
> am getting is `.git/COMMIT_EDITMSG'`. I would love to get the list of
> files I tried to commit also into the script so that I can run a lint
> program on it before committing it. How can I get this done?

First, a standard warning - consider using a pre-receive hook instead of a pre-commit hook. A lot of git's power comes from making commits as cheap as possible, so rules like "no committing until your code is pretty" tend to stifle people. For example, I often commit changes before running lint-type operations, then use `git add -p` and `git checkout -p` to selectively accept/reject individual changes. When I'm done, I `git commit --amend` to pretend the original commit never happened. A pre-receive hook gives you most of the same guarantees as a pre-commit hook with almost none of the cost.

Having said that, there are situations where pre-commit hooks are a good idea (like catching "DO NOT COMMIT" comments). I've played with this a little before, and never found a very satisfactory solution. Here are some important cases:

# git status will sometimes tell you the file that will be committed: # edit foo git add foo git commit

# git status will sometimes need a bit of careful parsing: # edit foo # edit bar git add foo git commit

# git status sometimes tells you the right file but the wrong contents: # edit foo git add foo # edit foo again git commit

# but often git status will tell you the wrong file altogether: # edit foo # edit bar git add foo git commit bar

The best solution I've found is a `git commit` wrapper that does something like `CHANGES="$(git commit $@ --dry-run -v)"` to get a reliable diff, then starts work from there.

	- Andrew
jaseem abid· May 14, 2012, 20:34 UTC · re: Andrew Sayers · lore

Re: Arguments to git hooks

On Tue, May 8, 2012 at 3:47 AM, Andrew Sayers <andrew-git@pileofstuff.org> wrote:

Show 13 quoted lines
> On 06/05/12 19:35, jaseem abid wrote:
>> Hello all,
>>
>> I am trying to write a hook '.git/hooks/commit-msg' to be run before
>> every commit.
>>
>> How can I pass arguments to the script? Now by default the only arg I
>> am getting is `.git/COMMIT_EDITMSG'`. I would love to get the list of
>> files I tried to commit also into the script so that I can run a lint
>> program on it before committing it. How can I get this done?
>
> First, a standard warning - consider using a pre-receive hook instead of
> a pre-commit hook.

I am trying to get a lint, commit message spell checker, trailing whitespace check in code etc work on my *local machine* before committing. pre-receive works in the server right? Its also time I need to seriously consider a pre-commit hook to "Reject commits made between 4am and 7am with a note to go to bed."

> A lot of git's power comes from making commits as
> cheap as possible, so rules like "no committing until your code is
> pretty" tend to stifle people.

Its ok since I am the only one to use it because I want to make my commits cleaner and better. There is always --no-verify for skipping hooks.

> The best solution I've found is a `git commit` wrapper that does
> something like `CHANGES="$(git commit $@ --dry-run -v)"` to get a
> reliable diff, then starts work from there.

Isn't `git commit $@ --dry-run --porcelain` better for parsing or am I missing something ?

-- 
Jaseem Abid
http://jaseemabid.github.com

← back to recent threads