Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to revert multiple git commits?

I have a git repository that looks like this:

A <- B <- C <- D <- HEAD 

I want the head of the branch to point to A, i.e. I want B, C, D, and HEAD to disappear and I want head to be synonymous with A.

It sounds like I can either try to rebase (doesn't apply, since I've pushed changes in between), or revert. But how do I revert multiple commits? Do I revert one at a time? Is the order important?

like image 901
Bill Avatar asked Sep 23 '09 00:09

Bill


People also ask

How do I revert multiple commits at once?

Another way of reverting multiple commits is to use the git reset command.

How do I revert the commit in git?

To revert a commit with GitKraken, simply right-click on any commit from the central graph and select Revert commit from the context menu.

How do I discard all commits?

Removing the last commit To remove the last commit from git, you can simply run git reset --hard HEAD^ If you are removing multiple commits from the top, you can run git reset --hard HEAD~2 to remove the last two commits. You can increase the number to remove even more commits.


1 Answers

Expanding what I wrote in a comment

The general rule is that you should not rewrite (change) history that you have published, because somebody might have based their work on it. If you rewrite (change) history, you would make problems with merging their changes and with updating for them.

So the solution is to create a new commit which reverts changes that you want to get rid of. You can do this using git revert command.

You have the following situation:

 A <-- B  <-- C <-- D                                  <-- master <-- HEAD 

(arrows here refers to the direction of the pointer: the "parent" reference in the case of commits, the top commit in the case of branch head (branch ref), and the name of branch in the case of HEAD reference).

What you need to create is the following:

 A <-- B  <-- C <-- D <-- [(BCD)-1]                   <-- master <-- HEAD 

where [(BCD)^-1] means the commit that reverts changes in commits B, C, D. Mathematics tells us that (BCD)-1 = D-1 C-1 B-1, so you can get the required situation using the following commands:

$ git revert --no-commit D $ git revert --no-commit C $ git revert --no-commit B $ git commit -m "the commit message for all of them" 

Works for everything except merge commits.


Alternate solution would be to checkout contents of commit A, and commit this state. Also works with merge commits. Added files will not be deleted, however. If you have any local changes git stash them first:

$ git checkout -f A -- . # checkout that revision over the top of local files $ git commit -a 

Then you would have the following situation:

 A <-- B  <-- C <-- D <-- A'                       <-- master <-- HEAD 

The commit A' has the same contents as commit A, but is a different commit (commit message, parents, commit date).


Alternate solution by Jeff Ferland, modified by Charles Bailey builds upon the same idea, but uses git reset. Here it is slightly modified, this way WORKS FOR EVERYTHING:

$ git reset --hard A $ git reset --soft D # (or ORIG_HEAD or @{1} [previous location of HEAD]), all of which are D $ git commit 
like image 115
Jakub Narębski Avatar answered Sep 19 '22 05:09

Jakub Narębski