Disaster Recovery with Git
Objectives
- Understand how to view and retrieve old versions from Git using Git commands
- Practice using Git to recover old versions of code
Why do commits look like diffs?
We’ve defined a commit as a snapshot of our entire project, but if you ask Git, it doesn’t seem to see things that way:
$ git show 1255f4e commit 1255f4e4a5836501c022deb337fda3f8800b02e4 Author: Max Goldman <maxg@mit.edu> Date: Mon Sep 14 14:58:40 2015 -0400 Change the greeting diff --git a/hello.txt b/hello.txt index c1106ab..3462165 100644 --- a/hello.txt +++ b/hello.txt @@ -1 +1 @@ -Hello, version control! +Hello again, version control!
Git is assuming that most of our project does not change in any given commit, so showing only the differences will be more useful. Almost all the time, that’s true. But we can also use Git to show us the entire state of the repository at a particular commit, not just the differences.
We can ask Git to show us what was in a particular file at a particular commit by typing a colon :
after the commit ID and specifying a path to that file:
$ git show 3e62e60:hello.scm (display "Hello, version control!")
We can also use this command to show the contents of a particular folder at a given commit by specifying a path to that folder. Notably, we can show the state of the entire repo at a given commit by typing nothing after the colon:
$ git show 3e62e60: tree 3e62e60: hello.rb hello.scm hello.txt
As the empty filepath corresponds to the root directory in the repo and thus shows all the files in the repo.
Using git show
is one of the simplest ways you can use Git to recover from a disaster: ask Git to git show
you the contents of a now-broken file at some earlier version when the file was OK.
Disaster recovery
As recommended in Version Control with Git, a GUI program can make it easier to navigate your repo and find the data you need to recover from a mistake. The built-in version control UI in VS Code is also useful for this (for example, the TIMELINE view in the Explorer pane allows you to quickly see the history of a file), but we continue to recommend the command line for running Git commands.
In 6.102, you can use GitHub’s web interface to review commits that were pushed to github.mit.edu.
On the summary page for a repo you see the files and folders in the root of the project on the current
main
branch.Click on a commit message or commit ID to see the changes introduced by that commit.
Then click the Browse Files button on the far right to browse the entire project at that old version.
While you browse, notice the Tree: …commit ID… button on the left, which reminds you that you are looking at an old version of your repo. Normally, when you are browsing the latest version of your repo, this button says Branch: main instead.
git clone
Rather than having to recover from a catastrophic loss of work, it would be much better to prevent catastrophe.
If you add, commit, and push your work regularly, that work is safe in the remote repo, and you can retrieve it with git clone
into a fresh folder.
git revert
If you want to undo an entire commit, find its ID and use git revert
.
For example, to revert the addition of a Ruby greeting program in the hello-git
repo:
- Use
git lol
to see the current commit graph. - Use
ls
to see the current files. - Revert the “Greeting in Ruby” commit…
- … and Git asks for a commit message, providing a reasonable default.
- Save the commit message, and Git adds a new commit to the project history.
This new commit undoes the change made by the old commit.
It does not remove the old commit from the history of the project. - The new commit is now the
HEAD
, andls
no longer showshello.rb
.
To emphasize, git revert
doesn’t rewind the whole repo back to an old version: it reverses the effect of an old commit by creating a new commit at the HEAD
.
git show and git checkout
Most of the time when we make a mistake, we don’t want to revert an entire commit. For example, if the commit improved three different functions, and only one of those improvements was misguided, we’d like to undo just that one.
Often, the easiest way to find the working code you need is to ask Git to show you an old version. Hover or tap on each step in these examples:
git show
revision
will give you the diff for a commit.
Removed lines of text are in red and prefixed with a minus sign-
; added/modified lines are in green and prefixed with a plus+
.- If you
git show
a commit with a diff that doesn’t fit on one screen, it will be displayed one screenful at a time (originally using themore
command, but now more likely its successorless
). You’ll know this is happening if you see a:
prompt at the bottom of the terminal… - … which means you can press
space
to page down the diff, or use the arrow keys to go line-by-line. (You can pressh
for more help with usingless
.) Pressq
to quitless
and get back to the command prompt.
$ git show 1255f4e commit 1255f4e4a5836501c022deb337fda3f8800b02e4 Author: Max Goldman <maxg@mit.edu> Date: Mon Sep 14 14:58:40 2015 -0400 Change the greeting diff --git a/hello.txt b/hello.txt index c1106ab..3462165 100644 --- a/hello.txt +++ b/hello.txt @@ -1 +1 @@ -Hello, version control! +Hello again, version control!
git checkout
revision
--
path/to/file
will replace a file in your working directory with an old version. Both the--
(with a space before and after it) and the path in that command are important, don’t forget them!- This command does not make a commit yet, so our history has not changed…
- … but it does stage the changes for commit!
- We can look at the staged changes: we’re reverting
hello.txt
back to its old contents by removing “again”.
Unlike git revert
, the revision in this commit is the specific revision we want: the file will look as it did including the changes in that revision, and none afterwards.
You do not want to use the command git checkout
revision
without a --
path/to/file
.
If you do, your HEAD will now point to that old commit, and you will no longer be on branch main
.
This is called detached HEAD, and nobody wants that.
If a command warns you that your HEAD is detached, seek assistance before you continue to avoid losing work. If you have been working in a detached HEAD situation without realizing it, the work you did can almost always be recovered, but it has to be done carefully. Get help!
Practice with GitStream
GitStream will not work with multiple exercise pages open at the same time.
Don’t open exercises in multiple tabs. If an exercise doesn’t work, please close all open GitStream pages and try again.
If you encounter a problem, please ask for help.
git log
and git revert
Note that GitStream doesn’t keep track of whether you’ve already done this exercise. To see which GitStream exercises you’ve already done, look at Omnivore.