git学习总结
GIT命令
设置与配置
$ git help // 命令用来显示任何命令的 Git 自带文档。
$ git config // 配置邮箱用户名,别名,默认项等
获取与创建项目
$ git init // 初始化新git项目
$ git clone
/*
1、它创建了一个新目录,切换到新的目录。
2、git init 来初始化一个空的 Git 仓库
3、为你指定的 URL 添加一个(默认名称为 origin 的)远程仓库(git remote add)
4、针对远程仓库执行 git fetch
5、通过 git checkout 将远程仓库的最新提交检出到本地的工作目录。
*/
快照基础
$ git add // 将内容从工作目录添加到暂存区(或称为索引(index)区),以备下次提交。 当 git commit 命令执行时,默认情况下它只会检查暂存区域,因此 git add 是用来确定下一次提交时快照的样子的。
$ git status // 显示工作区及暂存区域中不同状态的文件。 其中包含了已修改但未暂存,或已经暂存但没有提交的文件。
$ git diff // 查看你工作环境与你的暂存区的差异(git diff 默认的做法)
$ git diff --staged // 你暂存区域与你最后提交之间的差异
$ git diff master branchB // 或者比较两个提交记录的差异
$ git commit // 将所有通过 git add 暂存的文件内容在数据库中创建一个持久的快照,然后将当前分支上的分支指针移到其之上。
$ git reset // 用来根据你传递给动作的参数来执行撤销操作。 它可以移动 HEAD 指针并且可选的改变 index 或者暂存区,如果你使用 --hard 参数的话你甚至可以改变工作区。
$ git rm // Git 用来从工作区,或者暂存区移除文件的命令。 在为下一次提交暂存一个移除操作上,与 git add 相反。
$ git mv // 移到一个文件并且在新文件上执行`git add`命令及在老文件上执行`git rm`命令。
$ git clean // 从工作区中移除不想要的文件的命令
分支与合并
$ git branch // 分支管理工具: 它可以列出你所有的分支、创建新分支、删除分支及重命名分支。
$ git checkout // 命令用来切换分支,或者检出内容到工作目录。
$ git merge // 合并一个或者多个分支到你已经检出的分支中。 然后它将当前分支指针移动到合并结果上。
$ git log // 展示一个项目的可达历史记录,从最近的提交快照起。 默认情况下,它只显示你当前所在分支的历史记录,但是可以显示不同的甚至多个头记录或分支以供遍历。 此命令通常也用来在提交记录级别显示两个或多个分支之间的差异。
$ git stash // 临时地保存一些还没有提交的工作,以便在分支上不需要提交未完成工作就可以清理工作目录。
$ git tag // 用来为代码历史记录中的某一个点指定一个永久的书签。 一般来说它用于发布相关事项。
项目分享与更新
$ git fetch // 命令与一个远程的仓库交互,并且将远程仓库中有但是在当前仓库的没有的所有信息拉取下来然后存储在你本地数据库中.
$ git pull // 命令基本上就是 git fetch 和 git merge 命令的组合体,Git 从你指定的远程仓库中抓取内容,然后马上尝试将其合并进你所在的分支中。
$ git push // 命令用来与另一个仓库通信,计算你本地数据库与远程仓库的差异,然后将差异推送到另一个仓库中。 它需要有另一个仓库的写权限,因此这通常是需要验证的。
$ git remote // 你远程仓库的管理工具,可以列举、添加、移除、重命名功能等
补丁
$ git cherry-pick // 命令用来获得在单个提交中引入的变更,然后尝试将作为一个新的提交引入到你当前分支上。
$ git rebase // 命令基本是是一个自动化的 cherry-pick 命令。 它计算出一系列的提交,然后再以它们在其他地方以同样的顺序一个一个的 cherry-picks 出它们。
管理
$ git gc // 执行 “garbage collection”,删除数据库中不需要的文件和将其他文件打包成一种更有效的格式。
$ git fsck // 命令用来检查内部数据库的问题或者不一致性。
$ git reflog // 命令分析你所有分支的头指针的日志来查找出你在重写历史上可能丢失的提交。
GIT基础
git项目中各文件的各个状态及其关系
检查当前状态: git status
$ git status
/*
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
*/
跟踪新文件:git add
, 后面可以跟文件名或者文件夹名,添加文件或者文件夹所有文件。
提交文件:git commit
, 接-m参数传递 commit 信息,提交代码生成一个SHA-1值
add, commit命令合并:
git commit -a -m 'added new benchmarks'
更新远程代码:
git fetch
命令从服务器上抓取本地没有的数据时,它并不会修改工作目录中的内容,需要自己合并。
git pull
= git fetch
+ git merge
推送代码:git push
忽略文件:.gitignore
,规则如下:
所有空行或者以
#
开头的行都会被 Git 忽略。可以使用标准的 glob 模式(shell 所使用的简化了的正则表达式)匹配,它会递归地应用在整个工作区中。
匹配模式可以以(
/
)开头防止递归。匹配模式可以以(
/
)结尾指定目录。要忽略指定模式以外的文件或目录,可以在模式前加上叹号(
!
)取反。
查看提交历史:git log
按时间先后顺序列出所有的提交,最近的更新排在最上面。
参数:
1、-p
或 --patch
:它会显示每次提交所引入的差异(按 补丁 的格式输出)。 你也可以限制显示的日志条目数量,例如使用 -2
选项来只显示最近的两次提交。
2、--stat
:每次提交的简略统计信息
3、--pretty
:使用不同于默认格式的方式展示提交历史,例如
$ git log --pretty=oneline
,将所有信息一行显示,另外默认的参数还有short
,full
和 fuller
git log --pretty=format:"%h - %an, %ar : %s"
:定制记录的显示格式
format
接受的常用格式占位符的写法及其代表的意义。
无法复制加载中的内容
$ git commit --amend
重新提交
这个命令会将暂存区中的文件提交。 如果自上次提交以来你还未做任何修改(例如,在上次提交后马上执行了此命令), 那么快照会保持不变,而你所修改的只是提交信息。例如:
$ git commit -m 'initial commit' // 此时发现有遗漏的修改
$ git add forgotten_file
$ git commit --amend
最终你只会有一个提交——第二次提交将代替第一次提交的结果。用一个 新的提交 替换旧的提交,从效果上来说,就像是旧有的提交从未存在过一样,它并不会出现在仓库的历史中。
撤销操作
1、git checkout --
个文件在本地的任何修改都会消失——Git 会用最近提交的版本覆盖掉它。
标签管理:
1、 git tag
:查看标签 (可带上可选的 -l
选项 --list
)
2、git tag -a
$ git tag -a v1.0 -m "my version 1.0"
// -m 选项指定了一条将会存储在标签中的信息。
// 如果没有为附注标签指定一条信息,Git 会启动编辑器要求你输入信息。
$ git show v1.0
/*
tag v1.0
Tagger: ***
Date: ***
my version 1.0
commit ....
*/
// 输出显示了打标签者的信息、打标签的日期时间、附注信息,然后显示具体的提交信息。
3、$ git tag -a
: 对指定Commit ID 打tag
注意:
默认情况下,git push
命令并不会传送标签到远程仓库服务器上。 在创建完标签后你必须显式地推送标签到共享服务器上。 这个过程就像共享远程分支一样——你可以运行 git push origin
。
4、git tag -d
:删除标签(并不会从任何远程仓库中移除这个标签)
git push
删除远程分支,或者:
git push
5、git checkout
:检出该标签下文件.
注意:如果你做了某些更改然后提交它们,标签不会发生变化, 你的新提交将不属于任何分支,并且将无法访问,除非通过确切的提交哈希才能访问。 因此,如果你需要进行更改,比如你要修复旧版本中的错误,那么通常需要创建一个新分支:
git checkout -b version2
别名:
$ git config --global alias.co checkout // git checkout == git co
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status
GIT分支
远程仓库
git remote
查看你已经配置的远程仓库服务器,指定选项 -v
,会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL。
$ git remote -v
/*
origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)
*/
git remote add
: 添加远程仓库
git fetch
: 从指定源拉取数据(只会将数据下载到你的本地仓库——它并不会自动合并或修改你当前的工作)
git push
:推送到远程分支。例如:
$ git push origin master
/*
只有当你有所克隆服务器的写入权限,并且之前没有人推送过时,这条命令才能生效。
当你和其他人在同一时间克隆,他们先推送到上游然后你再推送到上游,你的推送就会毫无疑问地被拒绝。
你必须先抓取他们的工作并将其合并进你的工作后才能推送。
*/
git remote rename
: 重命名远程分支
git remote remove
: 移除远程仓库
1、git branch
:创建分支(一个可以移动的新的指针),例如创建一个 testing 分支:
$ git branch testing
注意:HEAD指针指向当前所在的分支(可以将 HEAD
想象为当前分支的别名),使用git checkout
可以切换当前分支,例如:
git checkout testing
git 指针状态
当我们修改testing分支上的内容,并且commit时,此时指针状态如下
此时,如果我们checkout master,
git将完成两部分工作: 一是使 HEAD 指回 master
分支,二是将工作目录恢复成 master
分支所指向的快照内容。
继续向master提交修改
此时将产生分叉,可通过git log --oneline --decorate --graph --all
Git 的分支实质上仅是包含所指对象校验和(长度为 40 的 SHA-1 值字符串)的文件,所以它的创建和销毁都异常高效。 创建一个新分支就相当于往一个文件中写入 41 个字节(40 个字符和 1 个换行符)。
经典:
实际工作中你可能会用到类似的工作流。 你将经历如下步骤:
- 开发某个网站。
- 为实现某个新的用户需求,创建一个分支。
- 在这个分支上开展工作。
正在此时,你突然接到一个电话说有个很严重的问题需要紧急修补。 你将按照如下方式来处理:
- 切换到你的线上分支(production branch)。
- 为这个紧急任务新建一个分支,并在其中修复它。
- 在测试通过之后,切换回线上分支,然后合并这个修补分支,最后将改动推送到线上分支。
- 切换回你最初工作的分支上,继续工作。
// master
$ git checkout -b iss53 // iss53
$ git add . // iss53
$ git commit -m '**' // iss53
$ git checkout master // master
$ git checkout -b hotfix // hotfix
$ git add . // hotfix
$ git commit -m '**' // hotfix
// 测试验证没问题以后
$ git checkout master // master
$ git merge hotfix // master
// 合并以后就可以删除该分支了(最好不用动被人的分支,除非是自己新建的)
$ git branch -d hotfix // master
$ git checkout i3353 // iss53分支继续开发并提交了C5
此时 如果你把iss53分支合并到master:这和你之前合并 hotfix
分支的时候看起来有一点不一样。master
分支所在提交并不是 iss53
分支所在提交的直接祖先,Git 不得不做一些额外的工作。 出现这种情况的时候,Git 会使用两个分支的末端所指的快照(C4
和 C5
)以及这两个分支的公共祖先(C2
),做一个简单的三方合并,并产生一个新的commit。
综上:当我们需要commit新代码时,最好是先stash本地代码,然后同步远程的代码,使本地的最新commit跟远程的最新commit ID一致,我们再继续commit,此时我们推送代码时,就会HEAD指针直接Fast-forward,不会产生新的merge commit
git stash
或 git stash push
:存储改动
git stash list
: 查看存储列表
git stash list
/*
stash@{0}: On wallet-page: 1018-unit-test
stash@{1}: On wallet-page: 1013
*/
git stash apply
:弹出存储
git stash apply // 默认弹出最新的存储
git stash apply stash@{1} // 弹出指定存储
分支跟踪:从一个远程跟踪分支检出一个本地分支会自动创建所谓的“跟踪分支”,如果在一个跟踪分支上输入 git pull
,Git 能自动地识别去哪个服务器上抓取、合并到哪个分支。
git checkout -b
git checkout --track origin/serverfix
由于这个操作太常见了,该捷径本身还有一个捷径。 如果你尝试检出的分支 (a) 不存在且 (b) 刚好只有一个名字与之匹配的远程分支,那么 Git 就会为你创建一个跟踪分支,例如:
$ git checkout serverfix
/*
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
*/
设置一个已有的本地分支与远程分支关联:使用 -u
或 --set-upstream-to
选项运行 git branch
来显式地设置,例如:git branch -u origin/serverfix
删除远程分支:可以运行带有 --delete
选项的 git push
命令来删除一个远程分支。 例如删除远程serverfix
分支:
git push origin --delete serverfix
变基
再来看下merge的时候分支的情况
此时会多一个merge的commit C5,往往会使人疑惑,接下来介绍一个方法使之不产生额外的分支来合并代码,变基(rebase):提取在 **C4**
中引入的补丁和修改,然后在 **C3**
的基础上应用一次。
下面将展示如何操作:
$ git checkout experiment
$ git rebase master
它的原理是首先找到这两个分支(即当前分支 experiment
、变基操作的目标基底分支 master
) 的最近共同祖先 C2
,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件, 然后将当前分支指向目标基底 C3
, 最后以此将之前另存为临时文件的修改依序应用。
注意,此时只是提交了rebase
,还需回到master进行合并
$ git checkout master
$ git merge experiment
到此为止,rebase工作才算完成。
请注意,rebase
和 merge
整合的最终结果所指向的快照始终是一样的,只不过提交历史不同罢了。 变基是将一系列提交按照原有次序依次应用到另一分支上,而合并是把最终结果合在一起。
GIT原理
底层命令和上层命令:
由于 Git 最初是一套面向版本控制系统的工具集,而不是一个完整的、用户友好的版本控制系统, 所以它还包含了一部分用于完成底层工作的子命令。 这些命令被设计成能以 UNIX 命令行的风格连接在一起,抑或由脚本调用,来完成工作。 这部分命令一般被称作“底层(plumbing)”命令,而那些更友好的命令则被称作“上层(porcelain)”命令。
git项目目录介绍
config // 项目特有的配置选项
description // GitWeb
HEAD // 目前被检出的分支
hooks/ // 户端或服务端的钩子脚本(
info/ // 全局性排除(global exclude)文件
objects/ // 存储所有数据内容
refs/ // 存储指向数据(分支、远程仓库和标签等)的提交对象的指针
index/ // 文件保存暂存区信息
GIT 存储
Git 是一个内容寻址文件系统,核心部分是一个简单的键值对数据库(key-value data store)。这意味着在Git 仓库中插入任意类型的内容,它会返回一个唯一的键(40 个字符,前两个字符用于命名子目录,余下的 38 个字符则用作文件名),通过该键可以在任意时刻再次取回该内容。
git数据对象
$ git init test
$ cd test
$ find .git/objects
// 写入内容
$ echo 'test content' | git hash-object -w --stdin // d670460b4b4aece5915caf5c68d12f560a9fe3e4
/*
git hash-object 会接受你传给它的东西,而它只会返回可以存储在 Git 仓库中的唯一键。
-w 选项会指示该命令不要只返回键,还要将该对象写入数据库中。
--stdin 选项则指示该命令从标准输入读取内容;
若不指定此选项,则须在命令尾部给出待存储文件的路径。
*/
$ find .git/objects -type f // .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4 // test content
// -p 指示该命令自动判断内容的类型
$ echo 'version 1' > test.txt
$ git hash-object -w test.txt // 83baae61804e65cc73a7201a7252750c76066a30
$ echo 'version 2' > test.txt
$ git hash-object -w test.txt // 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
$ find .git/objects -type f
/*
.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
*/
// 查看对象类型
$ git cat-file -t 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a // blob
git树对象
树对象解决了文件名保存的问题,也允许我们将多个文件组织到一起。 所有内容均以树对象和数据对象的形式存储。 一个树对象包含了一条或多条树对象记录(tree entry),每条记录含有一个指向数据对象或者子树对象的 SHA-1 指针,以及相应的模式、类型、文件名信息
$ git cat-file -p master^{tree}
/*
100644 blob a906cb2a4a904a152e80877d4088654daad0c859 README
100644 blob 8f94139338f9404f26296befa88755fc2598c289 Rakefile
040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 lib
*/
$ git cat-file -p 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0
//100644 blob 47c6340d6459e05787f644c2447d2595f5d3a54b simplegit.rb
创建树对象,例如
// 1.写入暂存区
$ git update-index --add --cacheinfo 100644 \
83baae61804e65cc73a7201a7252750c76066a30 test.txt
// -- add:不在缓存区内的(首次)文件添加
// --cacheinfo 添加的文件位于 Git 数据库中, 位于当前目录下
// 100644 表示普通文件,【指定文件模式】100755表示一个可执行文件;120000,表示一个符号链接(参考了常见的 UNIX 文件模式)
// 83baae61804e65cc73a7201a7252750c76066a30 SHA-1
// test.txt 文件名
// 2.创建树对象
$ git write-tree // 将暂存区内容写入一个树对象。返回d8329fc1cc938780ffdd9f94e0d364e0ea74f579
$ git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579
// 100644 blob 83baae61804e65cc73a7201a7252750c76066a30 test.txt
$ git cat-file -t d8329fc1cc938780ffdd9f94e0d364e0ea74f579 // tree
提交对象:记录保存的快照信息。
commit-tree
创建提交对象,例如:
$ echo 'first commit' | git commit-tree d8329f // fdf4fc3344e67ab068f836878b6c4951e3b15f3d
// 查看提交对象
$ git cat-file -p fdf4fc3
/*
tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579
author ***
committer ***
first commit
*/
GIT引用
如果你对仓库中从一个提交(比如 1a410e
)开始往前的历史感兴趣,那么可以运行 git log 1a410e
这样的命令来显示历史,不过你需要记得 1a410e
是你查看历史的起点提交。 如果我们有一个文件来保存 SHA-1 值,而该文件有一个简单的名字, 然后用这个名字指针来替代原始的 SHA-1 值的话会更加简单。
在 Git 中,这种简单的名字被称为“引用(references,或简写为 refs)”。 你可以在 .git/refs
目录下找到这类含有 SHA-1 值的文件。
一个用来保存SHA-A记录的文件夹。
$ find .git/refs
/*
.git/refs
.git/refs/heads
.git/refs/tags
*/
// 创建一个新引用来帮助记忆最新提交所在的位置,
$ echo 1a410efbd13591db07496601ebc7a059dd55cfe9 > .git/refs/heads/master
// 此时,你就可以在 Git 命令中使用这个刚创建的新引用来代替 SHA-1 值了:
$ git log --pretty=oneline master
/*
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
*/
// 更新某个引用
$ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9
HEAD 引用
当你执行 git branch
时,Git 如何知道最新提交的 SHA-1 值呢? 答案是 HEAD 文件。
HEAD 文件通常是一个符号引用(symbolic reference)(指向其他引用的指针),指向目前所在的分支。
$ cat .git/HEAD // ref: refs/heads/master
当我们执行 git commit
时,该命令会创建一个提交对象,并用 HEAD 文件中那个引用所指向的 SHA-1 值设置其父提交字段。
维护与数据恢复
维护
Git 会不定时地自动运行一个叫做 “auto gc” 的命令。 大多数时候,这个命令并不会产生效果。 然而,如果有太多松散对象(不在包文件中的对象)或者太多包文件,Git 会运行一个完整的 git gc
命令。 “gc” 代表垃圾回收,这个命令会做以下事情:收集所有松散对象并将它们放置到包文件中, 将多个包文件合并为一个大的包文件,移除与任何提交都不相关的陈旧对象。
或者手动回收:git gc --auto
该命令通常并不会产生效果。 大约需要 7000 个以上的松散对象或超过 50 个的包文件才能让 Git 启动一次真正的 gc 命令。
gc
将会做的另一件事是打包你的引用到一个单独的文件。 假设你的仓库包含以下分支与标签:
$ find .git/refs -type f
.git/refs/heads/experiment
.git/refs/heads/master
.git/refs/tags/v1.0
.git/refs/tags/v1.1
如果你执行了 git gc
命令,refs
目录中将不会再有这些文件。 为了保证效率 Git 会将它们移动到名为 .git/packed-refs
的文件中,就像这样:
$ cat .git/packed-refs
# pack-refs with: peeled fully-peeled
cac0cab538b970a37ea1e769cbbde608743bc96d refs/heads/experiment
ab1afef80fac8e34258ff41fc1b867c702daa24b refs/heads/master
cac0cab538b970a37ea1e769cbbde608743bc96d refs/tags/v1.0
9585191f37f7b0fb9444f35a9bf50de191beadc2 refs/tags/v1.1
^1a410efbd13591db07496601ebc7a059dd55cfe9
如果你更新了引用,Git 并不会修改这个文件,而是向 refs/heads
创建一个新的文件。 为了获得指定引用的正确 SHA-1 值,Git 会首先在 refs
目录中查找指定的引用,然后再到 packed-refs
文件中查找。 所以,如果你在 refs
目录中找不到一个引用,那么它或许在 packed-refs
文件中。
注意这个文件的最后一行,它会以 ^
开头。 这个符号表示它上一行的标签是附注标签,^
所在的那一行是附注标签指向的那个提交。
数据恢复
举个例子将硬重置你的测试仓库中的 master
分支到一个旧的提交,以此来恢复丢失的提交。
$ git log --pretty=oneline
/*
ab1afef80fac8e34258ff41fc1b867c702daa24b modified repo a bit
484a59275031909e19aadb7c92262719cfcdf19a added repo.rb
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
*/
现在,我们将 master
分支硬重置到第三次提交:
$ git reset --hard 1a410efbd13591db07496601ebc7a059dd55cfe9
/*
HEAD is now at 1a410ef third commit
$ git log --pretty=oneline
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
*/
现在 怎么处理?
1、最常用的方法:git reflog
当你正在工作时,Git 会默默地记录每一次你改变 HEAD 时它的值。 每一次你提交或改变分支,引用日志都会被更新。 引用日志(reflog)也可以通过 git update-ref
命令更新,我们在 Git 引用 有提到使用这个命令而不是是直接将 SHA-1 的值写入引用文件中的原因。 你可以在任何时候通过执行 git reflog
命令来了解你曾经做过什么:
$ git reflog
1a410ef HEAD@{0}: reset: moving to 1a410ef
ab1afef HEAD@{1}: commit: modified repo.rb a bit
484a592 HEAD@{2}: commit: added repo.rb
找到丢失的那个id,然后从该id新建一个分支:
git branch recover-branch ab1afef
2、当丢失的分支在reflog日志里也找不到时,使用 git fsck
实用工具,将会检查数据库的完整性。如果使用一个 --full
选项运行它,它会向你显示出所有没有被其他对象指向的对象:
$ git fsck --full
Checking object directories: 100% (256/256), done.
Checking objects: 100% (18/18), done.
dangling blob d670460b4b4aece5915caf5c68d12f560a9fe3e4
dangling commit ab1afef80fac8e34258ff41fc1b867c702daa24b
dangling tree aea790b9a58f6cf6f2804eeac9f0abbe9631e4c9
dangling blob 7108f7ecb345ee9d0084193f147cdad4d2998293
在这个例子中,你可以在 “dangling commit” 后看到你丢失的提交。 现在你可以用和之前相同的方法恢复这个提交,也就是添加一个指向这个提交的分支。