Skip to content

Commit

Permalink
markdown source builds
Browse files Browse the repository at this point in the history
Auto-generated via {sandpaper}
Source  : b33dbf2
Branch  : main
Author  : Martino Sorbaro <martinosorb@users.noreply.github.com>
Time    : 2024-07-18 07:39:46 +0000
Message : Merge pull request #927 from kleuveld/replace_checkout_with_restore

change the use of git checkout to git restore
  • Loading branch information
actions-user committed Jul 18, 2024
1 parent 058be50 commit 496d4c4
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 108 deletions.
150 changes: 44 additions & 106 deletions 05-history.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,18 +184,18 @@ $ git status
On branch main
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
(use "git restore <file>..." to discard changes in working directory)
modified: mars.txt
no changes added to commit (use "git add" and/or "git commit -a")
```

We can put things back the way they were
by using `git checkout`:
by using `git restore`:

```bash
$ git checkout HEAD mars.txt
$ git restore mars.txt
$ cat mars.txt
```

Expand All @@ -206,15 +206,15 @@ But the Mummy will appreciate the lack of humidity
```

As you might guess from its name,
`git checkout` checks out (i.e., restores) an old version of a file.
In this case,
we're telling Git that we want to recover the version of the file recorded in `HEAD`,
`git restore` restores an old version of a file.
By default,
it recovers the version of the file recorded in `HEAD`,
which is the last saved commit.
If we want to go back even further,
we can use a commit identifier instead:
we can use a commit identifier instead, using `-s` option:

```bash
$ git checkout f22b25e mars.txt
$ git restore -s f22b25e mars.txt
```

```bash
Expand All @@ -231,97 +231,44 @@ $ git status

```output
On branch main
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: mars.txt
```

Notice that the changes are currently in the staging area.
Again, we can put things back the way they were
by using `git checkout`:

```bash
$ git checkout HEAD mars.txt
```

::::::::::::::::::::::::::::::::::::::::: callout

## Don't Lose Your HEAD
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: mars.txt
Above we used
no changes added to commit (use "git add" and/or "git commit -a")
```bash
$ git checkout f22b25e mars.txt
```

to revert `mars.txt` to its state after the commit `f22b25e`. But be careful!
The command `checkout` has other important functionalities and Git will misunderstand
your intentions if you are not accurate with the typing. For example,
if you forget `mars.txt` in the previous command.
Notice that the changes are currently in the staging area.
Again, we can put things back the way they were by using `git restore`:

```bash
$ git checkout f22b25e
$ git restore mars.txt
$ cat mars.txt
```

```error
Note: checking out 'f22b25e'.
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 f22b25e Start notes on Mars as a base
```output
Cold and dry, but everything is my favorite color
The two moons may be a problem for Wolfman
But the Mummy will appreciate the lack of humidity
```

The "detached HEAD" is like "look, but don't touch" here,
so you shouldn't make any changes in this state.
After investigating your repo's past state, reattach your `HEAD` with `git checkout main`.


::::::::::::::::::::::::::::::::::::::::::::::::::

It's important to remember that
we must use the commit number that identifies the state of the repository
*before* the change we're trying to undo.
A common mistake is to use the number of
the commit in which we made the change we're trying to discard.
In the example below, we want to retrieve the state from before the most
recent commit (`HEAD~1`), which is commit `f22b25e`:
recent commit (`HEAD~1`), which is commit `f22b25e`. We use the `.` to mean all files:

![](fig/git-checkout.svg){alt='A diagram showing how git checkout HEAD~1 can be used to restore the previous version of two files'}
![](fig/git-restore.svg){alt='A diagram showing how git restore can be used to restore the previous version of two files'}

So, to put it all together,
here's how Git works in cartoon form:

![https://figshare.com/articles/How_Git_works_a_cartoon/1328266](fig/git_staging.svg){alt='A diagram showing the entire git workflow: local changes are staged using git add, applied to the local repository using git commit, and can be restored from the repository using git checkout'}

::::::::::::::::::::::::::::::::::::::::: callout

## Simplifying the Common Case

If you read the output of `git status` carefully,
you'll see that it includes this hint:

```output
(use "git checkout -- <file>..." to discard changes in working directory)
```

As it says,
`git checkout` without a version identifier restores files to the state saved in `HEAD`.
The double dash `--` is needed to separate the names of the files being recovered
from the command itself:
without it,
Git would try to use the name of the file as the commit identifier.


::::::::::::::::::::::::::::::::::::::::::::::::::

The fact that files can be reverted one by one
tends to change the way people organize their work.
Expand All @@ -344,13 +291,13 @@ Luckily, she has been keeping track of her project's versions using Git! Which c
let her recover the last committed version of her Python script called
`data_cruncher.py`?

1. `$ git checkout HEAD`
1. `$ git restore`

2. `$ git checkout HEAD data_cruncher.py`
2. `$ git restore data_cruncher.py`

3. `$ git checkout HEAD~1 data_cruncher.py`
3. `$ git restore -s HEAD~1 data_cruncher.py`

4. `$ git checkout <unique ID of last commit> data_cruncher.py`
4. `$ git restore -s <unique ID of last commit> data_cruncher.py`

5. Both 2 and 4

Expand All @@ -360,20 +307,16 @@ let her recover the last committed version of her Python script called

The answer is (5)-Both 2 and 4.

The `checkout` command restores files from the repository, overwriting the files in your working
The `restore` command restores files from the repository, overwriting the files in your working
directory. Answers 2 and 4 both restore the *latest* version *in the repository* of the file
`data_cruncher.py`. Answer 2 uses `HEAD` to indicate the *latest*, whereas answer 4 uses the
unique ID of the last commit, which is what `HEAD` means.

Answer 3 gets the version of `data_cruncher.py` from the commit *before* `HEAD`, which is NOT
what we wanted.

Answer 1 can be dangerous! Without a filename, `git checkout` will restore **all files**
in the current directory (and all directories below it) to their state at the commit specified.
This command will restore `data_cruncher.py` to the latest commit version, but it will also
restore *any other files that are changed* to that version, erasing any changes you may
have made to those files!
As discussed above, you are left in a *detached* `HEAD` state, and you don't want to be there.
Answer 1 results in an error. You need to specify a file to restore. If you want to restore all files
you should use `git restore .`



Expand All @@ -392,7 +335,7 @@ repository gets the correct change. The command `git revert [erroneous commit ID
new commit that reverses the erroneous commit.

The command `git revert` is
different from `git checkout [commit ID]` because `git checkout` returns the
different from `git restore -s [commit ID] .` because `git restore` returns the
files not yet committed within the local repository to a previous state, whereas `git revert`
reverses changes committed to the local and project repositories.

Expand Down Expand Up @@ -437,7 +380,7 @@ $ echo "Venus is beautiful and full of love" > venus.txt
$ git add venus.txt
$ echo "Venus is too hot to be suitable as a base" >> venus.txt
$ git commit -m "Comment on Venus as an unsuitable base"
$ git checkout HEAD venus.txt
$ git restore venus.txt
$ cat venus.txt #this will print the contents of venus.txt to the screen
```

Expand Down Expand Up @@ -470,7 +413,7 @@ the version of `venus.txt` committed to the repository is the one from the stagi
has only one line.

At this time, the working copy still has the second line (and
`git status` will show that the file is modified). However, `git checkout HEAD venus.txt`
`git status` will show that the file is modified). However, `git restore venus.txt`
replaces the working copy with the most recently committed version of `venus.txt`.

So, `cat venus.txt` will output
Expand Down Expand Up @@ -501,23 +444,22 @@ and what does happen?

## Getting Rid of Staged Changes

`git checkout` can be used to restore a previous commit when unstaged changes have
`git restore` can be used to restore a previous commit when unstaged changes have
been made, but will it also work for changes that have been staged but not committed?
Make a change to `mars.txt`, add that change using `git add`,
then use `git checkout` to see if you can remove your change.
then use `git restore` to see if you can remove your change.

::::::::::::::: solution

## Solution

After adding a change, `git checkout` can not be used directly.
After adding a change, `git restore` can not be used directly.
Let's look at the output of `git status`:

```output
On branch main
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
(use "git restore --staged <file>..." to unstage)
modified: mars.txt
```
Expand All @@ -526,19 +468,15 @@ Note that if you don't have the same output
you may either have forgotten to change the file,
or you have added it *and* committed it.

Using the command `git checkout -- mars.txt` now does not give an error,
Using the command `git restore mars.txt` now does not give an error,
but it does not restore the file either.
Git helpfully tells us that we need to use `git reset` first
Git helpfully tells us that we need to use `git restore --staged` first
to unstage the file:

```bash
$ git reset HEAD mars.txt
$ git restore --staged mars.txt
```

```output
Unstaged changes after reset:
M mars.txt
```

Now, `git status` gives us:

Expand All @@ -550,18 +488,18 @@ $ git status
On branch main
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
(use "git git restore <file>..." to discard changes in working directory)
modified: mars.txt
no changes added to commit (use "git add" and/or "git commit -a")
```

This means we can now use `git checkout` to restore the file
This means we can now use `git restore` to restore the file
to the previous commit:

```bash
$ git checkout -- mars.txt
$ git restore mars.txt
$ git status
```

Expand Down Expand Up @@ -618,6 +556,6 @@ $ git log --patch HEAD~9 *.txt
:::::::::::::::::::::::::::::::::::::::: keypoints

- `git diff` displays differences between commits.
- `git checkout` recovers old versions of files.
- `git restore` recovers old versions of files.

::::::::::::::::::::::::::::::::::::::::::::::::::
Loading

0 comments on commit 496d4c4

Please sign in to comment.