4 ms·
Show HN: Pre-commit – A framework for managing multi-language pre-commit hooks
- _mikz 12y agothere is https://github.com/jish/pre-commit https://github.com/jish/pre-commit already
- progx 12y agoI (think i) understand it, but i did not understand the workflow. Before i commit, i run local tests to be sure that my code is ok (with jshint, ...). Normally i work with my local branch before i push it to other developers. Why should i share unfinished untested code to others? Or is pre-commit a kind of local history (like Eclipse holds it in background for every file)?
- michaelmior 12y agoYou don't have to share any of the code. The idea is that before committing, you run the tests that you mention and you're blocked from committing if those tests don't pass. That's really all there is to it. You can disable those checks at any point when you commit if you wish.
- ethomson 12y agoNo, there is no change in how you share, nor is this any sort of local history. Git has the concept of "pre-commit hooks" which is a script that is run (by git itself) whenever you run "git commit", before your changes actually land in the repository. This can be used to (for example) run your local tests for you, as a sanity check. However, your hooks are configured on a per-repository basis, and not transferred when you clone. So you would need to configure these manually each time you clone. It's easy to forget to set up the hook with all the things you need to run. This tool is to help alleviate some of the pain in this, by having a configuration file to set up all the necessary hooks, as well as having a library of default hooks (whitespace checks, etc).
- Newky 12y agoShameful plug, but I wrote https://github.com/Newky/hooked/ https://github.com/Newky/hooked/ which allows you to deal with git hooks (in general) in a nicer fashion using Python. Might be of use to someone.
- icefox 12y agoAnother shameless plug, for my git-hooks project I wrote a few years ago https://github.com/icefox/git-hooks https://github.com/icefox/git-hooks It is a single small bash script with no external depenandancies so it just needs to be in your path. git-hooks provide a way to manage and share your hooks using three+ locations: User hooks, installed in ~/.git_hooks/ Project hooks, installed in .git/git_hooks/ in a project. Global hooks, specified with the hooks.global configuration option. Another very real problem with any hooks solution is that it must be enabled in each repository. Users frequently either don't do it or forget to do it in all of the repositories. Running git hooks --installglobal will force any new git repository or any git repository you clone to have a reminder to install git hooks. (It can't be on by default for security reasons of course.)
- michaelmior 12y agoThanks for this! It's been a while, but I did use it a year or so ago for a project at work and it was quite handy. It's unfortunate that git doesn't have something like this built-in.
- EGreg 12y agoThis is cool but why do we need it if Mercurial already supports pre-commit hooks? For example we have this for refreshing redmine: #!/bin/sh PROJ="" while [ $# -gt 0 ] ; do case $1 in --project) shift PROJ="&id=$1" shift ;; esac done echo $"Refreshing Redmine" curl -s -o /dev/null "http://issues.qbixstaging.com/sys/fetch_changesets?key=jI$ and here is our PHP syntax check: #!/bin/sh ### Configuration HGBIN="/usr/bin/hg" phpPath="/usr/bin/php" tmpstyle=`/bin/mktemp -t` ### hg log style file cat > $tmpstyle << EOF changeset = "{files}\n" file = "{file}\n" EOF ### PHP syntax check for f in `$HGBIN log -r $HG_NODE:tip --style $tmpstyle | grep -E "\.php[3-5]?$" | sort | uniq` ; do res=`$HGBIN cat -r tip $f | $phpPath -l -d display_errors=1 -d error_reporting=4` if [ $? -ne 0 ] ; then echo $f 1>&2 echo $res 1>&2 exit 1 fi done rm $tmpstyle finally here is one for JS: #!/bin/sh ### Configuration HGBIN="/usr/bin/hg" jshPath="/usr/local/bin/jshint" tmpstyle=`/bin/mktemp -t` ### hg log style file cat > $tmpstyle << EOF changeset = "{files}\n" file = "{file}\n" EOF ### JS syntax check for f in `$HGBIN log -r $HG_NODE:tip --style $tmpstyle | grep -E "\.js$" | sort | uniq` ; do res=`$HGBIN cat -r tip $f | $jshPath --config /projects/.jshintrc --verbose - | grep "(E"` st=$? if [ $st -eq 0 ] ; then echo $f 1>&2 echo $res 1>&2 exit 1 fi if [ $st -gt 1 ] ; then exit 1 fi done rm $tmpstyle
- struys 12y agoWe had something similar before building pre-commit and it served us well for many years. The issue is it grew to be a really long bash file with a lot of copy and pasted code (for lots of different hooks). We built pre-commit to reduce the code duplication and allow all developers to install new hooks that are not installed on the system. We also handle interesting cases like dealing with merge conflicts (see "pre-commit during merges" http://pre-commit.com/#advanced http://pre-commit.com/#advanced). aside: It would be cool to support mercurial in the future :D
- struys 12y agoHey everyone, creators of pre-commit here. Thought it was a good idea to clarify what makes our project different from most other systems. Even thought pre-commit is written in python we really don't care about the language that was used to write the hook/linter. If there's a good linter out there written in ruby, you should be able to use it and not have to install ruby/gems/etc. With pre-commit you just say you want scss-lint (https://github.com/causes/scss-lint https://github.com/causes/scss-lint) in your pre-commit config file and run pre-commit install. When you commit, pre-commit downloads, install scss-lint (without root) and runs the hook against the files you've changed. Currently we support ruby, node and python and we definitely want to expand the system to support linters in other languages like Go, C/C++ and PHP. We'd really like to support all of these linters - https://github.com/showcases/clean-code-linters https://github.com/showcases/clean-code-linters. Ken & Anthony
- icefox 12y agoSo pre-commit is just a package manager in disguise? To the extreme you could have a demo package where to build the demo you actually have to run git commit -m "world" and the pre-commit would install gcc and all of the dependencies and then run a build, letting the commit success if the build passes. ;D
- struys 12y agoIt's a weird form of a package manager yeah. The hooks execute independently from each other. We don't need requirements between the programming languages. In fact the hooks can even use different versions of the same programming language. If we have more usecases for this kind of programming, we could definitely pull just a package manager out of pre-commit.
- contingencies 12y agoGood job guys - I do think there's space for a broadly applicable solution in this space. The main selling points for a solution in this area, for us, are: (1) a strong remote registry implementation (available hooks, preferably auto-matched to auto-detected languages present, perhaps using file/libmagic and language syntax versioning); and (2) the ability to spec default behavior remotely in a company-wide registry, but then to override at two levels: that of checked in files within the repo, and .gitignore'd local developer-specific prefs. I'm definitely going to look at this further. To speed adoption, I'd encourage you to avoid assumptions around people's de-facto desire for all but the most basic levels of linting (iffy warnings, etc.), ie. make sure the defaults are very light touch ... but useful. Convenience is key. However, please don't encourage curl-based installs!