From other answers here, I was kind of confused with how git rebase -i could be used to remove a commit, so I hope it's OK to jot down my test case here (very similar to the OP).
Here is a bash script that you can paste in to create a test repository in the /tmp folder:
set -x
rm -rf /tmp/myrepo*
cd /tmp
mkdir myrepo_git
cd myrepo_git
git init
git config user.name me
git config user.email me@myself.com
mkdir folder
echo aaaa >> folder/file.txt
git add folder/file.txt
git commit -m "1st git commit"
echo bbbb >> folder/file.txt
git add folder/file.txt
git commit -m "2nd git commit"
echo cccc >> folder/file.txt
git add folder/file.txt
git commit -m "3rd git commit"
echo dddd >> folder/file.txt
git add folder/file.txt
git commit -m "4th git commit"
echo eeee >> folder/file.txt
git add folder/file.txt
git commit -m "5th git commit"
At this point, we have a file.txt with these contents:
aaaa
bbbb
cccc
dddd
eeee
At this point, HEAD is at the 5th commit, HEAD~1 would be the 4th - and HEAD~4 would be the 1st commit (so HEAD~5 wouldn't exist). Let's say we want to remove the 3rd commit - we can issue this command in the myrepo_git directory:
git rebase -i HEAD~4
(Note that git rebase -i HEAD~5 results with "fatal: Needed a single revision; invalid upstream HEAD~5".) A text editor (see screenshot in @Dennis' answer) will open with these contents:
pick 5978582 2nd git commit
pick 448c212 3rd git commit
pick b50213c 4th git commit
pick a9c8fa1 5th git commit
# Rebase b916e7f..a9c8fa1 onto b916e7f
# ...
So we get all commits since (but not including) our requested HEAD~4. Delete the line pick 448c212 3rd git commit and save the file; you'll get this response from git rebase:
error: could not apply b50213c... 4th git commit
When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To check out the original branch and stop rebasing run "git rebase --abort".
Could not apply b50213c... 4th git commit
At this point open myrepo_git/folder/file.txt in a text editor; you'll see it has been modified:
aaaa
bbbb
<<<<<<< HEAD
=======
cccc
dddd
>>>>>>> b50213c... 4th git commit
Basically, git sees that when HEAD got to 2nd commit, there was content of aaaa + bbbb; and then it has a patch of added cccc+dddd which it doesn't know how to append to the existing content.
So here git cannot decide for you - it is you who has to make a decision: by removing the 3rd commit, you either keep the changes introduced by it (here, the line cccc) -- or you don't. If you don't, simply remove the extra lines - including the cccc - in folder/file.txt using a text editor, so it looks like this:
aaaa
bbbb
dddd
... and then save folder/file.txt. Now you can issue the following commands in myrepo_git directory:
$ nano folder/file.txt  # text editor - edit, save
$ git rebase --continue
folder/file.txt: needs merge
You must edit all merge conflicts and then
mark them as resolved using git add
Ah - so in order to mark that we've solved the conflict, we must git add the folder/file.txt, before doing git rebase --continue:
$ git add folder/file.txt
$ git rebase --continue
Here a text editor opens again, showing the line 4th git commit - here we have a chance to change the commit message (which in this case could be meaningfully changed to 4th (and removed 3rd) commit or similar). Let's say you don't want to - so just exit the text editor without saving; once you do that, you'll get:
$ git rebase --continue
[detached HEAD b8275fc] 4th git commit
 1 file changed, 1 insertion(+)
Successfully rebased and updated refs/heads/master.
At this point, now you have a history like this (which you could also inspect with say gitk . or other tools) of the contents of folder/file.txt (with, apparently, unchanged timestamps of the original commits):
1st git commit  |  +aaaa
----------------------------------------------
2nd git commit  |   aaaa
                |  +bbbb
----------------------------------------------
4th git commit  |   aaaa
                |   bbbb
                |  +dddd
----------------------------------------------
5th git commit  |   aaaa
                |   bbbb
                |   dddd
                |  +eeee
And if previously, we decided to keep the line cccc (the contents of the 3rd git commit that we removed), we would have had:
1st git commit  |  +aaaa
----------------------------------------------
2nd git commit  |   aaaa
                |  +bbbb
----------------------------------------------
4th git commit  |   aaaa
                |   bbbb
                |  +cccc
                |  +dddd
----------------------------------------------
5th git commit  |   aaaa
                |   bbbb
                |   cccc
                |   dddd
                |  +eeee
Well, this was the kind of reading I hoped I'd have found, to start grokking how git rebase works in terms of deleting commits/revisions; so hope it might help others too...