How to Print All the Staged File Names Using Ruby Git Pre-Commit Hook

How to print all the staged file names using ruby git pre-commit hook?

One possible command is (from "Git pre-commit hook : changed/added files"):

git diff --cached --name-only --diff-filter=ACM

That is what I recommended for that other ruby pre-commit hook"

And you could use it with "jish/pre-commit".

Git pre-commit hook

You should rather grep on indexed (cached) files, instead of your working tree.

Otherwise, your grep could find debug instructions in files (or part of files) which aren't part of the next commit.

See "Git pre-commit hook : changed/added files":

git diff --cached --name-only --diff-filter=ACM

As explained in "Why You Need a Git Pre-Commit Hook and Why Most Are Wrong":

Most test against whatever files are currently on disk, not what is in the staging area (the files actually being committed).

The approach if that hook is a bit different: it stashes every work in progress before searching the files.

def main(all_files):
# Stash any changes to the working tree that are not going to be committed
subprocess.call(['git', 'stash', '-u', '--keep-index'], stdout=subprocess.PIPE)

pre-commit hook doesn't check if saved changes are staged before running

If I understood your problem correctly, you need to have files as they are in index at hand.

To do so, you can do git stash -k (keeping index) before running your utility and git stash pop afterwards assuming it won't change anything so that no conflicts would appear.

Searching files with pre-commit

First, the hook must be in the .git/hook folder and name pre-commit (with execution right: chmod +x .git/hooks/pre-commit)

The OP jesusjjf confirms in the comments that was the issue:

I had copied what was in the pre-commit.sample file onto a plain text file, instead of just renaming.

Second, here are some script examples:


You have another example using a similar technique, using git rev-parse and git diff-index, and the empty tree I mentioned before:

#!/bin/sh

if git rev-parse --verify HEAD >/dev/null 2>&1; then
against=HEAD
else
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

for FILE in `git diff-index --name-status $against -- | cut -c3-` ; do
# Check if the file contains 'debugger'
if [ "grep 'debugger' $FILE" ]
then
echo $FILE ' contains debugger!'
exit 1
fi
done
exit

The comments on this gist mention:

On my system, if [ "grep 'debugger' $FILE" ] always evaluates to true.

Changing it to if grep -q 'debugger' "$FILE" fixes that.


A more recent example:

#!/bin/bash

# Pre commit hook that prevents FORBIDDEN code from being commited.
# Add unwanted code to the FORBIDDEN array as necessary

FILES_PATTERN='\.(rb|js|coffee)(\..+)?$'
FORBIDDEN=( debugger ruby-debug )

for i in "${FORBIDDEN[@]}"
do
git diff --cached --name-only| grep ".js" |xargs sed 's/ //g'|grep "ha_mobile.debug=true" && \
echo 'COMMIT REJECTED Found ha_mobile.debug=true references. Please remove them before commiting' && exit 1

git diff --cached --name-only | \
grep -E $FILES_PATTERN | \
GREP_COLOR='4;5;37;41' xargs grep --color --with-filename -n $i && \
echo 'COMMIT REJECTED Found' $i 'references. Please remove them before commiting' && exit 1
done

exit 0

Git pre-commit hook issue

Judging by other git hooks (like "pre-commit/utils/staged_files.rb" or "i-wind/gpc/pre-commit.rb", you don't need to prepend with the root folder of the repo.

file_text = File.read(File.join(file))

How to write an update hook for git submodules?

The update hook is only run when someone has pushed into the current repository, which doesn't sound like what you want. You could use the post-commit hook, if you want to copy these files into place every time you create a commit in your repository. (That should be sufficient, because you'd need to commit the new version of any submodule in the main project when you change the commit that the submodule is meant to be at. This would be a natural point to update the files in public/assets.)

You say that your test hook isn't being run - that may be simply because you have the name wrong. The update hook must be an executable file called .git/hooks/update (n.b. without a .rb suffix). Similarly, a post-commit hook must be .git/hooks/post-commit.

You shouldn't create hooks in any particular submodule for this task, since the action the hook will be taking is specific to the main project. Because of that, it doesn't really matter whether the change you're worried about it due to committing a new version of the submodules or just updating any random file.

For writing hooks, you'll find the official githooks documentation useful, and possibly these additional tips.

Understanding git commit --only and pre-commit hooks

The precise details vary from one version of Git to another, and some people—I'm not saying the JetBrains folks are among them, as I have no idea—have tried to bypass the way Git does things and in the process, screwed things up such that either they can't be worked-around, or the work-around is Git-version-dependent. However, the main idea in these Git hooks is all the same:

  • the index contains the commit-to-make, and
  • the work-tree contains the work-tree.

These two need not be in sync when you first run git commit, and if you add files to the git commit command, with either --only or --include, Git must then make a new index, which may differ from the regular ordinary index. So now we wind up with an environment variable, GIT_INDEX_FILE, set to the path of a new, temporary index.1 Since all Git commands automatically respect the environment variables, the pre-commit hook will use the temporary index's files, and git write-tree will use the temporary index's files.

Of course, anything that fails to respect the temporary index—or, potentially, depending on --include vs --only, just uses the contents of the work-tree—will get the wrong answer.

There is still a problem, though, even with programs that do respect the environment variables. Suppose we have a file—let's call it test since that's its purpose—that initially contains "headvers", and matches the current (HEAD) commit. Now we modify it in the work-tree to contain "indexvers" and run git add test. The index version of test thus reads "indexvers". Now we modify it again in the work-tree, to contain "workvers", and run either git commit --only test or git commit --include test.

We know for sure what should go into the new commit: it should be the version of test containing workvers, because we specifically told Git to commit the work-tree version. But what should be left in the index and work-tree afterward? Does this depend on whether we used --include vs --only? I don't know what to consider the "right" answer here! All I can tell you is that when I experimented with Git before, it tended to contain workvers afterward (both in the index, and in the work-tree). That is, the temporary index's version became the normal index's version, and the work-tree file was untouched.

(If you have Git hooks that manipulate the index and/or work-tree, you will be able to pry open the difference between "copying index to saved-index, then copying back" vs "copying index to temp-index, then using temp-index".)


1This was the actual implementation at one time, when I was testing various behaviors, but it's possible that the actual implementation has changed a bit. For instance, Git could save the "normal" index in a temporary file and then replace the normal index, so that GIT_INDEX_FILE is not set after all. And, again, it may depend on --include vs --only.

Note that git commit -a may also use a temporary index, or not. I believe this behavior has changed between Git 1.7 and Git 2.10, based on the result of running git status in another window while still editing the commit message in the window that was running git commit -a.



Related Topics



Leave a reply



Submit