How do I "un-revert" a reverted Git commit?
Asked Answered
S

15

848

Given a change that has been committed using commit, and then reverted using revert, what is the best way to then undo that revert?

Ideally, this should be done with a new commit, so as to not re-write history.

Suzy answered 4/1, 2012 at 13:59 Comment(4)
Possible duplicate of How can I fix a reverted git commit?Ortrud
@Ortrud a comment for possible duplicate there, points here. One must be marked original and one must be marked dupliateVasiliu
@JohnDemetriou no the question that has a better set of answers should be kept open. Time isn't relevant here How should duplicate questions be handled?Ortrud
I didn't say about time. I just happened to comment on one of the two about the issueVasiliu
F
535

If you haven't pushed that change yet, git reset --hard HEAD^

Otherwise, reverting the revert is perfectly fine.

Another way is to git checkout HEAD^^ -- . and then git add -A && git commit.

Forgetful answered 4/1, 2012 at 16:14 Comment(11)
Note that if you want to un-revert without immediately applying the original changes to the master branch, you can (1) restore the original branch if deleted, (2) click "revert" on the revert branch as noted by Adam, then (3) click "edit" in the header of the resulting PR and change the target branch to the original branch instead of master. Now your original branch can be re-merged to effect the previously reverted changes.Pulsate
Yes, reverting a reverted commit is analogous to reinstating that commit. Thank you!Cochran
Please note this will remove all changes in working tree and index. Use git stash to save any changes you don't wan't to lose.Antilebanon
What's the advantage of the checkout && commit method? It seems that in the general case git cherry-pick or alternatively git revert are the most straight-forward ways to revert a revert.Hellespont
Erm ... shouldn't that be git reset --hard HEAD~?Literally
@Literally : they are the same when you only provide 1 ~ or ^. You can find a good answer on it here: https://mcmap.net/q/12625/-what-39-s-the-difference-between-head-and-head-in-gitFissure
I think it would be helpful to show how to: Otherwise, reverting the revert is perfectly fine., and then also to explain what git checkout HEAD^^ -- . is doing.Halverson
Good lord, don't use git add -A ...unless you want to add every file to version control, which is most likely not what you want.Minaminabe
I mis-reverted to HEAD~2 and did this. I lost the most recent commit. Thankfully I have a backup, but git reset --hard HEAD^ is dangerous. Don't do it unless you're willing to lose all the future commits.Czech
@Halverson -- in checkout is used to separate tree from file. According to the answer here stackoverflow.com/a/13321491.Boxthorn
Thanks my aim was to suggest the author provide a more detailed explanation so folks arent just cargo cult copy pasting commands into REPLs and hoping their repo works.Halverson
E
982

git cherry-pick <original commit sha>
Will make a copy of the original commit, essentially re-applying the commit

Reverting the revert will do the same thing, with a messier commit message:
git revert <commit sha of the revert>

Either of these ways will allow you to git push without overwriting history, because it creates a new commit after the revert.
When typing the commit sha, you typically only need the first 5 or 6 characters:
git cherry-pick 6bfabc

Eloquence answered 30/4, 2015 at 18:39 Comment(11)
This is easily the most elegant and complete solution to the OPs question. Much better than the accepted answer with it's assumptions about the revert commit being at the HEAD of the commit tree. The op also specifically asked for a solution that does not rewrite history so the hard solution offered in the accepted answer is simply wrong.Solomonsolon
@Solomonsolon To clarify, the accepted answer contains the solution I used ("reverting the revert"), and was posted within hours of my question -- a clear 3 years earlier than this answer. Hence, the check mark.Suzy
Using -s recursive -X theirs will allow cherry-pick (or rebase) to reuse the commits in some cases where it might otherwise not. For example when you have a branch that got introduced and merged too soon, later the merge commit is reverted. Still sometime later you want to recover those commits.Clubby
@Suzy I know i was 3 years late, I just wanted people coming here from a google search to see a better answerEloquence
@Eloquence Yep, but again, to clarify -- it's a better answer just not the one I used to solve my problem. I was simply commenting on why the check mark is where it is. Question to all: does SO convention dictate that I should "maintain" my past questions and re-assign check marks as new answers come in?Suzy
If you cherry-pick the commit, then revert the commit. Once you want redo the commit again, the cherry-pick will do nothing.Sweetandsour
@Suzy I have no idea about SO convention. But as a google searcher, I really prefer to see the better answer checked. And would appreciate anyone's efforts to maintain their past questions.Abdulabdulla
@Suzy I think the original answer should be edited to reflect the changing times, at least that's what I try to do, if he/she fails to do that then the new better answer takes over and should be checked. At least that's what I always do.Cheshire
<commit sha of the revert> what if the revert is done through pull/merge request, use the sha of the commit itself or the sha of the merge commit?Anemography
@Anemography https://mcmap.net/q/21244/-git-cherry-pick-says-quot-38c74d-is-a-merge-but-no-m-option-was-given-quot explains it perfectly.Amesace
This is very helpful if you've just accidentally reverted the initial commit of your Msc ProjectCampaign
F
535

If you haven't pushed that change yet, git reset --hard HEAD^

Otherwise, reverting the revert is perfectly fine.

Another way is to git checkout HEAD^^ -- . and then git add -A && git commit.

Forgetful answered 4/1, 2012 at 16:14 Comment(11)
Note that if you want to un-revert without immediately applying the original changes to the master branch, you can (1) restore the original branch if deleted, (2) click "revert" on the revert branch as noted by Adam, then (3) click "edit" in the header of the resulting PR and change the target branch to the original branch instead of master. Now your original branch can be re-merged to effect the previously reverted changes.Pulsate
Yes, reverting a reverted commit is analogous to reinstating that commit. Thank you!Cochran
Please note this will remove all changes in working tree and index. Use git stash to save any changes you don't wan't to lose.Antilebanon
What's the advantage of the checkout && commit method? It seems that in the general case git cherry-pick or alternatively git revert are the most straight-forward ways to revert a revert.Hellespont
Erm ... shouldn't that be git reset --hard HEAD~?Literally
@Literally : they are the same when you only provide 1 ~ or ^. You can find a good answer on it here: https://mcmap.net/q/12625/-what-39-s-the-difference-between-head-and-head-in-gitFissure
I think it would be helpful to show how to: Otherwise, reverting the revert is perfectly fine., and then also to explain what git checkout HEAD^^ -- . is doing.Halverson
Good lord, don't use git add -A ...unless you want to add every file to version control, which is most likely not what you want.Minaminabe
I mis-reverted to HEAD~2 and did this. I lost the most recent commit. Thankfully I have a backup, but git reset --hard HEAD^ is dangerous. Don't do it unless you're willing to lose all the future commits.Czech
@Halverson -- in checkout is used to separate tree from file. According to the answer here stackoverflow.com/a/13321491.Boxthorn
Thanks my aim was to suggest the author provide a more detailed explanation so folks arent just cargo cult copy pasting commands into REPLs and hoping their repo works.Halverson
D
79

A revert commit is just like any other commit in git. Meaning, you can revert it, as in:

git revert 648d7d808bc1bca6dbf72d93bf3da7c65a9bd746

That obviously only makes sense once the changes were pushed, and especially when you can't force push onto the destination branch (which is a good idea for your master branch). If the change has not been pushed, just do cherry-pick, revert or simply remove the revert commit as per other posts.

In our team, we have a rule to use a revert on Revert commits that were committed in the main branch, primarily to keep the history clean, so that you can see which commit reverts what:

     7963f4b2a9d    Revert "Revert "OD-9033 parallel reporting configuration"
     "This reverts commit a0e5e86d3b66cf206ae98a9c989f649eeba7965f.
                    ...
     a0e5e86d3b6    Revert "OD-9055 paralel reporting configuration"
     This reverts commit 648d7d808bc1bca6dbf72d93bf3da7c65a9bd746.
                ...
     Merge pull request parallel_reporting_dbs to master* commit 
    '648d7d808bc1bca6dbf72d93bf3da7c65a9bd746'

This way, you can trace the history and figure out the whole story, and even those without the knowledge of the legacy could work it out for themselves. Whereas, if you cherry-pick or rebase stuff, this valuable information is lost (unless you include it in the comment).

Obviously, if a commit reverted and re-reverted more than once that becomes quite messy.

Diazole answered 28/6, 2018 at 15:46 Comment(0)
M
45

Reverting the revert will do the trick

For example,

If abcdef is your commit and ghijkl is the commit you have when you reverted the commit abcdef, then run:

git revert ghijkl

This will revert the revert

Marcellmarcella answered 18/9, 2018 at 7:15 Comment(1)
This is the correct answer. It also clarifies that a revert is a commit itself that ca be reverted.Celie
M
12

If you did a revert by mistake:

git revert <commit-id>

you will simply need to run:

git cherry-pick <commit-id>

I had to commit my changes to processed with this command.

You can get your commits ID by running:

git log --pretty=format:"%h - %an, %ar : %s"
Merengue answered 25/1, 2022 at 16:22 Comment(0)
R
8

Here's how I did it:
If the branch my_branchname was included in a merge that got reverted. And I wanted to unrevert my_branchname :

I first do a git checkout -b my_new_branchname from my_branchname.
Then I do a git reset --soft $COMMIT_HASH where $COMMIT_HASH is the commit hash of the commit right before the first commit of my_branchname (see git log)
Then I make a new commit git commit -m "Add back reverted changes"
Then I push up the new branch git push origin new_branchname
Then I made a pull request for the new branch.

Reduplicative answered 25/7, 2018 at 1:52 Comment(1)
Way to go when there are too many "cherry-pick" to do. I don't get why this answer has so few upvotesDoralynne
S
5

If you don't like the idea of "reverting a revert" (especially when that means losing history information for many commits), you can always head to the git documentation about "Reverting a faulty merge".

Given the following starting situation

 P---o---o---M---x---x---W---x
  \         /
   A---B---C----------------D---E   <-- fixed-up topic branch

(W is your initial revert of the merge M; D and E are fixes to your initially broken feature branch/commit)

You can now simply replay commits A to E, so that none of them "belongs" to the reverted merge:

$ git checkout E
$ git rebase --no-ff P

The new copy of your branch can now be merged to master again:

   A'---B'---C'------------D'---E'  <-- recreated topic branch
  /
 P---o---o---M---x---x---W---x
  \         /
   A---B---C----------------D---E
Stately answered 14/11, 2017 at 9:3 Comment(1)
Good idea and thanks for the doc link. We usually rebase with master before merging back in, but git then seems to recognize that A', B', C' are the same as the ones before, and I now have D, E after W (pastebin). Suggestions on how to solve this?Weintrob
A
2

Or you could git checkout -b <new-branch> and git cherry-pick <commit> the before to the and git rebase to drop revert commit. send pull request like before.

Alterative answered 23/3, 2018 at 9:9 Comment(0)
E
2

To get back the unstaged and staged changes which were reverted after a commit:

git reset HEAD@{1}

To recover all unstaged deletions:

git ls-files -d | xargs git checkout --
Eucalyptus answered 11/6, 2019 at 18:37 Comment(0)
O
1

While a git revert still work (to "revert a revert"), with Git 2.43 (Q4 2023), the default log message created by "git revert"(man), when reverting a commit that records a revert, has been tweaked.

See commit c9192f9 (21 Aug 2023), and commit 883cb1b (02 Sep 2023) by Oswald Buddenhagen (ossilator).
(Merged by Junio C Hamano -- gitster -- in commit f73604f, 14 Sep 2023)

sequencer: beautify subject of reverts of reverts

Signed-off-by: Oswald Buddenhagen

Instead of generating a silly-looking Revert "Revert "foo"", make it a more humane Reapply "foo".

This is done for two reasons:

  • To cover the actually common case of just a double revert.
  • To encourage people to rewrite summaries of recursive reverts by setting an example (a subsequent commit will also do this explicitly in the documentation).

To achieve these goals, the mechanism does not need to be particularly sophisticated.
Therefore, more complicated alternatives which would "compress more efficiently" have not been implemented.

And:

git-revert.txt: add discussion

Signed-off-by: Oswald Buddenhagen

git revert now includes in its man page:

DISCUSSION

While git creates a basic commit message automatically, it is strongly recommended to explain why the original commit is being reverted. In addition, repeatedly reverting reverts will result in increasingly unwieldy subject lines, for example 'Reapply "Reapply "<original subject>""'. Please consider rewording these to be shorter and more unique.

Ousel answered 20/9, 2023 at 20:50 Comment(0)
C
0

I had an issue somebody made a revert to master to my branch, but I was needed to be able to merge it again but the problem is that the revert included all my commit. Lets look at that case we created our feature branch from M1 we merge our feature branch in M3 and revert on it in RM3

M1 -> M2 -> M3 -> M4- > RM3 -> M5
 \.         /
  F1->F2 -

How to make the F2 able to merge to M5?

git checkout master
git checkout -b brach-before-revert
git reset --hard M4
git checkout master
git checkout -b new-feature-branch
git reset --hard M1 
git merge --squash brach-before-revert
Cockatrice answered 13/12, 2020 at 18:58 Comment(0)
Z
0

After the initial panic of accidentally deleting all my files, I used the following to get my data back

git reset HEAD@{1}         
git fsck --lost-found      
git show 
git revert <sha that deleted the files>
Zoila answered 13/1, 2021 at 6:45 Comment(0)
G
0

I saw responses include the command git reset --hard HEAD without any caution. You should be careful with that command because of the option --hard. It resets your index and your remote repo but mostly, it also resets your local repo and all commits that were not pushed to the remote yet will be lost, both from your local repo and index. Never use that flag --hard unless you are sure you also want to reset all your local work from the current commit till the hash you chose. If anyway you did it by mistake, run git reflog to retrieve your ~hash then git reset --hard ~hash to recover your files.

Gelatin answered 25/6, 2021 at 15:23 Comment(0)
S
0

In my case I needed to commit the changes after revert before I could cherry-pick the original commit without a failure.

git commit -m "Make changes (original commit)."
git revert <original commit hash>
git commit -m "Revert original commit."
git cherry-pick <original commit hash>
Shake answered 23/12, 2021 at 15:17 Comment(0)
U
0

Another way: Create a patch from the commit that was reverted and then apply the patch.

You can do this from the command line, or ui tools like SourceTree.

How can I generate a Git patch for a specific commit?

Untenable answered 1/2 at 9:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.