247

On Git, say I mess up my commits, and I want to make the version 3 commits ago as the new version. If I do git checkout xxxx, it creates a new branch and it seems like I can only merge it? Could I make this the new "master version"?

I want:

A-B-C-D-E

to become

A-B-C-D-E-F

where F has exactly the same content as C

If I use git revert xxxx instead, it seems like it definitely will have conflicts and I need to manually resolve it.

What I really want is just make the old commit at some point the new commit, regardless of what's in my working directory or the latest commit.

How would I go about doing this?

5
  • 2
    just git checkout <commit-hash> . don't miss the final dot in the command Commented Mar 12, 2020 at 10:20
  • 3
    @IbrahimTayseer Yes, but git rm -r . is fairly necessary prior to that command, otherwise if there is any file that is present in the newer version but not in the older version is still kept around.
    – huggie
    Commented Mar 13, 2020 at 0:24
  • 1
    yes you are right :) Commented Mar 13, 2020 at 7:21
  • 1
    Not a duplicate, IMO, since this question wants to keep the previous commits in linear history for future reference. I had the same need, and svick's answer below worked for me, whereas the "duplicate" question was less helpful. Commented Nov 2, 2021 at 13:46
  • git revert --no-commit C..HEAD # where C = the commit id you want to copy. Then git commit -m 'Reverting to C' This will create a new commit id == C while leaving the git history prior to the new commit unchanged.
    – Lyle Z
    Commented Apr 6 at 1:42

6 Answers 6

250
git rm -r .
git checkout HEAD~3 .
git commit

After the commit, files in the new HEAD will be the same as they were in the revision HEAD~3.

28
  • 7
    No, just git checkout XXXXX. rev~n means n revisions before rev.
    – svick
    Commented Aug 4, 2010 at 17:39
  • 106
    The dot after HEAD~3 is important.
    – bbuser
    Commented Feb 21, 2012 at 16:54
  • 20
    this works but I feel like there should be a more elegant way to do this. Commented Apr 10, 2012 at 22:16
  • 8
    with a large repo it takes awhile to delete all of the files and then check them all back out. I feel like git should have a way to revert to an old revision without having to delete everything. But that's just my opinion, this worked well for me and I didn't see a better way when I was looking for alternatives. Commented Apr 10, 2012 at 22:39
  • 13
    Possible to explain in answer what rm -r . does?
    – 2540625
    Commented May 6, 2016 at 22:41
35

eloone did it file by file with

git checkout <commit-hash> <filename>

but you could checkout all files more easily by doing

git checkout <commit-hash> .
3
  • 2
    This causes rejection when pushing to origin.
    – 2540625
    Commented May 6, 2016 at 22:43
  • 2
    This works for me. Pushing to origin wasn't a problem.
    – Noffls
    Commented Mar 2, 2017 at 8:47
  • 3
    so git checkout <commit-hash> will detach HEAD (push gets rejected), git checkout <commit-hash> . should checkout . (all changes) from the commit to your working-tree, which you can apply as a new commit. You can also detach HEAD and branch off that commit. It should then be at HEAD for the new branch and you can commit there. The . is important.
    – Brandon G
    Commented Jul 11, 2018 at 17:57
34

It sounds like you just want to reset to C; that is make the tree:

A-B-C

You can do that with reset:

git reset --hard HEAD~3

(Note: You said three commits ago so that's what I wrote; in your example C is only two commits ago, so you might want to use HEAD~2)


You can also use revert if you want, although as far as I know you need to do the reverts one at a time:

git revert HEAD     # Reverts E
git revert HEAD~2   # Reverts D

That will create a new commit F that's the same contents as D, and G that's the same contents as C. You can rebase to squash those together if you want

10
  • 4
    Hi thanks for the answer. But what if I don't want to do the hard reset since it's already pushed onto a public repository?
    – huggie
    Commented Aug 1, 2010 at 11:02
  • 2
    @huggie Ah. Then you probably want to use the revert method Commented Aug 1, 2010 at 18:05
  • 1
    then git push -f to force push
    – radtek
    Commented Nov 30, 2014 at 5:39
  • 1
    Does this maintain commit "E" and create a new commit, "F"? Commented Jun 2, 2016 at 16:36
  • 1
    I don't think this is what the OP desires because it looses D-E.
    – Pete Alvin
    Commented Dec 23, 2019 at 18:31
23

This is exactly what I wanted to do. I was not sure of the previous command git cherry-pick C, it sounds nice but it seems you do this to get changes from another branch but not on same branch, has anyone tried it?

So I did something else which also worked : I got the files I wanted back from the old commit file by file

git checkout <commit-hash> <filename>

ex : git checkout 08a6497b76ad098a5f7eda3e4ec89e8032a4da51 file.css

-> this takes the files as they were from the old commit

Then I did my changes. And I committed again.

git status (to check which files were modified)
git diff (to check the changes you made)
git add .
git commit -m "my message"

I checked my history with git log, and I still have my history along with my new changes made from the old files. And I could push too.

Note that to go back to the state you want you need to put the hash of the commit before the unwanted changes. Also make sure you don't have uncommitted changes before you do that.

11

git cherry-pick C

where C is the commit hash for C. This applies the old commit on top of the newest one.

1
  • 21
    git cherry-pick C takes the changes introduced by C and applies them on top of E. This is not what the OP asked for. He wants to have the files in the exact state that they were in C, which git checkout provides.
    – gotgenes
    Commented May 30, 2013 at 13:06
1

The other answers so far create new commits that undo what is in older commits. It is possible to go back and "change history" as it were, but this can be a bit dangerous. You should only do this if the commit you're changing has not been pushed to other repositories.

The command you're looking for is git rebase --interactive

If you want to change HEAD~3, the command you want to issue is git rebase --interactive HEAD~4. This will open a text editor and allow you to specify which commits you want to change.

Practice on a different repository before you try this with something important. The man pages should give you all the rest of the information you need.

1
  • 2
    Vote down. 1. the question explicitly asks for keeping older commits, so that might be a reason why other answers attempt to do that. 2. as you said, the commits might have been published and there's no need to introduce comments on what that means with rebasing.
    – tishma
    Commented Feb 22, 2016 at 10:57

Not the answer you're looking for? Browse other questions tagged or ask your own question.