Benabalooba
Benabalooba

Reputation: 333

git revert several specific commits

The problem: A branch has good commits interleaved with undesired ones.

Attempted solution:

git revert hash5 hash8 hash9 hash23

What I thought this would do is that it'd apply all specified commits, and then let me sort out any conflicts.

What I now think that happens:

Question: How do I get git to apply all the reverts in a row before presenting any possible conflicts to me?

Upvotes: 17

Views: 3714

Answers (1)

ntc2
ntc2

Reputation: 11952

Sanity check

First, note that git revert reverts your patches in the order you list their hashes; you need to list the hashes from newest to oldest, since you want to proceed backwards in time. So, I'm going to call your hashes

<hash1> ... <hashN>

where <hash1> is older than <hash2> ... is older than <hashN>. So, make sure you were doing

git revert <hashN> ... <hash1>

in the first place!

Easy solution

Second, assuming you had been reverting them in the right order, try the --no-commit option:

git revert --no-commit <hashN> ... <hash1>

More involved solution

Third, If the easy solution doesn't work well, but the commits you want to revert really do make sense as a single commit (if not I don't see much hope), then try this: build one big commit out of the four you want to revert, and then revert the big commit.

  1. Build the big commit:

    Create a branch at the parent of the oldest commit:

    git checkout -b big-commit <hash1>~
    

    Copy the commits on your new branch and collapse them:

    git cherry-pick --no-commit <hash1> ... <hashN>
    git commit -m "Big commit"
    

    You should now have one big commit on your branch big-commit.

  2. Apply the big commit in reverse to the branch you're trying to revert:

    git checkout <branch you wanted to revert on>
    git revert big-commit
    

Another relatively easy solution

Use selective rebasing to rebuild the branch in question as if it never contained the unwanted commits:

  1. Create a new rebuild branch to work in:

    git checkout -b rebuild <branch you want to revert>
    
  2. Interactively rebase, dropping the commits you don't want:

    git rebase -i <hash1>~
    

    In the interactive rebase editor, delete the lines for <hash1> ... <hashN>.

Now your rebuild branch will contain <branch you want to revert>, as though <hash1> ... <hashN> never existed. If you run into conflicts here it would seem they're unavoidable.

If you need your work to be on <branch you want to revert>, and you can't just git reset it to point to your new rebuild branch:

git checkout <branch you want to revert>
git reset --hard rebuild

(e.g. because you've already pushed it publicly), then you can instead apply the differences to <branch you want to revert> as a patch:

git co <branch you want to revert>    
git diff <branch you want to revert> rebuild | patch

Upvotes: 12

Related Questions