-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve undo action to restore files upon undoing a commit #4167
Improve undo action to restore files upon undoing a commit #4167
Conversation
Note: I was not able to get the tests to run on a codespace. It shows a "POTENTIAL DEADLOCK" error every time I run it, but the other pre-existing tests next to this one show the same error, so i dont think it's an issue with my newly added tests. I'm not a go programmer so i'm not sure how to debug that further. This is the error I was getting:
|
I'd like to explore how we can do this without adding any new config items, because our config is already too big. Could we instead prompt the user to select soft/mixed/hard whenever they go to undo a commit? Or should it always do soft? As for rebases, I don't see why we would ever want to do a soft/mixed reset. What use case are you thinking of there? Is it just for the sake of not clobbering changes in the filetree when resetting? Because if so, a better solution could be to stash the working tree changes and then unstash after. Keen to get your thoughts on this too @stefanhaller |
First, I agree about trying to avoid adding new config options if possible. Second, I feel that @gabriellanata is "abusing" undo for something that it wasn't meant for. For me, undo means "put my repo back into the state that it was in before the last operation (no matter how I arrived at that state)". Ideally this would be a command that is built into git ( If you want to do a reset but keep your changes, I find it more appropriate to actually perform a reset operation, i.e. select the commit that you want to reset to, and press
I agree, but it seems we already do that. :) |
I'm interested in playing out what the downsides are of always soft-resetting when undoing a commit. Suppose that I:
Now I undo all of these: This could cause an issue if branch A has conflicts with what's in your working tree, and the reason this isn't clean is that there's no undo action for writing the code in the first place. But, this doesn't seem so bad to me, in fact it seems superior to the current behaviour. What if we commit some code, the rebase onto another branch, then commit some more code. Undoing that would involve a soft reset, then a hard reset (but with a stash pushed/popped), then another soft reset. Again, this doesn't seem so bad. It sounds like the worst that could happen is conflicts. Reflecting on my own usage, I typically only use undo after doing some rebase or cherry pick operation. If I had just committed some code and I wanted to easily undo that, I don't see an issue with that being a soft reset. Can you guys think of any especially egregious situations that could come about if we enforce that undoing a commit always uses a soft reset? |
Egregious, no, but confusing, perhaps. When I use undo I typically don't pay much attention to what operation it is that I'm undoing, and I would find it confusing if undoing sometimes leaves stuff in my working copy and other times it doesn't. |
I completely agree with the "put my repo back into the state that it was in before the last operation (no matter how I arrived at that state)". But IMO this is not what is happening right now.
To me, that is not the state that my repo was in before the last operation as I would have expected my changes to be back in the working directory. One simple example which is what i wanted to do: I committed my changes and immediately realized i committed one additional file accidentally. So I ran undo which removed the commit but didn't put my files back.
I find it more confusing if i had files on my working directory before the previous operation and performing an undo doesn't put them back. The first time I ran it I even had to check multiple times if I had done something wrong.
I agree that maybe rebase undo config is not a requirement. I added for completeness of the configuration options, but if the concern is bloating then it can definitely be removed.
As i said in the original PR description and on the example above, this is IMO what makes the most sense. I was adding it as a config option because I didn't want to break existing workflows, but that is up to you. Happy to update my PR to whatever you prefer |
Hm, ok. I still find it surprising and confusing, but that's not a blocking objection if I'm the only one who feels this way.
For the record, what I do in such a case is to press enter on the commit, press space on the file that was accidentally added, and press |
Something that just occurred to me: a few times now I've accidentally amended the wrong commit (whether that's amending the head commit or another commit) and whenever I do that it is a real pain trying to undo the change, because often it's not as simple as just picking one or two files to pull back out: sometimes a file you committed was already part of the commit you amended so you need to get very surgical to undo the operation. Last time this happened I used a diff between the current commit and the old reflog commit and then copied the changes from that via a custom patch and then hard reset to the old commit and applied the changes, but it was a real hassle. If I could just press undo to get the same result, that would be a huge improvement. If I look at the reflog in both cases, then soft-resetting on a commit operation (and hard-resetting with auto-stash on the rebase operation) works perfectly:
So I am thinking that an undo action on a commit should always be a soft reset, and rebase should stay as-is (hard reset with autostash). The only time you as a user perform a commit operation is when you have code in your working tree that you commit. Undoing that action via hard reset necessarily means you're not properly undoing the action because now that code is gone. |
That makes a lot of sense. |
I updated the PR, let me know what you think |
Ok, I'm persuaded now that soft-resetting when undoing a commit is better. The one situation that won me over is amending the head commit. For all other situations of creating commits it's much less of a deal for me, because it's so easy to explicitly reset to the commit before instead of undoing; but after an amend I don't see the commit to reset to unless I manually look for it in the reflog view, which is cumbersome. So that's a nice improvement indeed. There's something strange about redoing though. When I undo an amend I get the previous changes back (staged), but when I then immediately redo, I then still have those changes in the unstaged changes, but the reverse of those changes staged. I find this very confusing. At first I suspected this might be improved by doing a mixed reset rather than soft, but that makes it so that I only have the reverse of the original changes as unstaged changes. This doesn't make sense to me, and after thinking about it more I am coming to the conclusion that soft-resetting should only be done for undo; redo should still hard-reset. (Testing this a bit more with normal, non-amend commits: same here. After redoing I want to get back to the state after making the commit, at which point my working copy was empty. It doesn't make sense to put the reverse of the committed changes in the working copy when redoing a commit.) A few remarks about the code changes:
|
The redo case is interesting. Playing around with it locally where I have two changed files, and only commit one of them: hard+autostash indeed is better than soft+autostash. Soft without autostash seems good too (faster, no prompt required) but there's probably cases where it's problematic like if you've made changes since undoing that would cause conflicts (an auto-stash will handle those conflicts properly)
We should set up a cron via github actions for that, or even do it for every merged PR. |
For the changes that you didn't commit, yes; those get preserved in the same way either with autostash or with soft reset. But for the changes in the commit that you are redoing it doesn't make sense to preserve them in reverse in the index after redo, like soft reset does.
That would depend on getting the crowdin command-line tool to work, which I didn't succeed with so far. |
They won't be preserved though: I tested this myself and the outcome with soft without autosquash was identical to hard with autosquash. Nevertheless, hard+autosquash is probably more robust.
Ah, yes |
Only if you undo and then redo and don't touch your working copy in between, because then the two soft resets cancel each other out. My use case was:
|
Yeah, that makes sense |
9d7837b
to
87e0d46
Compare
Updated the PR with the latest comments |
2090d75
to
9af953a
Compare
This looks pretty good now. I took the liberty of pushing two commits, one that fixes formatting (it's a good idea to configure your editor to format automatically on save), and one that slightly simplifies the code in a minor way. It would be good if you could squash all commits down into one, with a commit message that describes the latest approach. One last thing though: we are still doing the auto-stash thing even for the soft reset. That's unnecessary, since soft-reset already preserves any modifications in the working copy (whether staged or unstaged). An easy fix could be to add |
I have joined the party with my own commit. Let me know your thoughts |
Looks great. I added one more commit to revert an unnecessary earlier renaming, so that we get a smaller overall diff. |
LGTM |
Something that I'm now wondering: does the auto-stash even need user confirmation? It seems silly to prompt when redoing a commit given that you're guaranteed to have changes in your working tree so you couldn't perform the redo without an auto-stash. We also already mention the auto-stash in the initial prompt: hitting the user with another prompt feels excessive. |
I have wondered the same for other situations where we offer to auto-stash, e.g. when checking out a different branch. No strong opinion either way though. I guess the prompt is nice in the case that popping the stash conflicts, because then it's a bit clearer what's going on (i.e. "you asked for it" :) If anything, what bothers me is that we mention auto-stashing twice, in the original prompt and then again in the auto-stash prompt. So if we decide we want to keep the second prompt, we should at least remove the "An auto-stash will be performed if necessary" from the first one.
That's not true though, see above. |
I've added a commit which removes the second prompt and adds a mention of a potential auto-stash to the first prompt for checkout actions (which was not previously present)
Ah, yes. |
Works for me. Note that when I mentioned checking out a branch in my previous comment, I didn't mean undoing a checkout, but actually checking out by pressing space. But there the situation is different because there is no initial prompt for that operation, so I guess the extra auto-stash confirmation is justified in that case. Another thing that I just noticed is that reverting a commit can't be undone; it will reset to the state before whatever other action was done before that. Would be nice to support this, but it's unrelated to this PR. |
Agreed.
Also agreed. I'm gonna go ahead and squash these commits and merge. |
98d62ad
to
4065175
Compare
Right now, undoing a commit performs a hard reset, which also discards all the changes from that commit. This PR adds new config options (and a new
undo
section) which allow users to choose betweenhard
andsoft
reset modes when undoing commits.Personally, I think that the default should be
soft
, because the state before the commit had the files, so undoing a commit should put the files where they were before. But this PR keepshard
as the default and does not change current behavior.go generate ./...
)