Search code examples
gitgit-revert

Reverting a series of pushed merges and commits in Git (without rewriting history)


Context

One of my teammates mistakenly pushed some commits to our main development branch. We're a small, collocated team. Our remote repository is hosted on an internal server.

Here is the top of our commit log (all these commits have already been pushed):

$ git log develop -6 --pretty=oneline --abbrev-commit
faada93 Merge branch 'develop' of <our_repo_path>.git
244d174 Support classes again
a97a877 Pruned all unused references (again).
8c29252 Merge branch 'develop' of <our_repo_path>.git
a78b993 Support models & methods - product types & categories
da8b496 Resolved JIRA issue PPF-182

da8b496 is the last commit we wanted to keep in our develop branch, so we needed to revert the 5 last commits. We created a new branch from 8c29252 to continue work in a "feature branch."

I tried many things, guided by this answer and this post from Linus, and ended up doing what you can see in my Terminal history below. But I'm not sure if what I ended up doing is "the right way." The information I found was complex; I was unable to discern a "best solution" for this particular problem.

Question

Was the approach I chose (see details below) a good way to revert those 5 commits, without harming our history? Is there an easier or "more correct" way to accomplish the same thing?

Amongst other things, I considered creating a new branch from da8b496 (git checkout -b new-develop da8b496) and abandoning our current develop branch, but that just didn't feel right.


What I ended up doing (details)

First, I created a new branch for the commits a78b993 and 8c29252, because these commits contain work that we want to keep and eventually merge back to our main development branch.

$ git checkout -b new-feature-brach 8c29252

Then I started reverting the offending commits in our development branch.

I tried this first, but it didn't work (likely because some of the commits are merges):

$ git revert a78b993..HEAD
error: a cherry-pick or revert is already in progress
hint: try "git cherry-pick (--continue | --quit | --abort)"
fatal: revert failed

So… I manually reverted each commit instead; one by one:

$ git revert -m 1 faada93
[develop 40965a5] Revert "Merge branch 'develop' of <our_repo_path>.git"
8 files changed, 167 insertions(+), 3 deletions(-)

$ git revert 244d174
[develop 3cebd68] Revert "Support classes again"
45 files changed, 557 insertions(+), 1572 deletions(-)
(list of affected files)

$ git revert a97a877
error: could not revert a97a877... Pruned all unused references (again).
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'

$ git mergetool
Merging:
exampleFile1.cs
exampleFile2.cs

Deleted merge conflict for 'exampleFile1.cs':
{local}: deleted
{remote}: modified file
Use (m)odified or (d)eleted file, or (a)bort? m

Deleted merge conflict for 'exampleFile2.cs':
{local}: deleted
{remote}: modified file
Use (m)odified or (d)eleted file, or (a)bort? m

$ git commit -m "Adding files to be reverted along with the next commit."
[develop 15bc02b] Adding files to be able to revert the next commit in line.
2 files changed, 239 insertions(+)
(list of affected files here)

$ git revert -m 1 8c29252
# On branch develop
# Your branch is ahead of 'origin/develop' by 3 commits.
#   (use "git push" to publish your local commits)
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       exampleFile1.cs.orig
#       exampleFile2.cs.orig
nothing added to commit but untracked files present (use "git add" to track)

$ git revert a78b993
[develop 841e77c] Revert "Support models & methods - product types & categories"
2 files changed, 239 deletions(-)
(list of affected files here)

Commit log after all the reverts were done:

$ git log develop -10 --pretty=oneline --abbrev-commit
841e77c Revert "Support models & methods - product types & categories"
15bc02b Adding files to be able to revert the next commit in line.
3cebd68 Revert "Support classes again"
40965a5 Revert "Merge branch 'develop' of <our_repo_path>.git"
faada93 Merge branch 'develop' of <our_repo_path>.git
244d174 Support classes again
a97a877 Pruned all unused references (again).
8c29252 Merge branch 'develop' of <our_repo_path>.git
a78b993 Support models & methods - product types & categories
da8b496 Resolved JIRA issue PPF-182

Graph after reverts:

$ git log --graph --oneline -8 develop
* 841e77c Revert "Support models & methods - product types & categories"
* 15bc02b Adding files to be able to revert the next commit in line.
* 3cebd68 Revert "Support classes again"
* 40965a5 Revert "Merge branch 'develop' of <our_repo_path>.git"
*   faada93 Merge branch 'develop' of <our_repo_path>.git
|\
| * a97a877 Pruned all unused references (again).
| *   8c29252 Merge branch 'develop' of <our_repo_path>.git
| |\
| | * da8b496 Resolved JIRA issue PPF-182

Seems correct to me. Lastly, I remove some backup files that I don't want to keep:

$ git clean -fd
(list of affected files here)

Current status is clean:

$ git status
# On branch develop
# Your branch is ahead of 'origin/develop' by 4 commits.
#   (use "git push" to publish your local commits)
#
nothing to commit, working directory clean

And then I push everything back to the remote:

git push origin develop

Solution

  • You have a small co-located team, so communication isn't a problem. Make the commit history look as it should have looked:

    git branch -f develop dab4896
    git branch newfeature 8c29252
    git push -f origin develop newfeature
    

    and have everyone refetch. You're done.

    This kind of mistake is one of the reasons to rewrite.