8

How can I revert a commit but put the changes but on the stage so I can edit the commit until it is what I want.

Formerly I've been familar with TFS, where revert did exactly that, but in GIT git revert seem to automatically check-in the undone commit, so no chance to keep something from the changeset.

codymanix
  • 28,510
  • 21
  • 92
  • 151

3 Answers3

11

Try this

git reset HEAD^

HEAD^ means the previous commit.

Donat
  • 4,157
  • 3
  • 11
  • 26
  • 3
    Note that this answers a very different question. This might be the question the OP *should* have asked! Resetting away a bogus commit is sometimes the best way to go. But it's not the same as making a new commit that undoes a bad one. – torek Nov 23 '19 at 18:14
5
(make sure that you have a clean working directory)
git revert <commit>
(accept commit message)
git reset HEAD^

This will make it so that you have local changes that could revert the commit if you accepted everything, but allows you to only choose a few lines to revert. You can also change to git reset HEAD^ --soft if you want to have the changes put in your staging area.

I agree with the other answer that it is probably better to revert a full commit if you are dealing with other people's history. I use this revert + reset often when I rebase and fix my own changes though.

MrBerta
  • 2,457
  • 12
  • 24
4

You can use git revert -n. I would advise that you don't. Make a separate commit to make the changes that you do want.

The reason for that is simple enough. A commit is a snapshot, but it represents a change. To find the change from the snapshot, Git compares the commit to its immediate parent.

That is, if file A had 10 lines before, and has 11 now, comparing the old copy of file A to the new copy of file A will (probably) show that someone added one line. The diff will say: to change the old commit to the new one, add this one line to file A. If file B had 20 lines before, and has 19 now, the diff will say: to change the old commit to the new one, delete this one line from file B.

A simple git revert that commits will, when shown, show the same change but backwards: delete this one line from file A, and add this one line to file B.

If what you meant—and will commit in this third commit—is to just add the one line to file A, now you have a correct single commit which, when shown, will say add this one line to file A.

If you instead make a non-committing revert, then put the line back, you'll have to add together two separate commits—the mistaken one, and the correcting revert—to see what was actually intended. That's not wrong, but it means that anyone coming along later, to see what happened and what they might need to do in some similar situation, has to work harder.

Compare these instructions:

  1. "Do X; wait, no, don't do X. Do Y."
  2. "Do X. Then while undoing X, do Z."

Which would future-you prefer to see?

(Note that you can construct commit Y by doing:

git cherry-pick -n X

where X is the one that you reverted. That way, you get all the changes, but can start undoing them.

Note also that git revert -n and git cherry-pick -n put everything into the staging area—that is, they do a git add on all the updated files. There's no actual problem with that, but if you don't like it, you can run git reset to un-stage.)

torek
  • 448,244
  • 59
  • 642
  • 775
  • This is a very valid argument if the original intention was to _keep_ the original commit and the reverted commit. However, I think the OP was suggesting to eradicate the original commit (X) entirely, in which case others would only ever see Y. – Michael Sorens Nov 25 '19 at 14:55
  • Should have also said: eradicating a commit introduces its own hazards! :-) – Michael Sorens Nov 25 '19 at 15:02
  • @MichaelSorens: Yes—though if you have never *sent* the commit anywhere (e.g., if it's private to your own repository and you never ran `git push`) it's safe. This is also where `git reset HEAD~1` or equivalent comes in, if the commit was the most recent one. – torek Nov 25 '19 at 16:41