Fix issue with restoring stashed code with partially edited files#1251
Fix issue with restoring stashed code with partially edited files#1251mrexox merged 3 commits intoevilmartians:masterfrom
Conversation
743a078 to
1850053
Compare
This fixes evilmartians#1216 by recalculating the changeset after the stash of partially edited files is completed.
1850053 to
4bef010
Compare
|
Thanks for looking into this! #1216 is not a well written issue because as mentioned, it actually contains two. my bad. This appears to address only one of them, the other "revert+retry when restoring stashed fails" remains as far as I can tell. But nevermind, if/when this is merged, I can file another issue for the remaining parts. |
Ah! My bad. My team kept getting bit on this problem on partially staged files so I just trying to fix that. Looking at the issue again, do you have any opinions on comparing the pre-stash changeset or the post-stash changeset? I realize I did post-stage, but your issue sounds like you'd prefer pre-stash. |
|
Operating on post stash changesets is the right thing to do, i.e.
The other issue I'm talking in #1216 is that it's possible that the tools have made changes in step 3) that make the originally stashed changes in step 1) fail to apply when we attempt to restore them in 6). In that case I think the right thing to do would be to remove all changes made by tools in step 3) and attempt restoring again. I.e. what pre-commit does in https://github.com/pre-commit/pre-commit/blob/8a0630ca1aa7f6d5665effe674ebe2022af17919/pre_commit/staged_files_only.py. This is because the changes made by tools can be easily redone, but the stashed changes may contain more valuable work that cannot be automatically/easily redone. |
|
That all makes sense! I've updated the
p.s. I don't regularly write go code, so holler if I made it too Python-y or anything. |
|
@scop Just looking for a ballpark of when this could be reviewed and potentially released. Not trying to rush, just debating if I should move over our laptops to my fork in the meantime to prevent potential data loss. |
|
Sorry for taking so long getting back to this, and thanks heaps for working on it! I intend to try and find time to try this out and review soon(tm) (hopefully this week), unless it is merged before that. But I'd like to note that I'm not a lefthook project member but just an individual (opinionated :)) contributor, and it'll be up to @mrexox et al to decide what goes in and how the tool is to behave, so I cannot promise anything regarding merging and releasing. I do hope that if/when I review/approve this, it'll make their job of accepting this a bit easier though ;) |
| // Capture changeset after stashing partially staged files, so we compare the same state | ||
| // before and after running hooks |
There was a problem hiding this comment.
I'm somewhat wondering why we capture the first changeset at the beginning of before, in addition to this. Maybe because it's kind of necessary also when not stashing changes for fail-on-changes support for that case.
Maybe the first one should be taken only if we are not stashing changed files?
If we fail to get the changeset here for some reason, we still end up comparing the pre-stash changeset (in case taking that one succeeded). If we want to fix that, I suppose we need to add some tracking to differentiate whether we actually succeeded in taking a changeset and it just happened to be empty, or if it's empty because an error occurred.
Failing on changes can be an "important" thing, so from that PoV maybe we should error out if taking any of the changesets fails (both in before() and after() (in after() after trying to restore stashed changes)), instead of just logging warnings about them. That would simplify some corner cases, too, including likely the above one.
| {Command: "git stash drop --quiet 1", Output: ""}, | ||
| }, | ||
| }, | ||
| "stashUnstagedChanges=true failOnChanges=true with partially staged no hook changes": { |
There was a problem hiding this comment.
macOS tests are failing for some reason.
| {Command: "git stash drop --quiet 1", Output: ""}, | ||
| }, | ||
| }, | ||
| "stashUnstagedChanges=true failOnChanges=true with partially staged no hook changes": { |
There was a problem hiding this comment.
If the codecov numbers are sane, this being an important data loss related change, maybe we should look into increasing the test coverage for the changes?
|
Added some observations on a quick read through, did not test (will try to do that sometime later). |
|
Hey guys! I'm really sorry for keeping this PR for so long. I am going to merge it and adjust the code a little bit, I'll try to address the original issue, but I need some time. After that I'll release a new version and ask you to take a look and make sure that everything is in the right places. Thank you for your contribution! |
|
Thanks! Simplistic testing with As a user, as a minor improvement, I think I'd prefer to see something like this diagnostic in the output when lefthook forcibly removes changes made by tools to get the stashed ones to apply: "Could not restore stashed changes. reverting ones made by hooks and retrying". IIRC pre-commit and prek do something like this. |
|
I think it makes sense to defined a task for detecting changes and restoring previous state. I still lean to always printing the diff if changes get detected. If you could prepare a feature-request, and fill it with what's expected, that would be great! |
Closes #1216
Context
#1216 happens because lefthook compares the pre-stash changeset with a post-stash changeset, meaning if you have
fail_on_changesenabled and a partially updated file, it will fail.Changes
This PR adds a copy of the
changesetBeforecode after the stashing code so if we make it to stashing (i.e. it doesn't exit earlier) we reset thechangesetBeforeto be accurate.NOTE: I'm not 100% confident on the test addition. I verified it fails in the current code and passes in the new code, and I've built the binary and manually tested as well. I attempted to match existing code/style.