overcommit 0.23.0 → 0.24.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/overcommit +1 -1
- data/config/default.yml +154 -18
- data/config/starter.yml +3 -3
- data/lib/overcommit.rb +2 -1
- data/lib/overcommit/cli.rb +11 -8
- data/lib/overcommit/configuration.rb +18 -4
- data/lib/overcommit/configuration_loader.rb +45 -28
- data/lib/overcommit/configuration_validator.rb +33 -1
- data/lib/overcommit/constants.rb +5 -3
- data/lib/overcommit/exceptions.rb +3 -0
- data/lib/overcommit/git_repo.rb +116 -0
- data/lib/overcommit/git_version.rb +15 -0
- data/lib/overcommit/hook/base.rb +42 -5
- data/lib/overcommit/hook/commit_msg/capitalized_subject.rb +13 -0
- data/lib/overcommit/hook/commit_msg/spell_check.rb +41 -0
- data/lib/overcommit/hook/post_checkout/submodule_status.rb +30 -0
- data/lib/overcommit/hook/post_commit/submodule_status.rb +30 -0
- data/lib/overcommit/hook/post_merge/submodule_status.rb +30 -0
- data/lib/overcommit/hook/post_rewrite/submodule_status.rb +30 -0
- data/lib/overcommit/hook/pre_commit/base.rb +2 -2
- data/lib/overcommit/hook/pre_commit/bundle_check.rb +1 -1
- data/lib/overcommit/hook/pre_commit/case_conflicts.rb +20 -0
- data/lib/overcommit/hook/pre_commit/coffee_lint.rb +29 -2
- data/lib/overcommit/hook/pre_commit/css_lint.rb +1 -8
- data/lib/overcommit/hook/pre_commit/go_lint.rb +8 -2
- data/lib/overcommit/hook/pre_commit/go_vet.rb +20 -0
- data/lib/overcommit/hook/pre_commit/html_tidy.rb +1 -10
- data/lib/overcommit/hook/pre_commit/image_optim.rb +11 -28
- data/lib/overcommit/hook/pre_commit/js_lint.rb +18 -0
- data/lib/overcommit/hook/pre_commit/jsl.rb +24 -0
- data/lib/overcommit/hook/pre_commit/json_syntax.rb +4 -7
- data/lib/overcommit/hook/pre_commit/rails_schema_up_to_date.rb +1 -1
- data/lib/overcommit/hook/pre_commit/ruby_lint.rb +19 -0
- data/lib/overcommit/hook/pre_commit/scss_lint.rb +8 -1
- data/lib/overcommit/hook/pre_commit/w3c_css.rb +4 -18
- data/lib/overcommit/hook/pre_commit/w3c_html.rb +4 -18
- data/lib/overcommit/hook/pre_commit/xml_syntax.rb +19 -0
- data/lib/overcommit/hook/pre_commit/yaml_syntax.rb +4 -8
- data/lib/overcommit/hook/pre_push/base.rb +10 -0
- data/lib/overcommit/hook/pre_push/protected_branches.rb +27 -0
- data/lib/overcommit/hook/pre_push/r_spec.rb +12 -0
- data/lib/overcommit/hook/pre_rebase/base.rb +11 -0
- data/lib/overcommit/hook_context.rb +2 -2
- data/lib/overcommit/hook_context/base.rb +5 -7
- data/lib/overcommit/hook_context/pre_commit.rb +66 -16
- data/lib/overcommit/hook_context/pre_push.rb +44 -0
- data/lib/overcommit/hook_context/pre_rebase.rb +36 -0
- data/lib/overcommit/hook_runner.rb +27 -7
- data/lib/overcommit/installer.rb +46 -7
- data/lib/overcommit/message_processor.rb +3 -0
- data/lib/overcommit/printer.rb +8 -12
- data/lib/overcommit/subprocess.rb +11 -0
- data/lib/overcommit/utils.rb +28 -6
- data/lib/overcommit/version.rb +1 -1
- data/template-dir/hooks/commit-msg +2 -2
- data/template-dir/hooks/overcommit-hook +2 -2
- data/template-dir/hooks/post-checkout +2 -2
- data/template-dir/hooks/post-commit +2 -2
- data/template-dir/hooks/post-merge +2 -2
- data/template-dir/hooks/post-rewrite +2 -2
- data/template-dir/hooks/pre-commit +2 -2
- data/template-dir/hooks/pre-push +81 -0
- data/template-dir/hooks/pre-rebase +81 -0
- metadata +33 -13
- data/lib/overcommit/hook/pre_commit/pry_binding.rb +0 -14
@@ -2,40 +2,23 @@ module Overcommit::Hook::PreCommit
|
|
2
2
|
# Checks for images that can be optimized with `image_optim`.
|
3
3
|
class ImageOptim < Base
|
4
4
|
def run
|
5
|
-
|
6
|
-
|
7
|
-
rescue LoadError
|
8
|
-
return :fail, 'image_optim not installed -- run `gem install image_optim`'
|
9
|
-
end
|
5
|
+
result = execute(command + applicable_files)
|
6
|
+
return [:fail, result.stdout + result.stderr] unless result.success?
|
10
7
|
|
11
|
-
|
12
|
-
|
13
|
-
optimize_images(applicable_files)
|
14
|
-
rescue ::ImageOptim::BinResolver::BinNotFound => e
|
15
|
-
return :fail, "#{e.message}. The image_optim gem is dependendent on this binary."
|
16
|
-
end
|
8
|
+
optimized_files = extract_optimized_files(result.stdout)
|
9
|
+
return :pass if optimized_files.empty?
|
17
10
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
"\n\nOptimize them by running:\n" \
|
22
|
-
" image_optim --skip-missing-workers #{optimized_images.join(' ')}"
|
23
|
-
end
|
24
|
-
|
25
|
-
:pass
|
11
|
+
output = "The following images are optimizable:\n#{optimized_files.join("\n")}"
|
12
|
+
output += "\n\nOptimize them by running `#{command.join(' ')} #{optimized_files.join(' ')}`"
|
13
|
+
[:fail, output]
|
26
14
|
end
|
27
15
|
|
28
16
|
private
|
29
17
|
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
image_optim.optimize_images(image_paths) do |path, optimized|
|
35
|
-
path if optimized
|
36
|
-
end
|
37
|
-
|
38
|
-
optimized_images.compact
|
18
|
+
def extract_optimized_files(output)
|
19
|
+
output.split("\n").
|
20
|
+
select { |line| line =~ /^\d+/ }.
|
21
|
+
map { |line| line.split(/\s+/).last }
|
39
22
|
end
|
40
23
|
end
|
41
24
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Overcommit::Hook::PreCommit
|
2
|
+
# Runs `jslint` against any modified JavaScript files.
|
3
|
+
class JsLint < Base
|
4
|
+
MESSAGE_REGEX = /(?<file>[^:]+):(?<line>\d+)/
|
5
|
+
|
6
|
+
def run
|
7
|
+
result = execute(command + applicable_files)
|
8
|
+
return :pass if result.success?
|
9
|
+
|
10
|
+
# example message:
|
11
|
+
# path/to/file.js:1:1: Error message
|
12
|
+
extract_messages(
|
13
|
+
result.stdout.split("\n").grep(MESSAGE_REGEX),
|
14
|
+
MESSAGE_REGEX
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Overcommit::Hook::PreCommit
|
2
|
+
# Runs `jsl` against any modified JavaScript files.
|
3
|
+
class Jsl < Base
|
4
|
+
MESSAGE_REGEX = /(?<file>.+)\((?<line>\d+)\):(?<type>[^:]+)/
|
5
|
+
|
6
|
+
MESSAGE_TYPE_CATEGORIZER = lambda do |type|
|
7
|
+
type =~ /warning/ ? :warning : :error
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
file_flags = applicable_files.map { |file| ['-process', file] }
|
12
|
+
result = execute(command + file_flags.flatten)
|
13
|
+
return :pass if result.success?
|
14
|
+
|
15
|
+
# example message:
|
16
|
+
# path/to/file.js(1): lint warning: Error message
|
17
|
+
extract_messages(
|
18
|
+
result.stdout.split("\n").grep(MESSAGE_REGEX),
|
19
|
+
MESSAGE_REGEX,
|
20
|
+
MESSAGE_TYPE_CATEGORIZER
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -1,22 +1,19 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
1
|
module Overcommit::Hook::PreCommit
|
4
2
|
# Checks the syntax of any modified JSON files.
|
5
3
|
class JsonSyntax < Base
|
6
4
|
def run
|
7
|
-
|
5
|
+
messages = []
|
8
6
|
|
9
7
|
applicable_files.each do |file|
|
10
8
|
begin
|
11
9
|
JSON.parse(IO.read(file))
|
12
10
|
rescue JSON::ParserError => e
|
13
|
-
|
11
|
+
error = "#{e.message} parsing #{file}"
|
12
|
+
messages << Overcommit::Hook::Message.new(:error, file, nil, error)
|
14
13
|
end
|
15
14
|
end
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
[:fail, output]
|
16
|
+
messages
|
20
17
|
end
|
21
18
|
end
|
22
19
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Overcommit::Hook::PreCommit
|
2
|
+
# Runs `ruby-lint` against any modified Ruby files.
|
3
|
+
class RubyLint < Base
|
4
|
+
MESSAGE_TYPE_CATEGORIZER = lambda do |type|
|
5
|
+
type.include?('W') ? :warning : :error
|
6
|
+
end
|
7
|
+
|
8
|
+
def run
|
9
|
+
result = execute(command + applicable_files)
|
10
|
+
return :pass if result.success?
|
11
|
+
|
12
|
+
extract_messages(
|
13
|
+
result.stdout.split("\n"),
|
14
|
+
/^(?<file>[^:]+):(?<type>[^:]+):(?<line>\d+)/,
|
15
|
+
MESSAGE_TYPE_CATEGORIZER
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -7,7 +7,14 @@ module Overcommit::Hook::PreCommit
|
|
7
7
|
|
8
8
|
def run
|
9
9
|
result = execute(command + applicable_files)
|
10
|
-
|
10
|
+
|
11
|
+
# Status code 81 indicates the applicable files were all filtered by
|
12
|
+
# exclusions defined by the configuration. In this case, we're happy to
|
13
|
+
# return success since there were technically no lints.
|
14
|
+
return :pass if [0, 81].include?(result.status)
|
15
|
+
|
16
|
+
# Any status that isn't indicating lint warnings or errors indicates failure
|
17
|
+
return :fail, result.stdout unless [1, 2].include?(result.status)
|
11
18
|
|
12
19
|
extract_messages(
|
13
20
|
result.stdout.split("\n"),
|
@@ -2,24 +2,10 @@ module Overcommit::Hook::PreCommit
|
|
2
2
|
# Runs `w3c_validators` against any modified CSS files.
|
3
3
|
class W3cCss < Base
|
4
4
|
def run
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
10
|
-
|
11
|
-
result_messages =
|
12
|
-
begin
|
13
|
-
collect_messages
|
14
|
-
rescue W3CValidators::ValidatorUnavailable => e
|
15
|
-
return :fail, e.message
|
16
|
-
rescue W3CValidators::ParsingError => e
|
17
|
-
return :fail, e.message
|
18
|
-
end
|
19
|
-
|
20
|
-
return :pass if result_messages.empty?
|
21
|
-
|
22
|
-
result_messages
|
5
|
+
collect_messages
|
6
|
+
rescue W3CValidators::ParsingError,
|
7
|
+
W3CValidators::ValidatorUnavailable => e
|
8
|
+
[:fail, e.message]
|
23
9
|
end
|
24
10
|
|
25
11
|
private
|
@@ -2,24 +2,10 @@ module Overcommit::Hook::PreCommit
|
|
2
2
|
# Runs `w3c_validators` against any modified HTML files.
|
3
3
|
class W3cHtml < Base
|
4
4
|
def run
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
10
|
-
|
11
|
-
result_messages =
|
12
|
-
begin
|
13
|
-
collect_messages
|
14
|
-
rescue W3CValidators::ValidatorUnavailable => e
|
15
|
-
return :fail, e.message
|
16
|
-
rescue W3CValidators::ParsingError => e
|
17
|
-
return :fail, e.message
|
18
|
-
end
|
19
|
-
|
20
|
-
return :pass if result_messages.empty?
|
21
|
-
|
22
|
-
result_messages
|
5
|
+
collect_messages
|
6
|
+
rescue W3CValidators::ParsingError,
|
7
|
+
W3CValidators::ValidatorUnavailable => e
|
8
|
+
[:fail, e.message]
|
23
9
|
end
|
24
10
|
|
25
11
|
private
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Overcommit::Hook::PreCommit
|
2
|
+
# Checks the syntax of any modified XML files.
|
3
|
+
class XmlSyntax < Base
|
4
|
+
def run
|
5
|
+
messages = []
|
6
|
+
|
7
|
+
applicable_files.each do |file|
|
8
|
+
begin
|
9
|
+
REXML::Document.new(IO.read(file))
|
10
|
+
rescue REXML::ParseException => e
|
11
|
+
error = "Error parsing #{file}: #{e.message}"
|
12
|
+
messages << Overcommit::Hook::Message.new(:error, file, nil, error)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
messages
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,22 +1,18 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
|
3
1
|
module Overcommit::Hook::PreCommit
|
4
2
|
# Checks the syntax of any modified YAML files.
|
5
3
|
class YamlSyntax < Base
|
6
4
|
def run
|
7
|
-
|
5
|
+
messages = []
|
8
6
|
|
9
7
|
applicable_files.each do |file|
|
10
8
|
begin
|
11
9
|
YAML.load_file(file)
|
12
|
-
rescue ArgumentError => e
|
13
|
-
|
10
|
+
rescue ArgumentError, Psych::SyntaxError => e
|
11
|
+
messages << Overcommit::Hook::Message.new(:error, file, nil, e.message)
|
14
12
|
end
|
15
13
|
end
|
16
14
|
|
17
|
-
|
18
|
-
|
19
|
-
[:fail, output]
|
15
|
+
messages
|
20
16
|
end
|
21
17
|
end
|
22
18
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Overcommit::Hook::PrePush
|
2
|
+
# Prevents destructive updates to specified branches.
|
3
|
+
class ProtectedBranches < Base
|
4
|
+
def run
|
5
|
+
return :pass unless illegal_pushes.any?
|
6
|
+
|
7
|
+
messages = illegal_pushes.map do |pushed_ref|
|
8
|
+
"Deleting or force-pushing to #{pushed_ref.remote_ref} is not allowed."
|
9
|
+
end
|
10
|
+
|
11
|
+
[:fail, messages.join("\n")]
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def branches
|
17
|
+
@branches ||= config['branches']
|
18
|
+
end
|
19
|
+
|
20
|
+
def illegal_pushes
|
21
|
+
@illegal_pushes ||= pushed_refs.select do |pushed_ref|
|
22
|
+
(pushed_ref.deleted? || pushed_ref.forced?) &&
|
23
|
+
branches.any? { |branch| pushed_ref.remote_ref == "refs/heads/#{branch}" }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Overcommit::Hook::PreRebase
|
4
|
+
# Functionality common to all pre-rebase hooks.
|
5
|
+
class Base < Overcommit::Hook::Base
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
def_delegators :@context,
|
9
|
+
:upstream_branch, :rebased_branch, :fast_forward?, :rebased_commits
|
10
|
+
end
|
11
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# Utility module which manages the creation of {HookContext}s.
|
2
2
|
module Overcommit::HookContext
|
3
|
-
def self.create(hook_type, config, args)
|
3
|
+
def self.create(hook_type, config, args, input)
|
4
4
|
hook_type_class = Overcommit::Utils.camel_case(hook_type)
|
5
5
|
underscored_hook_type = Overcommit::Utils.snake_case(hook_type)
|
6
6
|
|
7
7
|
require "overcommit/hook_context/#{underscored_hook_type}"
|
8
8
|
|
9
|
-
Overcommit::HookContext.const_get(hook_type_class).new(config, args)
|
9
|
+
Overcommit::HookContext.const_get(hook_type_class).new(config, args, input)
|
10
10
|
rescue LoadError, NameError => error
|
11
11
|
# Could happen when a symlink was created for a hook type Overcommit does
|
12
12
|
# not yet support.
|
@@ -13,9 +13,10 @@ module Overcommit::HookContext
|
|
13
13
|
class Base
|
14
14
|
# @param config [Overcommit::Configuration]
|
15
15
|
# @param args [Array<String>]
|
16
|
-
def initialize(config, args)
|
16
|
+
def initialize(config, args, input)
|
17
17
|
@config = config
|
18
18
|
@args = args
|
19
|
+
@input = input
|
19
20
|
end
|
20
21
|
|
21
22
|
# Returns the camel-cased type of this hook (e.g. PreCommit)
|
@@ -58,12 +59,9 @@ module Overcommit::HookContext
|
|
58
59
|
[]
|
59
60
|
end
|
60
61
|
|
61
|
-
# Returns
|
62
|
-
|
63
|
-
|
64
|
-
# there is a concept of files changing for the type of hook being run.
|
65
|
-
def modified_lines(_file)
|
66
|
-
Set.new
|
62
|
+
# Returns an array of lines passed to the hook via STDIN.
|
63
|
+
def input_lines
|
64
|
+
@input_lines ||= @input.read.split("\n")
|
67
65
|
end
|
68
66
|
end
|
69
67
|
end
|
@@ -7,7 +7,30 @@ module Overcommit::HookContext
|
|
7
7
|
# This includes staged files, which lines of those files have been modified,
|
8
8
|
# etc. It is also responsible for saving/restoring the state of the repo so
|
9
9
|
# hooks only inspect staged changes.
|
10
|
-
class PreCommit < Base
|
10
|
+
class PreCommit < Base # rubocop:disable ClassLength
|
11
|
+
# Returns whether this hook run was triggered by `git commit --amend`
|
12
|
+
def amendment?
|
13
|
+
return @amendment unless @amendment.nil?
|
14
|
+
|
15
|
+
cmd = Overcommit::Utils.parent_command
|
16
|
+
amend_pattern = 'commit(\s.*)?\s--amend(\s|$)'
|
17
|
+
|
18
|
+
return @amendment if
|
19
|
+
# True if the command is a commit with the --amend flag
|
20
|
+
@amendment = !(/\s#{amend_pattern}/ =~ cmd).nil?
|
21
|
+
|
22
|
+
# Check for git aliases that call `commit --amend`
|
23
|
+
`git config --get-regexp '^alias\\.' '#{amend_pattern}'`.
|
24
|
+
scan(/alias\.([-\w]+)/). # Extract the alias
|
25
|
+
each do |match|
|
26
|
+
return @amendment if
|
27
|
+
# True if the command uses a git alias for `commit --amend`
|
28
|
+
@amendment = !(/git\s+#{match[0]}/ =~ cmd).nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
@amendment
|
32
|
+
end
|
33
|
+
|
11
34
|
# Stash unstaged contents of files so hooks don't see changes that aren't
|
12
35
|
# about to be committed.
|
13
36
|
def setup_environment
|
@@ -18,9 +41,9 @@ module Overcommit::HookContext
|
|
18
41
|
if !initial_commit? && any_changes?
|
19
42
|
@stash_attempted = true
|
20
43
|
|
44
|
+
stash_message = "Overcommit: Stash of repo state before hook run at #{Time.now}"
|
21
45
|
result = Overcommit::Utils.execute(
|
22
|
-
%w[git stash save --keep-index --quiet] +
|
23
|
-
["Overcommit: Stash of repo state before hook run at #{Time.now}"]
|
46
|
+
%w[git stash save --keep-index --quiet] + [stash_message]
|
24
47
|
)
|
25
48
|
|
26
49
|
unless result.success?
|
@@ -31,7 +54,7 @@ module Overcommit::HookContext
|
|
31
54
|
"\nSTDOUT:#{result.stdout}\nSTDERR:#{result.stderr}"
|
32
55
|
end
|
33
56
|
|
34
|
-
@changes_stashed =
|
57
|
+
@changes_stashed = `git stash list -1`.include?(stash_message)
|
35
58
|
end
|
36
59
|
|
37
60
|
# While running the hooks make it appear as if nothing changed
|
@@ -64,34 +87,58 @@ module Overcommit::HookContext
|
|
64
87
|
# Get a list of added, copied, or modified files that have been staged.
|
65
88
|
# Renames and deletions are ignored, since there should be nothing to check.
|
66
89
|
def modified_files
|
67
|
-
@modified_files
|
68
|
-
|
90
|
+
unless @modified_files
|
91
|
+
@modified_files = Overcommit::GitRepo.modified_files(staged: true)
|
69
92
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
93
|
+
# Include files modified in last commit if amending
|
94
|
+
if amendment?
|
95
|
+
subcmd = 'show --format=%n'
|
96
|
+
@modified_files += Overcommit::GitRepo.modified_files(subcmd: subcmd)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
@modified_files
|
75
100
|
end
|
76
101
|
|
77
102
|
# Returns the set of line numbers corresponding to the lines that were
|
78
103
|
# changed in a specified file.
|
79
104
|
def modified_lines_in_file(file)
|
80
105
|
@modified_lines ||= {}
|
81
|
-
@modified_lines[file]
|
82
|
-
|
106
|
+
unless @modified_lines[file]
|
107
|
+
@modified_lines[file] =
|
108
|
+
Overcommit::GitRepo.extract_modified_lines(file, staged: true)
|
109
|
+
|
110
|
+
# Include lines modified in last commit if amending
|
111
|
+
if amendment?
|
112
|
+
subcmd = 'show --format=%n'
|
113
|
+
@modified_lines[file] +=
|
114
|
+
Overcommit::GitRepo.extract_modified_lines(file, subcmd: subcmd)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
@modified_lines[file]
|
83
118
|
end
|
84
119
|
|
85
120
|
private
|
86
121
|
|
87
122
|
# Clears the working tree so that the stash can be applied.
|
88
123
|
def clear_working_tree
|
124
|
+
removed_submodules = Overcommit::GitRepo.staged_submodule_removals
|
125
|
+
|
89
126
|
result = Overcommit::Utils.execute(%w[git reset --hard])
|
90
127
|
unless result.success?
|
91
128
|
raise Overcommit::Exceptions::HookCleanupFailed,
|
92
129
|
"Unable to cleanup working tree after #{hook_script_name} hooks run:" \
|
93
130
|
"\nSTDOUT:#{result.stdout}\nSTDERR:#{result.stderr}"
|
94
131
|
end
|
132
|
+
|
133
|
+
# Hard-resetting a staged submodule removal results in the index being
|
134
|
+
# reset but the submodule being restored as an empty directory. This empty
|
135
|
+
# directory prevents us from stashing on a subsequent run if a hook fails.
|
136
|
+
#
|
137
|
+
# Work around this by removing these empty submodule directories as there
|
138
|
+
# doesn't appear any reason to keep them around.
|
139
|
+
removed_submodules.each do |submodule|
|
140
|
+
FileUtils.rmdir(submodule.path)
|
141
|
+
end
|
95
142
|
end
|
96
143
|
|
97
144
|
# Applies the stash to the working tree to restore the user's state.
|
@@ -128,8 +175,12 @@ module Overcommit::HookContext
|
|
128
175
|
def store_modified_times
|
129
176
|
@modified_times = {}
|
130
177
|
|
131
|
-
|
178
|
+
staged_files = modified_files
|
179
|
+
unstaged_files = Overcommit::GitRepo.modified_files(staged: false)
|
180
|
+
|
181
|
+
(staged_files + unstaged_files).each do |file|
|
132
182
|
next if Overcommit::Utils.broken_symlink?(file)
|
183
|
+
next unless File.exist?(file) # Ignore renamed files (old file no longer exists)
|
133
184
|
@modified_times[file] = File.mtime(file)
|
134
185
|
end
|
135
186
|
end
|
@@ -137,10 +188,9 @@ module Overcommit::HookContext
|
|
137
188
|
# Restores the file modification times for all modified files to make it
|
138
189
|
# appear like they never changed.
|
139
190
|
def restore_modified_times
|
140
|
-
|
191
|
+
@modified_times.each do |file, time|
|
141
192
|
next if Overcommit::Utils.broken_symlink?(file)
|
142
193
|
next unless File.exist?(file)
|
143
|
-
time = @modified_times[file]
|
144
194
|
File.utime(time, time, file)
|
145
195
|
end
|
146
196
|
end
|