Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

  • git applies commit hash5, in the process introducing large conflicts.
  • I attemt a merge, editing code what I want it to look like, setting the stage for more conflicts (see next point)
  • git applies commit hash8, which conflict with the edits done in the merge
  • I attempt a merge... etc etc

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

like image 551
Benjamin Burkhart Avatar asked Nov 26 '13 22:11

Benjamin Burkhart


People also ask

How do I revert to a last 10 commit?

The easiest way to undo the last Git commit is to execute the “git reset” command with the “–soft” option that will preserve changes done to your files. You have to specify the commit to undo which is “HEAD~1” in this case. The last commit will be removed from your Git history.

How do I revert multiple commits in Intellij?

Revert uncommitted changes In the Commit tool window Alt+0 , select one or more files that you want to revert, and select Rollback from the context menu, or press Ctrl+Alt+Z .


1 Answers

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
like image 94
ntc2 Avatar answered Oct 20 '22 17:10

ntc2