Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ch5): translate 589-973 #54

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
340 changes: 340 additions & 0 deletions ch5/[589-973]CHN.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,340 @@
[590]
目前为止有什么问题吗
这就是 git 大致的储存模型了
然后我们就要开始
实际地使用 git 命令
来理解 git 的命令
和这个图结构变换的关系
所以对于把历史
建模成 blob 构成的树
外面套一层 commit 树 # REVIEW ...
而 commit 则是 blob 树的一个快照
而 blob 树则会
随着不同 commit 整体改变
然后引用则会指向图上的某一节点
没问题吗 好强啊
我们有了对象和引用以后
这就可以构成一整个 git 仓库了
这就是仓库里实际存的东西
从高层次(用户层)来说
所有的 git 命令
就只是在改变对象或者引用数据而已
现在我们来讲一些 git 命令
我们会和 Vim 那堂课那样交互式地演示
然后可以参考课堂笔记来了解细节
因为这个工具实在非常强大
我们不可能二十分钟讲完
*那就讲一个小时
然后我们进到一个叫做 `playground` 的目录
开个新文件夹叫做 `demo` 然后切进去
我们假设这是项目的根目录
现在是空的 毕竟我刚刚开这文件夹
我现在用 `git init` 命令
来把它初始化成一个 git 仓库
init = initialize = 初始化
然后它告诉我它在这个目录
下面的 `.git` 文件夹里
初始化了空 git 仓库
[629]
如果只是跑 `ls`
还是啥都没有
但是我跑 `ls -a`
就会有个隐藏的文件夹 `.git`
* `.` 开头的文件默认隐藏 文件夹是特殊的文件
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* `.` 开头的文件默认隐藏 文件夹是特殊的文件
* `.` 开头的文件默认隐藏 文件夹是特殊的文件
* 至于为啥 `.` 开头的文件表示隐藏,最初来源于 ls 的一个 bug

而我跑 `ls .git`
会看到一堆的文件
这就是本地磁盘上 git 储存数据的地方
也就是那些对象和引用
然后你在这里也可以看到
对象(`objs`)和引用(`refs`)两个文件夹
仓库的数据就存在里面
而另外一个学习时值得注意的命令
则是 `git help`
然后你要加一个子命令名作为参数
来指定要看啥的帮助
我现在跑 `git help init`
它就会告诉我 `git init` 的帮助信息
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
它就会告诉我 `git init` 的帮助信息
它就会告诉我 `git init` 的帮助信息
* 另外两种方法是 `git init --help` 和 `man git-init`

然后有些命令可以用来
了解 git 仓库的状态
例如 `git status`
可以了解用户层的仓库状态
先不看第一行
第二行说我们现在还没有 commit
因为我们刚开一个新的 git 仓库
自然也就没有历史
还有人要看吗 我要擦掉了
我想要一路打命令
一路展示引用和对象数据的变化
现在这个美妙的空图像
展现了我们~~整洁~~的空仓库
所以来往历史里加点东西
[665]
让我开一个新的文件
里面只有 `hello world`
通常来说这会是你的源代码啥的
现在 我想要把目录里的内容
变成新的快照
代表我仓库的第一个状态
你可能会猜
是不是有个 `git snapshot` 啥的
来给整个目录来个快照
因为某些原因
以及为了让操作更灵活
让你选择下一个快照里包含什么
git 并没有完全一致的功能
初学者经常在这里满头问号
所以我现在先把这个说了
git 里有一个概念叫做 staging 区
在用户层面上
你通过这个方式告诉 git
你想要把哪些修改包含在下一个快照里
现在再跑一次 `git status`
它会说现在没有 commit
然后 `hello.txt` 没有被纳入版本管理
意思就是说
git 知道这里有个文件
但是就是不会加进下一个快照
现在 git 会暂时忽略它
然后我现在跑 `git add hello.txt`
然后再跑 `git status`
它就会说这些修改将被 commit:
新文件 `hello.txt`
然后我现在跑 git 的快照命令
实际上是 `git commit`
就会在黑板上创造一个新的圈(节点)
* 要在整个 commit 完成之后
* 例如要求 commit message 非空否则默认 abort
这个文本文件会被包含在那个快照里
然后我现在跑这个命令
[708]
它会弹出一个文本编辑器
让我输入这个 commit 的 message
写一手好 commit message 非常重要
以后你(或者别人)往回看版本历史的时候
能够很方便地知道这样改变的原因
我这里就随便写点
但是课堂笔记里有个链接
来指导你写高质量的 commit message
然后 git 给我打出了一些信息
master 先不管
这个 是 commit 的 hash
现在我的历史上有了一个节点
节点里面是一个
只有一个文件节点的 blob 树
这个文件节点的文件名叫做 `hello.txt`
里面写有 `hello world` # REVIEW 树套树套..
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Git 其实是 DAG 套树

Copy link
Collaborator Author

@ksyx ksyx Feb 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

但是他这里说树(
而且 dag 可以转成有根树吧

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

做不到吧,你考虑 merge 的情况,一定可能存在有一个节点有两个父亲的情况,这必不可能是个树

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
里面写有 `hello world` # REVIEW 树套树套..
里面写有 `hello world` # REVIEW DAG套树

它的短 hash 是 `42fb7a2...`
git 把它截断了
然后是我的 commit message
接下来是再次提醒我加了个新文件 `hello.txt`
现在我跑 `git log` 命令
这个命令能够帮助你可视化历史
非常有用
有问题吗
学生:这个 `42fb7a2` 是代表一整个树
还是 `hello` 这个功能
#REVIEW 也没说啥树= =
好问题 也就是说这个 hash 到底代表什么
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
好问题 也就是说这个 hash 到底代表什么
好问题 也就是说这个 hash 到底代表什么
* 其实是代表一个 object,可能是 commit、blob 或者 tree,这里代表一个 commit;
* 一个 commit 包含 commit message、作者、签名、parent commit 的指针(也就是 hash,可能有多个,在 merge 那里会提到)和代表 commit 时仓库状态的 tree;
* 一个 tree 包含其所有子节点的指针(即目录下所有文件(tree 和 blob)的指针)和对应节点的名字,也就是说 tree 是 Git 内部对应目录的数据结构;
* 一个 blob 包含一个文件的内容

这是 commit 的 hash
commit 里面有 blob 树的 hash
以及(commit message,commit 时间等)其他信息
实际上 我可以用 `git cat-file -p 42fb7a2`
这是 git 内部实现用的命令
会把 commit 的内容打出来
你会注意到它和黑板上的结构一致
它的 blob tree 的 hash 是这个
作者是这个
commit message 是这个
然后我可以继续深入
`cat-file -p` 这个 hash
你可以看到树里只有一个文件
这个 blob 的 hash 是这个
[758]
再套一层娃
它就会给我显示文件的实际内容了
所以这就是用来展示
git 对象数据的内部命令
那边还有提问?
学生:你为啥要手动指定要加的文件
学生:而不是直接把所有修改 commit 了
问得好
这个同学问 为啥不直接 commit 所有改变
而是要来个 `git add`
实际上 我们可以一次 commit 所有改变
如果你跑 `git commit -a`
就会对所有纳入版本管理的文件的改变
进行 commit
也就是在前一个快照里有
而且之后被修改过的文件
但是不包括新文件
也有 `git add` 的变体
`git add :/` 会从项目根目录递归 stage 所有文件
#REVIEW 没有任何问题 只是给你看看可爱的 :/
在高层次来说
把 `git add` 和 `git commit` 分开
`git commit` 不对整个目录进行快照
这样设计的原因是
你通常来说并不想把所有东西加入快照 #REVIEW svn 哈哈
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

别啊,SVN 也是可以设置 ignore 的,只是没 Git 灵活

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ignore 和 stage 还是有区别?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是,所以说没 git 灵活(Git 可以随时随地随意调整,SVN 必须写死在文件里)

举几个例子
[785]
一个是我在勤奋工作 #REVIEW packing
我写了两个新功能
我并不是很想把新功能 A 和 B
打到一个快照里
说我实现了 A 和 B
我更想分成两个快照
先是实现 A
然后是实现 B
然后第一个快照有 A 功能
第二个有 A 和 B 功能
有了 `git add` 和 staging 区
才能够使我这样做
另外一个是
假设我在修 bug
然后我输出调试代码里满地都是
然后我终于找到了是多加了 1
然后我把它修了以后想来个新快照
但是那些快照最好不要有输出调试
而只是去掉那个 +1
我可以手动删掉所有调试输出
而 git 就很香
它可以让我选择 add 哪一块修改
例如只 add 删掉这个 -1 这行
然后就可以 commit 来个新快照
之后就可以把输出调试全部丢掉了
这是 staging 区的两种用法
也因此没有直接快照所有修改的命令
学生:还有一个例子 你目录下面有个日志文件
Jon 说到了
你目录下面有个你程序打出来的日志文件
你快照的时候把这个加入快照没意思啊
以及其他的一些 例如编译时的 `.o` 和可执行文件啥的
这些东西你也不应该加进版本历史里
[836]
接着前面讲
我清个屏
然后展示一下 `git log` 命令
这个命令可以用来把版本历史可视化
十分有用
默认情况下
`git log` 会展示扁平化的版本历史
即便版本历史是一个图
它还是会以线性的形式展示
我觉得这样十分令人头大
所以我基本上不单独用 `git log`
我可以给它加一些参数
使得 `git log` 以图的形式展现
你可以把它当作咒语先记着
如果你真的想深入了解这些选项
可以去查阅文档
现在来看没什么区别
因为我们图上只有一个节点
所以图形式和扁平的形式并没有多大区别
我现在创建一个新快照
然后再回来跑这个命令
看看会发生什么
我现在在 `hello.txt` 尾部加一行
所以现在 `cat hello.txt`
会有之前的内容和新加的内容
然后跑 `git commit`
这样并不会有什么用
会告诉你没有要 commit 的东西
为什么呢
因为我没把要加入下一个快照的改变
加到 staging 区里
git 也就不知道要快照什么了
那我现在 `git add hello.txt`
`git status` 就会说这个改变将要被 commit
这个文件修改
然后就可以 `git commit`
随便打个 commit message
然后就打了个新快照
现在我的历史上就有了新节点
它的 hash 是 `62da510`
然后我现在再跑之前那个
带有好几个参数的 `git log`
它现在就更像个图了
[884]
注意这里其实是把黑板上的图转了一下
竖着画而不是横着画
越新的 commit 在越上面
这是一个 commit 和它的 hash
然后下面有 commit message 和一些信息
这是我接下来要说的东西
我们现在一直在谈对象 #REVIEW 草(
也就是我们仓库里实际的内容
接下来我们来聊聊
用来给仓库里内容命名成人类能理解的东西
称为引用
`master` 是你初始化仓库的时候
默认创建的引用
它一般用来指代你代码仓库的主开发分支
也就是最新最热的分支
你可以把 `master` 当作指向这个 commit 的指针
然后在加新 commit 的时候
这个指针就会被改变 指向新 commit
然后是这个 `HEAD`
这是 git 里一个特殊的引用
[909]
它和 `master` 同样是引用 但是有点特殊 #REVIEW
`HEAD` 通常用来指代你现在所在的版本
有问题吗
那边有人要提问
学生:我用 GitHub 要开个账号来做在线开发
学生:git 和 GitHub 有什么关系
学生:它们是同一个东西还是有什么神秘交易
#REVIEW p__ 和 p___hub 什么关系
问得好
这位同学问
用 GitHub 要注册一个账号
所以 GitHub 和 git 有什么关系
答案是
GitHub 托管 git 仓库
所以你可以在上面开个账号储存 git 仓库
然后用它和其他人协作
git 这个命令行工具和 GitHub 是独立的
你并不需要 GitHub 才能用 git
甚至不一定要用 GitHub 协作
还有其他的 git 仓库托管服务提供商
例如 BitBucket 和 GitLab 等
总之 GitHub 托管 git 仓库
还有问题吗
学生:所以我们现在用 git
学生:整出了图上的两个 commit
学生:如果我想在想把它放上 GitHub
学生:是不是有登录啥的命令
所以提问是你要怎么把仓库传上 GitHub
是的 有另一套命令来完成这些工作
[934]
你可以让你本地的版本历史副本(仓库)
和远程的副本交互
这是另一套 `git remote` 命令
把你的副本数据传输到远程
或者从远程把数据获取到你的本地副本
我们晚点会讲到这个
或者在课程笔记或者补充视频里
还有问题吗
好 还有几个基本命令要展示一下
所以目前为止
我新建了一个文件并修改了一下
展示了版本历史
但是除了读它
我们并没有真正把它用起来
而一个实用的命令是 `git checkout`
这是一个扭曲的命令
你可以用它做好多种事情
其中一个是在版本历史之间横跳
我可以给 `git checkout` 一个 commit hash
并不需要输入一整串 只要一个前缀
[962]
就像我刚刚说的那样
# REVIEW and it is a smart refresh of what i am talking about
它会把我的工作目录的状态
改变到这个 commit 时的状态
然后我现在 `cat hello.txt`
就像在第一次 commit 的时候一样
只有一行
第二行是后面加的
然后我现在 `git log`
它真的非常有用 会把所有东西都告诉你
跑了以后你就会发现和之前有点点微妙的区别