Git 练习：存储库导航
Git
![](/data/attachment/album/201909/23/224146fo79str9bxs8wb6s.jpg)


我觉得前几天的 [curl 练习](https://jvns.ca/blog/2019/08/27/curl-exercises/)进展顺利，所以今天我醒来后，想尝试编写一些 Git 练习。Git 是一大块需要学习的技能，可能要花几个小时才能学会，所以我分解练习的第一个思路是从“导航”一个存储库开始的。


我本来打算使用一个玩具测试库，但后来我想，为什么不使用真正的存储库呢？这样更有趣！因此，我们将浏览 Ruby 编程语言的存储库。你无需了解任何 C 即可完成此练习，只需熟悉一下存储库中的文件随时间变化的方式即可。


### 克隆存储库


开始之前，需要克隆存储库：



```
git clone https://github.com/ruby/ruby
```

与实际使用的大多数存储库相比，该存储库的最大不同之处在于它没有分支，但是它有很多标签，它们与分支相似，因为它们都只是指向一个提交的指针而已。因此，我们将使用标签而不是分支进行练习。*改变*标签的方式和分支非常不同，但*查看*标签和分支的方式完全相同。


### Git SHA 总是引用同一个代码


执行这些练习时要记住的最重要的一点是，如本页面所述，像`9e3d9a2a009d2a0281802a84e1c5cc1c887edc71` 这样的 Git SHA 始终引用同一个的代码。下图摘自我与凯蒂·西勒·米勒撰写的一本杂志，名为《[Oh shit, git!](https://wizardzines.com/zines/oh-shit-git/)》。（她还有一个名为 <https://ohshitgit.com/> 的很棒的网站，启发了该杂志。）


![](/data/attachment/album/201909/23/224212gedldsaen5u4qzzl.png)


我们将在练习中大量使用 Git SHA，以使你习惯于使用它们，并帮助你了解它们与标签和分支的对应关系。


### 我们将要使用的 Git 子命令


所有这些练习仅使用这 5 个 Git 子命令：



```
git checkout
git log (--oneline, --author, and -S will be useful)
git diff (--stat will be useful)
git show
git status
```

### 练习


1. 查看 matz 从 1998 年开始的 Ruby 提交。提交 ID 为 `3db12e8b236ac8f88db8eb4690d10e4a3b8dbcd4`。找出当时 Ruby 的代码行数。
2. 检出当前的 master 分支。
3. 查看文件 `hash.c` 的历史记录。更改该文件的最后一个提交 ID 是什么？
4. 了解最近 20 年来 `hash.c` 的变化：将 master 分支上的文件与提交 `3db12e8b236ac8f88db8eb4690d10e4a3b8dbcd4` 的文件进行比较。
5. 查找最近更改了 `hash.c` 的提交，并查看该提交的差异。
6. 对于每个 Ruby 版本，该存储库都有一堆**标签**。获取所有标签的列表。
7. 找出在标签 `v1_8_6_187` 和标签 `v1_8_6_188` 之间更改了多少文件。
8. 查找 2015 年的提交（任何一个提交）并将其检出，简单地查看一下文件，然后返回 master 分支。
9. 找出标签 `v1_8_6_187` 对应的提交。
10. 列出目录 `.git/refs/tags`。运行 `cat .git/refs/tags/v1_8_6_187` 来查看其中一个文件的内容。
11. 找出当前 `HEAD` 对应的提交 ID。
12. 找出已经对 `test/` 目录进行了多少次提交。
13. 提交 `65a5162550f58047974793cdc8067a970b2435c0` 和 `9e3d9a2a009d2a0281802a84e1c5cc1c887edc71` 之间的 `lib/telnet.rb` 的差异。该文件更改了几行？
14. 在 Ruby 2.5.1 和 2.5.2 之间进行了多少次提交（标记为 `v2_5_1` 和 `v2_5_3`）（这一步有点棘手，步骤不只一步）
15. “matz”（Ruby 的创建者）作了多少提交？
16. 最近包含 “tkutil” 一词的提交是什么？
17. 检出提交 `e51dca2596db9567bd4d698b18b4d300575d3881` 并创建一个指向该提交的新分支。
18. 运行 `git reflog` 以查看你到目前为止完成的所有存储库导航操作。 ——————————————————————————–


via: [https://jvns.ca/blog/2019/08/30/git-exercises–navigate-a-repository/](https://jvns.ca/blog/2019/08/30/git-exercises--navigate-a-repository/)


作者：[Julia Evans](https://jvns.ca/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


OK
I think the [curl exercises](https://jvns.ca/blog/2019/08/27/curl-exercises/) the other day went
well, so today I woke up and wanted to try writing some Git exercises. Git is a big thing to learn,
probably too big to learn in a few hours, so my first idea for how to break it down was by starting
by **navigating** a repository.

I was originally going to use a toy test repository, but then I thought – why not a real repository? That’s way more fun! So we’re going to navigate the repository for the Ruby programming language. You don’t need to know any C to do this exercise, it’s just about getting comfortable with looking at how files in a repository change over time.

### clone the repository

To get started, clone the repository:

```
git clone https://github.com/ruby/ruby
```


The big different thing about this repository (as compared to most of the repositories you’ll work
with in real life) is that it doesn’t have branches, but it DOES have lots of tags, which are
similar to branches in that they’re both just pointers to a commit. So we’ll do exercises with tags
instead of branches. The way you *change* tags and branches are very different, but the way you
*look at* tags and branches is exactly the same.

### a git SHA always refers to the same code

The most important thing to keep in mind while doing these exercises is that a git SHA like
`9e3d9a2a009d2a0281802a84e1c5cc1c887edc71`

always refers to the same code, as explained in this
page. This page is from a zine I wrote with Katie Sylor-Miller called [Oh shit, git!](https://wizardzines.com/zines/oh-shit-git/). (She also has a great site called
[https://ohshitgit.com/](https://ohshitgit.com/) that inspired the zine).



![](https://wizardzines.com/zines/oh-shit-git/samples/ohshit-commit.png)

We’ll be using git SHAs really heavily in the exercises to get you used to working with them and to help understand how they correspond to tags and branches.

### git subcommands we’ll be using

All of these exercises only use 5 git subcommands:

```
git checkout
git log (--oneline, --author, and -S will be useful)
git diff (--stat will be useful)
git show
git status
```


### exercises

- Check out matz’s commit of Ruby from 1998. The commit ID is
`3db12e8b236ac8f88db8eb4690d10e4a3b8dbcd4`

. Find out how many lines of code Ruby was at that time. - Check out the current master branch
- Look at the history for the file
`hash.c`

. What was the last commit ID that changed that file? - Get a diff of how
`hash.c`

has changed in the last 20ish years: compare that file on the master branch to the file at commit`3db12e8b236ac8f88db8eb4690d10e4a3b8dbcd4`

. - Find a recent commit that changed
`hash.c`

and look at the diff for that commit - This repository has a bunch of
**tags**for every Ruby release. Get a list of all the tags. - Find out how many files changed between tag
`v1_8_6_187`

and tag`v1_8_6_188`

- Find a commit (any commit) from 2015 and check it out, look at the files very briefly, then go back to the master branch.
- Find out what commit the tag
`v1_8_6_187`

corresponds to. - List the directory
`.git/refs/tags`

. Run`cat .git/refs/tags/v1_8_6_187`

to see the contents of one of those files. - Find out what commit ID
`HEAD`

corresponds to right now. - Find out how many commits have been made to the
`test/`

directory - Get a diff of
`lib/telnet.rb`

between the commits`65a5162550f58047974793cdc8067a970b2435c0`

and`9e3d9a2a009d2a0281802a84e1c5cc1c887edc71`

. How many lines of that file were changed? - How many commits were made between Ruby 2.5.1 and 2.5.2 (tags
`v2_5_1`

and`v2_5_3`

) - How many commits were authored by
`matz`

(Ruby’s creator)? - What’s the most recent commit that included the word
`tkutil`

? - Check out the commit
`e51dca2596db9567bd4d698b18b4d300575d3881`

and create a new branch that points at that commit. - Run
`git reflog`

to see all the navigating of the repository you’ve done so far


**Question #1: **Check out matz's commit of Ruby from 1998. The commit ID is `3db12e8b236ac8f88db8eb4690d10e4a3b8dbcd4`. Find out how many lines of code Ruby was at that time.

**Solution #1: **

git checkout 3db12e8b236ac8f88db8eb4690d10e4a3b8dbcd4 find . -name '*.c' | xargs wc -l

**Question #2:** Check out the current master branch

**Solution #2:**

git checkout master

**Question #3:** Look at the history for the file `hash.c`. What was the last commit ID that changed that file?

**Solution #3:**

git log hash.c # look at the first line to get the commit ID. # I got 3df37259d81d9fc71f8b4f0b8d45dc9d0af81ab4.

**Question #4:** Get a diff of how `hash.c` has changed in the last 20ish years: compare that file on the master branch to the file at commit `3db12e8b236ac8f88db8eb4690d10e4a3b8dbcd4`.

**Solution #4:**

git diff 3db12e8b236ac8f88db8eb4690d10e4a3b8dbcd4 hash.c

**Question #5:** Find a recent commit that changed `hash.c` and look at the diff for that commit

**Solution #5:**

git log hash.c # look at the first line to get the commit ID. # I got 3df37259d81d9fc71f8b4f0b8d45dc9d0af81ab4. git show 3df37259d81d9fc71f8b4f0b8d45dc9d0af81ab4

**Question #6:** This repository has a bunch of **tags** for every Ruby release. Get a list of all the tags.

**Solution #6:**

git tags

**Question #7:** Find out how many files changed between tag `v1_8_6_187` and tag `v1_8_6_188`

**Solution #7:**

git diff v1_8_6_187 v1_8_6_188 --stat # 5 files!

**Question #8:** Find a commit (any commit) from 2015 and check it out, look at the files very briefly, then go back to the master branch.

**Solution #8:**

git log | grep -C 2 ' 2015 ' | head git checkout bd5d443a56ee4bcb59a0a08776c07dea3ee60121 ls git checkout master

**Question #9:** Find out what commit the tag `v1_8_6_187` corresponds to.

**Solution #9:**

git show v1_8_6_187

**Question #10:** List the directory `.git/refs/tags`. Run `cat .git/refs/tags/v1_8_6_187` to see the contents of one of those files.

**Solution #10:**

$ cat .git/refs/tags/v1_8_6_187 928e6916b25aee5b2b379999a3fa8816d40db714

**Question #11:** Find out what commit ID `HEAD` corresponds to right now.

**Solution #11:**

git show HEAD

**Question #12:** Find out how many commits have been made to the `test/` directory

**Solution #12:**

git log --oneline test/ | wc

**Question #13:** Get a diff of `lib/telnet.rb` between the commits `f2a91397fd7f9ca5bb3d296ec6df2de6f9cfc7cb` and `e44c9b11475d0be2f63286c1332a48da1b4d8626 `. How many lines of that file were changed?

**Solution #13:**

git diff f2a91397fd7f9..e44c9b11475d0 lib/tempfile.rb

**Question #14:** How many commits were made between Ruby 2.5.1 and 2.5.2 (tags `v2_5_1` and `v2_5_3`)

**Solution #14:**

git log v2_5_1..v2_5_3 --oneline | wc

**Question #15:** How many commits were authored by `matz` (Ruby's creator)?

**Solution #15:**

git log --oneline --author matz | wc -l

**Question #16:** What's the most recent commit that included the word `tkutil`?

**Solution #16:**

git log -S tkutil # result is 6c5f5233db596c2c7708d5807d9a925a3a0ee73a

**Question #17:** Check out the commit `e51dca2596db9567bd4d698b18b4d300575d3881` and create a new branch that points at that commit.

**Solution #17:**

git checkout e51dca2596db9567bd4d698b18b4d300575d3881 git branch my-branch

**Question #18:** Run `git reflog` to see all the navigating of the repository you've done so far

**Solution #18:**

git reflog