Reputation: 2268
I have a Git
repository whose commit history is the following:
A -> B -> C
(C
being the latest commit) and this entire history is pushed to a public remote repository. Can I do the following ?
Go back to B
state and have C
as un-staged changes ?
As A -> B -> C
is pushed to remote repo, I cannot expect a git reset B
. But what I can expect is A -> B -> C -> B'
where, B'
is the same state as B
but with C
as un-staged changes.
Upvotes: 1
Views: 1715
Reputation: 38106
You can use below commands to meet your requirement:
git revert <commit id for B>
git checkout <commit id for C> -- *.* & git reset HEAD *.*
Upvotes: 0
Reputation: 488213
As Ovsyanka answered, git reset
does do what you're asking for in terms of work tree (and, for that matter, the index / staging area too: you control whether the index resets to the target commit B
, or not, using --mixed
vs --soft
). However, if you do a regular git revert C
, then do the usual edit-add-commit sequence, you will get:
A--B--C--unC--D
i.e., a total of 5 commits. Should you not want that, you can use:
git revert -n C
which reverts C
in your work tree (and index) without actually committing. You can then make further changes and commit again, giving:
A--B--C--D
where D
undoes C
and makes further changes.
There is a good reason to stick with a simple revert, though. Suppose someone—perhaps even you yourself—comes back to this project in the future, say, a year from now. This person is wondering what happened in the past, and is looking through the commits. They come upon commit D
, which when inspected, clearly undoes some of commit C
and also does some other stuff, and they wonder: "Hey, who threw out all that good work in C
? Wait, it was the same guy who wrote C
. What the ...?"
If they come across, instead, the C--unC--D
sequence, with commit unC
being "revert ", they—which might, again, be you yourself—will immediately know: "Aha, the person who reverted C
is saying C
was wrong, and then the person who added D
is making a different change... oh, huh, that person is me. Oh yeah, I remember now!"
Even if you haven't pushed / published commit C
, it's still a pretty good idea to revert it like this. Then, before you actually git push
your sequence of commits, you can run git rebase -i
and delete both C
and its reversion, to make it look like you never made that mistake. (Or, equivalently, squash a bunch of commits together so that you have one "really good" change, or a small set of "really sensible" changes, rather than a meandering collection of "try this, try that too, oh wait the first one was wrong, ah we need this auxiliary fix as well, oh and before we did any of these changes, it would have been nice if we'd fixed this main problem in the tests! then we'd have seen just what was wrong, and it would be obvious what we were fixing and why!")
Upvotes: 3
Reputation: 418
git reset --mixed B
do what you wants:
Resets the index but not the working tree (i.e., the changed files are preserved but not marked for commit) and reports what has not been updated. This is the default action.
But if you want to actually remove C changes, not just fix it there will be better to make revert C commit and then do another commits. It will be clear to other peoples, that you completle discarded C commit changes.
You can use git revert C
- then you will have clezn working directory and history 'A - B - C - C(rev)' and state of files will be wxactly like in B.
Upvotes: 1