How do I get the project back to a specific commit?

Asked

Viewed 105,525 times

42

Assuming a condition where, I have a project with 20 commits, and I decide for inexplicable reasons to go back some independent commits if I want to go back 4, 5 or 10, assuming the description of my commits is quite clear, I view my last commits using the command $ git log, and once located, how do I revert to a specific commit? What possible problems can I encounter? And how to analyze them?

  • 1

    https://answall.com/a/98587/153104 Better answer. Thank you! You really helped.

3 answers

54

Your question is very broad. There are many, many possible scenarios with several alternative solutions, one with both advantages and disadvantages. Still, I see three important scenarios to consider:

  • you want to return your repository local to a specific point;
  • you want to return a repository public to a specific point
  • you want to go back to a specific point of history to take a test, but you don’t want to change history.

Let us see them, then.

Rewind local repository

Consider this repository on Github. Let’s make some improvements to the program. First, we clone the repository locally and edit it.

  1. First, let’s add one shebang:

    $ git diff -U1
    diff --git a/add.py b/add.py
    index 77d557c..2bb03ed 100644
    --- a/add.py
    +++ b/add.py
    @@ -1,3 +1,4 @@
    +#!/usr/bin/env python
     import sys
    $
    $  git com -am "Adding shebang line"
    [master 3c1dd69] Adding shebang line
     1 file changed, 1 insertion(+)
    
  2. Then we’ll make the exit more explanatory:

    $ git diff -U1
    diff --git a/add.py b/add.py
    index 2bb03ed..3287cc7 100644
    --- a/add.py
    +++ b/add.py
    @@ -6,4 +6,4 @@ def add(a, b):
     a2 = int(sys.argv[2])
    -print add(a1, a2)
    +print "%d + %d = %d" % (a1, a2, add(a1, a2))
    $
    $ git com -am "Making output readable"
    [master 3cba3f9] Making output readable
     1 file changed, 1 insertion(+), 1 deletion(-)
    
  3. Finally, we add a greeting:

    $ git diff -U1
    diff --git a/add.py b/add.py
    index 3287cc7..676b124 100644
    --- a/add.py
    +++ b/add.py
    @@ -3,2 +3,4 @@ import sys
    
    +print "This is the lame calculator. Hello!"
    +
     def add(a, b):
    $
    $ git com -am "Greeting"
    [master a41916f] Greeting
     1 file changed, 2 insertions(+)
    

We’re ready to upload the changes to Github, but it’s decided that the second and third changes are a bad idea. To undo it, as it only exists in your local repository, we can use git reset. First, we have this history:

$ git log --oneline -n4
a41916f Greeting
f69d7d0 Making output readable
3c1dd69 Adding shebang line
cf629bc Removing spurious line

Then we use git reset --hard:

$ git reset --hard cf629bc
HEAD is now at cf629bc Removing spurious line

The result will be:

$ git log --oneline -n4
cf629bc Removing spurious line
e4eccaf Using better names
b0d6449 Using proper name
e0e3713 Using variables

Now yes! We can make our own push happy.

Rewind public repository

Well, before we make our own push, We noticed that there are already wrong commits on Github! The commit 0b75b1 renaming b for a2 within the function add(), where this shouldn’t be done. Commit e88170 is even worse, turning addition into meaningless subtraction!

When to rewind public repositories almost we can never use git reset. If we used git reset, person who cloned our repository would have serious problems synchronizing with it again. The solution in this case is git revert. To do this, simply pass the range of commits to be reversed, starting from the last commit to be removed and ending with the first commit to nay be removed (e88170). That is, you must pass the interval f187f6..e88170:

$ git revert --no-edit HEAD..e88170
[master b77fd51] Revert "Using subtraction"
 1 file changed, 1 insertion(+), 1 deletion(-)
[master bf5d6e0] Revert "Using better names"
 1 file changed, 4 insertions(+), 4 deletions(-)

What is the difference to the git reset? Well, instead of deleting commits, it adds new commits undoing old ones. If you look at the last commit, it will be the reverse version of the first reverse commit:

$ git show -U1
commit bf5d6e0a64916f9b4a40975c6e8ae519e682d37d
Author: Adam Victor Nazareth Brandizzi <[email protected]>
Date:   Fri Jun 6 13:01:01 2014 -0300

    Revert "Using better names"

    This reverts commit 0b75b1fbbf6858bd5fe3c46a51dda7ea424bd84b.

diff --git a/lamecalc.py b/lamecalc.py
index 3edf375..9c3a009 100644
--- a/lamecalc.py
+++ b/lamecalc.py
@@ -3,7 +3,7 @@ import sys
 def add(a, b):
-    return a+a2
+    return a+b


-a1 = int(sys.argv[1])
-a2 = int(sys.argv[2])
-print add(a1, a2)
+a = int(sys.argv[1])
+b = int(sys.argv[2])
+print add(a, b)

Now yes! We can do the push reversals. Our past mistakes will remain visible, but we will not break repositories of our followers.

A very cool thing from git revert is that you don’t need to use it only in the last commands. If you only want to reverse the commit 0b75b1, could do it:

$ git revert 0b75b1

Of course it could give conflict, but in this case it was only to solve it, as it does with any conflict.

Go back in time to do an experiment

git reset back the repository and causes the current branch to point to the chosen commit. We don’t always want this. For example, suppose we don’t know which commit causes our program to show subtraction instead of addition. We suspect, however, that the problem did not exist in the review f187f6. In this case, just checkout this review and test:

$ git co f187f6
Note: checking out 'f187f6'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

HEAD is now at f187f65... Using variables

Ready! In our current state, there is no more commit that we wonder:

$ git log --oneline -n5
f187f65 Using variables
f8f7118 Reading from parameters
e70e491 Moving to function
bbfb15d Adding operation
dd958e3 Initial commit
$
[13h13 adam@adam:~/sandbox/lamecalc] $ git branch
* (detached from f187f65)
  master

We tested and found that the problem really didn’t exist then:

$ python lamecalc.py 2 2
4

On the other hand, our branch master was not changed:

$ git log --oneline -n5 master
e881705 Using subtraction
0b75b1f Using better names
f187f65 Using variables
f8f7118 Reading from parameters
e70e491 Moving to function

But now that we know which version works, we can get back to the master branch with git co master and then apply git revert to wrong commit.

The sky is the limit

This answer is just the tip of the iceberg. There are other ways to return to a point - git rebase iterative, checkout with -b etc. - each one with its challenges. Boy, even the ones I presented here are completely explained! Still, I think we can already give an idea. Anything, we can increase the question later too, right? :)

  • 3

    I had no idea that so much could be done or ... but anyway ... thank you so much for your help

  • 1

    congratulations for the answer, I consult it at least once a week in the most diverse situations ...

29

You can give a git checkout <hash-do-seu-commit>. Example:

git checkout c8ccd1c

Then you’ll go back to the state you were when you did this commit.

  • But if I return to the previous state, as in your example, git checkout c8ccd1c, and edit, when a new commit, the above version, will be overwritten?

  • 2

    @Duds, I don’t think git will allow the commit. It will ask you to create a new branch from this commit if you want to make any changes from that point on

21


I had this same problem, to solve just use the command below:

git reset --hard {hash-do-commit-desejado}

Your branch goes straight to the hash desired.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.