How to revert a git merge
You have merged a branch to your current branch and a few commits later you realize that you want to revert that merge. How do you do it?
setup
Let’s suppose you have two branches: main
and b1
.
On your main
branch, you have the following files: A
, B
, and C
:
alina
alina git:( main ) ls
A.txt B.txt C.txt README.md
alina git:( main ) █
And on the b1
branch, you have the following files: 1
, 2
, and 3
:
alina
alina git:( main ) git switch b1
Switched to branch 'b1'
alina git:( b1 ) ls
1.txt 2.txt 3.txt README.md
alina git:( b1 ) █
Back on the main
branch, you merge b1
:
alina
alina git:( b1 ) git switch main
Switched to branch 'main'
Your branch is ahead of 'origin/main' by 3 commits.
(use "git push" to publish your local commits)
alina git:( main ) git merge b1
Merge made by the 'ort' strategy.
1.txt | 1 +
2.txt | 1 +
3.txt | 1 +
3 files changed, 3 insertions(+)
create mode 100644 1.txt
create mode 100644 2.txt
create mode 100644 3.txt
alina git:( main ) █
This gives you the following commit graph:
Now you have the files A
, B
, C
, 1
, 2
, and 3
:
alina
alina git:( main ) ls
1.txt 2.txt 3.txt A.txt B.txt C.txt README.md
alina git:( main ) █
The git log
command shows you the commit graph:
alina
alina git:( main ) git log --graph --oneline --all
* 7a0f203 (HEAD -> main) Merge branch 'b1'
|\
| * 4d2cd88 (b1) add 3.txt
| * 82d43ec add 2.txt
| * bcada98 add 1.txt
* | 4fa0b70 add C.txt
* | ab0bacb add B.txt
* | 213ff64 add A.txt
|/
* 416c761 (origin/main, origin/HEAD) Initial commit
alina git:( main ) █
You then add a new commit:
alina
alina git:( main ) echo "x" > x.txt; git add x.txt; git commit -m 'add x.txt'
[main 1438321] add x.txt
1 file changed, 1 insertion(+)
create mode 100644 x.txt
alina git:( main ) █
And you get this commit graph:
Now you have the following files:
alina
alina git:( main ) ls
1.txt 2.txt 3.txt A.txt B.txt C.txt README.md x.txt
alina git:( main ) █
git revert -m 1
You realize that the merge was a bad idea, and you decide to revert the merge commit 7a0f203
:
alina
alina git:( main ) git revert 7a0f203
error: commit 7a0f2030dd4a8b3670b49a8eb9b45dd1460310df is a merge but no -m option was given.
fatal: revert failed
alina git:( main ) █
Git is unhappy and gives an error message.
The reason why Git is unhappy is that you are trying to revert a merge commit without specifying which parent you want to revert to.
A Git revert is a three-way merge between your current commit (HEAD
) and the parent of the commit you are reverting (the commit you are reverting to),
where the base is the commit you are reverting.
That means that Git needs to know which parent you want to revert to.
The git show
command shows you the parents of the commit 7a0f203
:
alina
alina git:( main ) git show 7a0f203
commit 7a0f2030dd4a8b3670b49a8eb9b45dd1460310df
Merge: 4fa0b70 4d2cd88
Author: alina <alina@email.com>
Date: Sat Jul 1 08:42:54 2023 -0700
Merge branch 'b1'
alina git:( main ) █
The Merge:
line indicates that we have a merge commit, and the two hashes after the Merge:
line are the hashes of the parents of the merge commit.
The order of those hashes is important:
- Parent
#1
is the commit of the branch you were on when you did the merge. - Parent
#2
is the commit of the branch you merged.
If you want to revert to the state of the branch you were on when you did the merge, you need to use the parent #1
hash.
alina
alina git:( main ) git revert 7a0f203 -m 1
[main 6b121fa] Revert "Merge branch 'b1'"
3 files changed, 3 deletions(-)
delete mode 100644 1.txt
delete mode 100644 2.txt
delete mode 100644 3.txt
alina git:( main ) █
That brings you back to the state of the main
branch you were on when you did the merge, but it keeps the changes made since then.
The file x.txt
is still there:
alina
alina git:( main ) ls
A.txt B.txt C.txt README.md x.txt
alina git:( main ) █
And your commit graph is:
git revert -m 2
Let’s go back to the state after the merge and the commit adding the x
file:
We have the following files:
alina
alina git:( main ) ls
1.txt 2.txt 3.txt A.txt B.txt C.txt README.md x.txt
alina git:( main ) █
And the commit graph is:
The commit tree was recreated completely so the commit hashes are different from the previous example.
The new merge commit is f970398
:
alina
alina git:( main ) git show f970398
commit f970398069ccb6a8340ee52ec4673bb3d9c9806b
Merge: daa69b1 c116942
Author: alina <alina@email.com>
Date: Sat Jul 1 09:22:42 2023 -0700
Merge branch 'b1'
(END)
(END)
alina git:( main ) █
Usually, git revert -m 1
is what you want to do, but sometimes you want to revert to the state of the branch you merged.
Let’s try this time to revert the merge by restoring the state of the branch we merged:
alina
alina git:( main ) git revert f970398 -m 2
[main c4ce39c] Revert "Merge branch 'b1'"
3 files changed, 3 deletions(-)
delete mode 100644 A.txt
delete mode 100644 B.txt
delete mode 100644 C.txt
alina git:( main ) █
This time, the files A
, B
, and C
are deleted as they were the files on the main
branch before the merge.
alina
alina git:( main ) ls
1.txt 2.txt 3.txt README.md x.txt
alina git:( main ) █
The commit graph is: