One day, I wanted to rollback git repository to a previous commit with a new “rollback” commit because the wrong commits had already pushed to the master.
MODIFIED: The best way is git revert -n INITHASH..HEAD
!
Thanks, @miyagawa!
$ git init
$ echo important > important
$ touch important_empty
$ git add .
$ git commit -m 'init'
$ ls
important important_empty
$ git rm important important_empty
$ echo wrong > wrong
$ touch wrong_empty
$ git add .
$ git commit -m 'wrong' ## WRONG COMMIT!
$ ls
wrong wrong_empty
$ git revert -n INITHASH..HEAD
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: important
# renamed: wrong_empty -> important_empty
# deleted: wrong
#
$ ls
important important_empty
old posts
Generally, git revert -n HASH
works, however, if some files are added or deleted, it doesn’t work well. Here is an example.
git revert
is not the way to revert “to HASH”, but to revert “HASH”.
$ git revert -n INITHASH ## want to rollback to INITHASH
$ git status
# On branch master
nothing to commit, working directory clean
$ ls
wrong wrong_empty
So, I tried some ways. First, git checkout INITHASN .
. It worked only for deleted files.
$ git checkout INITHASH .
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: important
# new file: important_empty
#
$ ls
important important_empty wrong wrong_empty
Second, git checkout -b rollback INITHASH
and git merge
. Unfortunately, INITHASH
had already merged, so it happened nothing.
$ git checkout -b rollback INITHASH
$ ls
important important_empty
$ git checkout master
$ git merge rollback
Already up-to-date.
Third, git diff
and patch
. It affected only non-empty files because git diff
output for empty files was not good for patch
command.
$ git diff HEAD..INITHASH | patch -p1
patching file important
patching file wrong
$ git status
# On branch master
# Changes not staged for commit:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# deleted: wrong
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# important
no changes added to commit (use "git add" and/or "git commit -a")
$ ls
important wrong_empty
Finally, I found the best way, that is git apply
.
$ git diff HEAD..INITHASH > /tmp/patch
$ git apply /tmp/patch
$ git status
# On branch master
# Changes not staged for commit:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# deleted: wrong
# deleted: wrong_empty
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# important
# important_empty
no changes added to commit (use "git add" and/or "git commit -a")
$ ls
important important_empty
Hey, git experts, is this the best way to create a new “rollback” commit?