Skip to content

Commit c45c725

Browse files
committed
Gracefully handle failed cleanups
"Graceful" is a bit misleading here, as the best we can do is not ignore that a problem occurred. A problem that could occur is that if a file was placed in between `git reset`ing the tree and applying the stash, the stash would silently fail to apply. We need to tell the user that something funky happened. While one approach would be to "pause" and ask the user what to do, this is exceptional enough that we're just going to fail loudly and present some instructions for recovering. Change-Id: I391574ffba861f94cc46ca74f51f640e5d913a5b Reviewed-on: http://gerrit.causes.com/41194 Tested-by: jenkins <jenkins@causes.com> Reviewed-by: Shane da Silva <shane.dasilva@brigade.com>
1 parent a1a94ab commit c45c725

File tree

4 files changed

+31
-4
lines changed

4 files changed

+31
-4
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
* Fix edge case where hitting Ctrl-C after all pre-commit hooks had run
88
but before the cleanup had finished would result in a lost working
99
tree
10+
* Handle edge case where if a file was created in the working directory by a
11+
separate process in between the working tree being reset and the stash being
12+
applied, the hook runner would silently fail
1013

1114
## 0.15.0
1215

lib/overcommit/exceptions.rb

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ class GitConfigError < StandardError; end
88
# Raised when a {HookContext} is unable to setup the environment before a run.
99
class HookSetupFailed < StandardError; end
1010

11+
# Raised when a {HookContext} is unable to clean the environment after a run.
12+
class HookCleanupFailed < StandardError; end
13+
1114
# Raised when a hook run was cancelled by the user.
1215
class HookCancelled < StandardError; end
1316

lib/overcommit/hook_context/pre_commit.rb

+22-2
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ def setup_environment
4242
# as if nothing ever changed.
4343
def cleanup_environment
4444
unless initial_commit? || (@stash_attempted && !@changes_stashed)
45-
`git reset --hard &> /dev/null` # Ensure working tree is clean before popping stash
45+
clear_working_tree # Ensure working tree is clean before restoring it
4646
end
4747

4848
if @changes_stashed
49-
`git stash pop --index --quiet`
49+
restore_working_tree
5050
end
5151

5252
Overcommit::GitRepo.restore_merge_state
@@ -69,6 +69,26 @@ def modified_lines(file)
6969

7070
private
7171

72+
# Clears the working tree so that the stash can be applied.
73+
def clear_working_tree
74+
result = Overcommit::Utils.execute(%w[git reset --hard])
75+
unless result.success?
76+
raise Overcommit::Exceptions::HookCleanupFailed,
77+
"Unable to cleanup working tree after #{hook_script_name} hooks run:" \
78+
"\n#{result.stderr}"
79+
end
80+
end
81+
82+
# Applies the stash to the working tree to restore the user's state.
83+
def restore_working_tree
84+
result = Overcommit::Utils.execute(%w[git stash pop --index --quiet])
85+
unless result.success?
86+
raise Overcommit::Exceptions::HookCleanupFailed,
87+
"Unable to restore working tree after #{hook_script_name} hooks run:" \
88+
"\n#{result.stderr}"
89+
end
90+
end
91+
7292
# Returns whether there are any changes to the working tree, staged or
7393
# otherwise.
7494
def any_changes?

template-dir/hooks/overcommit-hook

+3-2
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,9 @@ rescue Overcommit::Exceptions::HookContextLoadError => error
7878
puts error
7979
puts 'Are you running an old version of Overcommit?'
8080
exit 69 # EX_UNAVAILABLE
81-
rescue Overcommit::Exceptions::HookSetupFailed => error
82-
puts error
81+
rescue Overcommit::Exceptions::HookSetupFailed,
82+
Overcommit::Exceptions::HookCleanupFailed => error
83+
puts error.message
8384
exit 74 # EX_IOERR
8485
rescue Overcommit::Exceptions::HookCancelled
8586
puts 'You cancelled the hook run'

0 commit comments

Comments
 (0)