Is there a way in Git to rollback to a much earlier version of a file? I can roll back to the previous version with REVERT, but what if i want to go back to earlier versions? Whats the best workflow for managing waypoints in yout code? Branch each time so that you have a full copy of your code at a certain period in time?
I think I've found it....from http://www-cs-students.stanford.edu/~blynn/gitmagic/ch02.html
Sometimes you just want to go back and forget about every change past a certain point because they're all wrong. Then:
$ git log
shows you a list of recent commits, and their SHA1 hashes. Next, type:
$ git reset --hard SHA1_HASH
to restore the state to a given commit and erase all newer commits from the record permanently.
You can quickly review the changes made to a file using the diff command:
git diff <commit hash> <filename>
Then to revert a specific file to that commit use the reset command:
git reset <commit hash> <filename>
You may need to use the --hard
option if you have local modifications.
A good workflow for managaging waypoints is to use tags to cleanly mark points in your timeline. I can't quite understand your last sentence but what you may want is diverge a branch from a previous point in time. To do this, use the handy checkout command:
git checkout <commit hash>
git checkout -b <new branch name>
You can then rebase that against your mainline when you are ready to merge those changes:
git checkout <my branch>
git rebase master
git checkout master
git merge <my branch>
git revert <hash>
Will revert a given commit. It sounds like you think git revert
only affects the most recent commit.
That doesn't solve your problem, if you want to revert a change in a specific file and that commit changed more than that file.
A note on git tags:
If you are on a branch, you can tag it and then delete the branch even if you don't merge it back to master.
That's because a git tag is a primary object (along with commits, trees and blobs).
This way, you can tag a work in progress without having to keep the branch around. And, since references are kept to the commit, which references the trees which reference the blobs, you can run git-gc without worrying about losing any of the work you might want to get back to someday.
You have to be careful when you say "rollback". If you used to have one version of a file in commit $A, and then later made two changes in two separate commits $B and $C (so what you are seeing is the third iteration of the file), and if you say "I want to roll back to the first one", do you really mean it?
If you want to get rid of the changes both the second and the third iteration, it is very simple:
$ git checkout $A file
and then you commit the result. The command asks "I want to check out the file from the state recorded by the commit $A".
On the other hand, what you meant is to get rid of the change the second iteration (i.e. commit $B) brought in, while keeping what commit $C did to the file, you would want to revert $B
$ git revert $B
Note that whoever created commit $B may not have been very disciplined and may have committed totally unrelated change in the same commit, and this revert may touch files other than file you see offending changes, so you may want to check the result carefully after doing so.
From Chris Loyd's post it was not explained how the rebase commands work. After studying this for awhile, I will try to explain.
git checkout <my branch> git rebase master git checkout master git merge <my branch>
Assume you have
---o----o----o----o master \---A----B <my branch>
The first two commands ... commit git checkout git rebase master
... check out the branch of changes you want to apply to the master
branch. The rebase
command takes the commits from <my branch>
(that are not found in master
) and reapplies them to the head of master
. In other words, the parent of the first commit in <my branch>
is no longer a previous commit in the master
history, but the current head of master
. The two commands are the same as:
git rebase master <my branch>
It might be easier to remember this command as both the "base" and "modify" branches are explicit.
. The final history result is:
---o----o----o----o master \----A'----B' <my branch>
The final two commands ...
git checkout master
git merge <my branch>
... do a fast-forward merge to apply all <my branch>
changes onto master
. Without this step, the rebase commit does not get added to master
. The final result is:
---o----o----o----o----A'----B' master, <my branch>
master
and <my branch>
both reference B'
. Also, from this point it is safe to delete the <my branch>
reference.
git branch -d <my branch>