Reputation: 23362
In my Git repository, I created three commits in a row: commit1
, commit2
, and commit3
.
I then realized I messed up in commit2
and commit3
, and decided to go back to commit1
. To do that, I ran
git checkout commit1
Now I am in commit1
. How do I delete commit2
and commit3
?
Upvotes: 3
Views: 951
Reputation: 66422
Based on your description and under the assumption you were on some branch called mybranch
before checking out commit1
(C1
in my graphs below), you must be in the following situation:
C1 [HEAD]
\
C2 -- C3 [mybranch]
Commits C2
and C3
still appear in the output of git log
because they're still reachable from the mybranch
refererence. Also, note that HEAD
is detached. What you should do is...
Reattach HEAD
to mybranch
, by running
git checkout mybranch
This should put you in the following situation:
C1
\
C2 -- C3 [HEAD -> mybranch]
Reset the mybranch
branch to its tip's grandparent, by running
git reset --hard mybranch~2
That should put you in the following situation:
C1 [HEAD -> mybranch]
Because commits C2
and C3
have now become unreachable (i.e. "deleted"), they're not shown on this last graph.
This may be a bit cheeky, but here is an explanation of why the other two answers won't work. As correctly pointed out by cmbuckley in his comment,
git reset
resets the state of the current branch you’re on (so you’d need to be on the branch to do that). If you’ve checked outcommit1
, you’re probably not on a branch (detached HEAD state).
Since the OP (Imray) is in detached HEAD state, running git-reset before reattaching HEAD to the branch will not move the branch reference in question. Here is a toy example illustrating this.
# set things up
$ mkdir test
$ cd test
$ git init
Initialized empty Git repository in /Users/jubobs/Desktop/test/.git/
# create a first commit
$ touch README
$ git add .
$ git commit -m "add README"
[master (root-commit) 85137ba] add README
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README
# create a second commit
$ printf "foo\n" > README
$ git commit -am "write 'foo' in README"
[master 3948e84] write 'foo' in README
1 file changed, 1 insertion(+)
# inspect the log
$ git log --graph --decorate --oneline --all
* 3948e84 (HEAD, master) write 'foo' in README
* 85137ba add README
# check out the second commit (which detaches the HEAD)
$ git checkout 3948e84
Note: checking out '3948e84'.
# (boilerplate stdout is omitted...)
HEAD is now at 3948e84... write 'foo' in README
# reset to the first commit (equivalent to 'git reset --hard 85137ba')
$ git reset --hard HEAD^
HEAD is now at 85137ba add README
$ git log --graph --decorate --oneline --all
* 3948e84 (master) write 'foo' in README
* 85137ba (HEAD) add README
Note that the git reset
command moved HEAD
to the initial commit, but did not move the master
branch whatsoever. The second commit is not "deleted", because it's still reachable from master
; it is therefore listed in the output of git log
.
Upvotes: 3
Reputation: 4913
git branch -f mybranch
git checkout -
git checkout -
git reset --hard HEAD@{1}
The second option is particular advantageous because you do not need to type the name of your branh or the identity of your current commit. You could even make it an alias.
EDIT: This assumes that you have not been jumping around, and your most recent checkout was from your branch.
Upvotes: 1
Reputation: 9886
I'm going to assume you're in the master branch in your repo for naming purposes, but any branch will do. This can be thought of as simply a pointer to a commit object. You can also think of HEAD as another pointer, which you can move around with git checkout
commit1 -> commit2 -> commit3
^
|
master
If you want to change your master pointer to be at commit1, then you need to issue a git reset
command, as others have indicated.
git reset --hard commit1
This moves the master pointer in the above diagram to same place as the commit1 object.
Note, you aren't actually deleting the commit2 and commit3 objects, it's just that within git there's no branches pointing to them, so git is free to clean them up if it wants to, or you can force it by running a garbage collect with something like:
git gc --aggressive --prune
Until it is actively cleared from your repo, you can still checkout both commit2 and commit3, so despite you moving the master pointer back to commit1 (with git reset
), you have to be careful if (say) you accidentally commit passwords to the repository and are trying to revert back - they will still be in your local repo until pruned.
Upvotes: 1
Reputation: 9413
You want to nuke commit commit3
(Assuming you are currently on commit3 - as HEAD
). you can do following:
git reset --hard HEAD~1
The result is:
commit1 -> commit2
↑
HEAD
You can follow similar process for moving back to commit1
(i.e. git reset --hard HEAD~2
).
Upvotes: 0