Undoing Things · practice
I Made a Commit That Should Not Be a Commit
You committed something that should not have been a
Amending would replace it with a different commit, and you do not want a different commit. You want one fewer.
Make the mistake first
The scratch.tmp, holding two personal reminders. Commit it as though you had not been paying attention:
git add scratch.tmp
git commit -m "wip"
git log
git add scratch.tmp stages it whether or not it was already staged, so this works the same however you arrived at this lesson. git log now shows a commit called wip holding a private to-do list. It should not be in the project’s history at all.
Move the branch back
Your line of work has a name, main, and that name marks which commit is the newest one in it. git reset moves the mark. Send it back one commit and the wip commit stops being part of your history:
git reset --soft HEAD~1
git log
git status
That name is called a
HEAD~1 means “one commit before where I am now”. --soft is the important part: it moves that name and nothing else. Your files are not touched, and everything the undone commit contained is left sitting in the
git log no longer lists wip. git status shows scratch.tmp staged again, which is exactly where it was before you committed. You are back to the decision, not past it.
Finish the job by taking it off the list, the way you did earlier in this chapter:
git restore --staged scratch.tmp
git status
The three resets, and the dangerous one
In the commit-moving form used here, git reset moves the branch pointer. What differs is how much else it changes:
--softmoves the pointer only. Your changes stay staged. Nothing is lost.--mixed, the default when you name no option, moves the pointer and resets the staging area to the target commit. In thisHEAD~1case, the undone commit’s changes become unstaged. Your files keep their contents, so nothing is lost, but you will need to stage those changes again.--hardmoves the pointer, resets the staging area, and overwrites tracked files to match. Staged or unstaged edits to tracked files are gone. Untracked files usually remain, although Git may remove one if it blocks a tracked path.
Read that last one twice. git reset --hard can destroy tracked work you have no copy of. It is not forbidden and it is genuinely useful, but run it only after reading git status and deciding that every staged or unstaged tracked edit may be discarded.
The commit you reset away is a different story. It is not deleted, only unreferenced, which is the subject of the last lesson in this chapter.
When not to use this
Reset removes a commit from your branch. If somebody else already has that commit, their history still contains it and yours no longer does, and the two have to be reconciled by hand.
Reset a commit only while it is still private.
Here you made the wip commit yourself, seconds ago, in your own repository. That is the safe case. The next lesson is the other one.
You run git reset --soft HEAD~1 after a commit you regret. What happens to the changes that were in that commit?
Next: the same mistake, except somebody else already has it.