Skip to content

Commit

Permalink
Add an option to stash changes before running hooks
Browse files Browse the repository at this point in the history
In order to ensure any pre-commit tests are run against the files as
they will appear in the commit, this commit adds an option to run `git
stash` to save any changes to the working tree before running the
scripts, then restore any changes after the scripts finish.

The save/restore procedure is based on Chris Torek's StackOverflow
answer to a question asking how to do exactly this.[1]  This
implementation does not do a hard reset before restoring the stash by
default, since it assumes that if scripts modify tracked files the
changes should be kept.  But it does provide this behavior, and `git
clean`, as configurable options.

It follows the convention requested in observing#4 by making the new stash option
default to off.  Although there are no known implementation issues (with
the exception of the git bug noted in Torek's SO answer), current
scripts may expect modified/untracked files to exist or modify untracked
files in a way which prevents applying the stash, making default-on
behavior backwards-incompatible.

The tests are split into a separate file.  Since each stash option is
tested against a project repository and a clean/reset is done between
each test, the tests are somewhat slow.  By splitting the tests into a
separate file, we can avoid running them by default.  They can instead
be run as test-stash, as part of test-all, and as part of test-travis.

This commit is based off of the work of Christopher Hiller in observing#47,
although the implementation differs significantly due to the use of
Promises in place of async, which I found to be significantly clearer,
more flexible, and they make the tests significantly more concise.

Fixes: observing#4

1.  https://stackoverflow.com/a/20480591

Signed-off-by: Christopher Hiller <boneskull@boneskull.com>
[kevin@kevinlocke.name: Reimplement using Promises and Torek's method]
Signed-off-by: Kevin Locke <kevin@kevinlocke.name>
  • Loading branch information
kevinoid committed Feb 6, 2016
1 parent 8ab4d7c commit 3573728
Show file tree
Hide file tree
Showing 5 changed files with 817 additions and 26 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ node_modules
npm-debug.log
coverage
.tern-port
test-repo/
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,32 @@ should be ran you can also configure the following options:
- **colors** Don't output colors when we write messages. Should be a boolean.
- **template** Path to a file who's content should be used as template for the
git commit body.
- **stash** Run `git stash` to stash changes to the working directory prior to
run and restore changes after. This can be useful for checking files as they
will appear in the commit without uncommitted changes and files. It can also
cause rebuilds or reloads due to file changes for editors and watch scripts
and has some ([known issues](https://stackoverflow.com/a/20480591/503410)).
The value can be a boolean or an options object with the following properties:
- **clean** Run `git clean` before re-applying the stashed changes.
When combined with `includeUntracked`/`includeAll`, this would delete
any files files created by the scripts. In particular ones which would
prevent applying the stash if they exist in the working dir and stash.
- **includeAll** Include all files (both untracked and ignored) in stash
(and clean, if run). This is almost never what you want, since it will
stash `node_modules` among other things.
- **includeUntracked** Include untracked files in stash. This is useful to
exclude untracked js files from linting, but carries some risk of losing
[untracked files](http://article.gmane.org/gmane.comp.version-control.git/263385/)
or [directories which become
empty](http://thread.gmane.org/gmane.comp.version-control.git/254037)
or [files/directories changing ignore
status](http://thread.gmane.org/gmane.comp.version-control.git/282324)
or creating a stash which [requiring manual intervention to
apply](http://article.gmane.org/gmane.comp.version-control.git/285403).
Also, it takes extra effort to [view untracked files in the
stash](https://stackoverflow.com/a/22819771).
- **reset** Run `git reset --hard` before re-applying the stashed changes.
This would revert any changes to tracked files made by the scripts.

These options can either be added in the `pre-commit`/`precommit` object as keys
or as `"pre-commit.{key}` key properties in the `package.json`:
Expand Down
Loading

0 comments on commit 3573728

Please sign in to comment.