I have a local git repository containing some commits I would like to remove. More precisely, I would like to rewrite the entire repository history as if the given commits never took place. Removing old commits have been discussed here and here for example, but for some reasons it is not working for me.

To have a concrete workable example, consider a git repository constructed as follows

git init .
echo hello >foo.txt
git add foo.txt
git commit -a -m first
echo hello2 >>foo.txt
git commit -a -m second
sed -i 's/hello2/hello2 bis/' foo.txt
git commit -a -m second_bis
echo hello3 >>foo.txt
git commit -a -m third

The git repository now contains a single file foo.txt, which contains

hello
hello2 bis
hello3

The full git history obtained by ```git log -p --all`` is (Authors/Date removed)

commit 7bd2f440ef5a0cbfd0fd252671d1651a6c282db5
Author: ---
Date: ---

    third

diff --git a/foo.txt b/foo.txt
index 83d1cb0..ce5a249 100644
--- a/foo.txt
+++ b/foo.txt
@@ -1,2 +1,3 @@
 hello
 hello2 bis
+hello3

commit c2c7f8c66ddb40fc6196350ea5e4f4c54293cf54
Author: ---
Date: ---

    second_bis

diff --git a/foo.txt b/foo.txt
index 97531f3..83d1cb0 100644
--- a/foo.txt
+++ b/foo.txt
@@ -1,2 +1,2 @@
 hello
-hello2
+hello2 bis

commit 853dca5b3c9152ab50cdf9de260f1a3b4bba4100
Author: ---
Date: ---

    second

diff --git a/foo.txt b/foo.txt
index ce01362..97531f3 100644
--- a/foo.txt
+++ b/foo.txt
@@ -1 +1,2 @@
 hello
+hello2

commit 921efb9472e14333804dff575a71050213a770be
Author: ---
Date: ---

    first

diff --git a/foo.txt b/foo.txt
new file mode 100644
index 0000000..ce01362
--- /dev/null
+++ b/foo.txt
@@ -0,0 +1 @@
+hello

At this point, suppose I would like to eliminate the commit with comment "second_bis", so to have a history like the following

commit 7bd2f440ef5a0cbfd0fd252671d1651a6c282db5
Author: ---
Date: ---

    third

diff --git a/foo.txt b/foo.txt
index 83d1cb0..ce5a249 100644
--- a/foo.txt
+++ b/foo.txt
@@ -1,2 +1,3 @@
 hello
 hello2
+hello3

commit 853dca5b3c9152ab50cdf9de260f1a3b4bba4100
Author: ---
Date: ---

    second

diff --git a/foo.txt b/foo.txt
index ce01362..97531f3 100644
--- a/foo.txt
+++ b/foo.txt
@@ -1 +1,2 @@
 hello
+hello2

commit 921efb9472e14333804dff575a71050213a770be
Author: ---
Date: ---

    first

diff --git a/foo.txt b/foo.txt
new file mode 100644
index 0000000..ce01362
--- /dev/null
+++ b/foo.txt
@@ -0,0 +1 @@
+hello

The approach I tried is to use git rebase as to simply eliminate the commit "second_bis"

git rebase -i 853dca5b

This opens my editor with a file containing

pick c2c7f8c second_bis
pick 7bd2f44 third
# Rebase 853dca5..7bd2f44 onto 853dca5 (2 commands)
#
#...

At this point, I substitute "pick" with "drop" on the line pertaining to "second_bis". To my surprise, git is not able to manage the operation and complains with a conflict

Auto-merging foo.txt
CONFLICT (content): Merge conflict in foo.txt

Of course I can manually resolve the conflict in this simple example, but this defies the idea of automatically remove a commit. Even worse, on a repository with further commits after "third", after resolving the conflict git rebase complains again with a conflict on commits after the "third" one, and so on.

Why is git rebase unable to solve the conflict automatically?

Is there an automated way to remove the "second_bis" commit?

Alternatively, would it be possible to, say, apply a patch "second_bis -> second" to every commits in the history, and then eventually remove commits which do not nothing?

2 Answers

1
eftshift0 On Best Solutions

the problem is that when the change by the revision that adds hello3 on the file is done, the previous line is "hello2 bis" not just "hello 2" and there's nothing after the affected line on the original revision so git can't really tell what's going on. give git a little more context by adding hello3 before the sed and it works like a charm:

git init .
echo hello >foo.txt
git add foo.txt
git commit -m first foo.txt
echo hello2 >>foo.txt
git commit -m second foo.txt
echo hello3 >>foo.txt
git commit -m third foo.txt
sed -i 's/hello2/hello2 bis/' foo.txt
git commit -m second_bis foo.txt
echo hello4 >> foo.txt
git commit -m hello4 foo.txt

as a side note, your instructions will also work if instead of having a file with 1, 2, 3 lines, you try in the middle of a file that has at least a cumple of lines before and another couple of lines after. the abrupt EOF is what is reaaly confusing git to do its job (which I avoided by adding hello3 before the sed, obviously).

0
Sazzad Hissain Khan On

Seems your second_bis is the last commit, You can do as follows,

Amend last commit message

git commit --amend
#change second_bis into third

Reset last commit

git reset HEAD~
git add *
git commit -a -m "third"
#now 3rd commit shows third

Revert last commit

If you have already pushed the change into server, you can revert

git revert HEAD
#revert done change for third commit
git add *
git commit -a -m "third"
#now 3rd commit shows third