文章目录
- [1. Git 跟踪并管理的是修改的内容,而非文件本身](#1. Git 跟踪并管理的是修改的内容,而非文件本身)
-
- [git status 命令](#git status 命令)
- [git diff 命令](#git diff 命令)
- [2. 版本回退](#2. 版本回退)
-
- [2.1 git reset](#2.1 git reset)
- [2.2 git reflog (后悔药)](#2.2 git reflog (后悔药))
- [2.3 版本回退的底层原理](#2.3 版本回退的底层原理)
- [3. 撤销修改](#3. 撤销修改)
-
- [3.1 工作区修改,还未add](#3.1 工作区修改,还未add)
- [git checkout](#git checkout)
- [3.2 已经add,还没commit](#3.2 已经add,还没commit)
- [3.3 已经add和commit](#3.3 已经add和commit)
- [4. 删除文件](#4. 删除文件)
1. Git 跟踪并管理的是修改的内容,而非文件本身
Git 跟踪并管理的是修改的内容,而非文件本身,这是 Git 区别于 SVN 等其他版本控制系统的根本:
之前我们上传了一个readme文件,即它已经被提交到版本库了,现在我们来修改一下它
可以git log查看一下提交日志
那现在我们来修改一下readme文件
随便新增两行内容
修改完毕,保存退出
git status 命令
然后我们再来介绍一个命令------git status
通过上一篇文章的学习,我们知道了 Git 有工作区、暂存区和版本库。但在日常写代码时,我们不可能每次都去 .git 目录里扒底层文件。
git status命令的作用就是:随时查看当前工作区和暂存区的状态,告诉你哪些文件被修改了、哪些准备提交、哪些还没被 Git 管理。
那刚才我们修改了readme文件,现在我们来使用git status命令查看一下
看一下它都展示了什么信息
git diff 命令
下面再介绍一个命令------git diff
用 git status 知道了"哪些文件被修改了",但 git status 不会告诉你具体改了什么。
而 git diff可以用来查看工作区(你刚改的代码)和暂存区(上次 git add 进去的代码)的内容差异。
直接敲 git diff,对比的是当前工作区所有被修改的文件和暂存区。
如果你改了三四个文件,但只想看其中某一个文件的差异,就可以把文件名跟在后面:git diff Readme
我们这里只改了一个,加不加无所谓
所以:
只要工作区的文件内容发生了改变,我们就需要重新执行 git add 和 git commit,才能把新版本记录到 Git 版本库中。
这就是 Git 最经典的开发循环:修改 -> 暂存(add) -> 提交(commit)。
2. 版本回退
我们知道git是一个版本控制器,那么其中版本回退是一个非常重要的功能,这使得git能够管理文件的历史版本,并可以回退到某一个指定版本
如果有一天你发现之前的工作做的出现了很大的问题,需要在某个特定的历史版本重新开始,这个时候,就需要版本回退的功能了
比如还来看我们之前举的这个例子
假如现在你把最后这个版本提交上去,但是老师说我觉得你这个版本的报告还没有第一版符合我的预期,你还是把第一版交上来吧!
那由于我们这里对所有的历史版本进行了管理,所以就可以很方便地找到第一版报告。
2.1 git reset
git当然也可以完成这个功能,那么git如何实现版本回退呢?------使用git reset命令来完成
要注意的是:
"回退"的本质,是将版本库中的状态(分支指针)进行回退,而工作区或暂存区是否跟着回退,完全由你添加的命令参数决定。
我们通过一个具体的案例来介绍这个命令:
之前我们提交过两个文件,并且readme文件进行了修改,修改后重新进行了add和commit。
现在Readme文件有这样三行内容,但是不要忘记了
第一次的提交readme文件中只有一行,后面两行是我们后面修改新增的。
所以对于这个readme文件来说,它是有两个版本的
"回退"的本质,是将版本库中的状态(分支指针)进行回退,而工作区或暂存区是否跟着回退,完全由你添加的命令参数决定。
当前现在这三个里面的readme肯定都是最新的这个版本。
使用git reset进行回退,后面通常跟这三个选项,对应三种情况
第一个:git reset --soft <commit_id>只回退版本库,工作区和暂存区不变
第二个:git reset --mixed <commit_id>(默认选项,git reset 的默认模式 )------将暂存区的内容退回为指定提交版本,工作区文件保持不变。
第三个:git reset --hard <commit_id>------将暂存区与工作区都退回到指定版本。
切记工作区有未提交的代码时不要用这个命令,因为工作区会回滚,你没有提交的代码就再也找不回了,所以使用该参数前一定要慎重。
然后我们来实操一下,用用这个命令,这里重点演示一下hard
首先通过 git log命令是可以查看到每次提交的信息以及对应的cimmit id(上面命令的最后一个参数即填要回退版本的commit id)
比如现在我们发现readme文件修改错了,想要回退到第一次提交后的这个版本,即readme中只有第一行内容,并想让工作区的内容也回退到这
git reset --hard 80a6a4d8dd4b10f7c8b9cb6db5ae839e5aeb7b42
那现在就回退成功了
此时我们发现,现在这个目录下就只有readme这一个文件了,并且readme里面的内容也只有最初的第一行了(因为工作区也回退了),git log也只打印了第一次的提交了!
到这里一般回退功能就演示完了,但现在如果我后悔了,想再回到修改readme文件的那个版本怎么办?
我们可以继续使用 git reset 命令,回退到这个版本,但我们必须要拿到这个版本对应的 commit id。
但是此时git log已经看不到这个版本的提交记录和commit id了!
好在终端之前的历史记录还保留了
现在就成功回到这个版本了
但是,在实际开发中,由于长时间的开发或者你中间关闭了服务器,commit id 可能无法在历史终端记录找到了,这时候还能回退吗?
2.2 git reflog (后悔药)
git log 是"正统历史":
它展示的是 Commit 链表(顺着 parent 指针走),如果你用 reset 退回了旧版本,那些被抛弃的提交在 git log 里就看不见了。
git reflog 是"操作流水账":
不管你是提交、回退、切换分支、重置版本还是合并,只要指针动了,它就会在你的本地留底。哪怕这些提交在 git log 里已经"消失"了,reflog 依然记得它们。
所以回到上面那个问题:
我们看到这里面,commit reset都被记录下来了,所以这样就可以找到修改readme文件的那个版本的commit id,但我们看到这个commit id怎么变得这么短了?
没关系,依然能用
🆗,这就回退成功了。
2.3 版本回退的底层原理
上面的操作中我们能感受到git版本回退的速度是非常快的,那它是怎么做到的呢?
通过上一篇文章的学习,我们知道Git 内部有个指向当前分支(此处是master)的 HEAD 指针,它里面存着 ref: refs/heads/master, refs/heads/master 文件里存的其实就是当前master分支里最新的一个 commit id。
(比如现在version3的提交是最新的)
当我们在回退版本的时候,Git 仅仅是给 refs/heads/master 中存储的commit id修改为要回退版本的commit id即可。
可以任务,版本回退的本质,其实就是移动指针。这自然是非常快的!
3. 撤销修改
如果我们在工作区写了很长时间的代码,发现写的实在垃圾,想恢复到原状怎么办?
这里介绍三种情况:
3.1 工作区修改,还未add

我们来看一个例子:
现在readme文件的内容是这样的,并且之前这个文件的修改我们也更新到了暂存区和版本库了
现在我们再来在工作区修改这个文件
那现在我想撤销这个修改怎么办:
直接再次编辑这个文件,然后把刚才新增那一行删掉不就行了。
这当然也没啥问题。
但如果你已经进行了很长时间的开发了,新增了很多代码在很多个地方,并且可能在很多地方进行了修改。
你可能已经忘了自己在哪些地方进行了修改了,这时候这种方法其实就不太可靠了。
git checkout
Git 其实还为我们提供了更好的方式,我们可以使用 git checkout -- file 命令让工作区的文件回到最近一次 add 或 commit 时的状态。
要注意 git checkout -- file 命令中的 -- 很重要,切记不要省略。
演示一下:
git checkout -- Readme
就成功撤销掉上次的修改了。
3.2 已经add,还没commit
工作区进行了修改,而且已经进行了add,这种情况如何撤销呢?
演示一下:
准备工作,再次修改readme,并add更新到暂存区
那现在我们想恢复到修改之前,可以怎么做呢?
回忆一下上面讲过的git reset命令
现在的情况是什么
工作区进行了修改,并且已经add,所以现在工作区和暂存区都已经发生了变化,但版本库还保留的是上一个版本的状态。
那我们这个场景可以来使用git reset嘛?
当然也是可以的,我们上面讲的用法都是使用git reset回退到历史版本,其实也可以回退到当前版本 。
怎么理解?
当前我们的版本库中是没有更新readme的这次修改的,所以当前版本库的这个版本就是没有发生修改的版本,那不这次readme文件修改之前的版本嘛。
所以我们可以回退到当前版本,那应该用哪个选项呢?
是不是可以用hard,重置工作区和暂存区到当前版本(即readme修改之前的那个版本)
这样工作区和暂存区就和当前版本库的版本一样了,那之前的修改不就被撤销了嘛。
我们来试一下,同时给大家补充一个小知识点:
我们上面介绍的gitreset 后面是跟commit id表示对应的某个版本,也可以这样:
HEAD 表示当前版本
HEAD^ 上一个版本
HEAD^^ 上上一个版本
以此类推...
还可以使用 〜数字表示:
HEAD~0 表示当前版本
HEAD~1 上一个版本
HEAD~2 表示上上一个版本
试一下:
git reset --hard HEAD
就成功撤销修改了。
那其实还有第二种方法:
我们也可以使用mixed选项,这样只把暂存区恢复到当前版本,变成这样
那这样不就变成我们讲的情况一了嘛!(这种方法大家自行尝试,不再演示)
3.3 已经add和commit
那其实就是我们第二小节(2. 版本回退)介绍的内容了嘛,依然使用git reset命令来处理:
我们后面会讲到远程版本库,一旦你推送到远程版本库(git push),本地回退的话(你的本地环境确实退回去了),但无法直接同步到远程(直接 push 会被拒绝)。
4. 删除文件
来看一个例子:
当前我们的工作区有这两个文件,并且已经提交到版本库进行管理了。
那如果现在我想删掉text.txt文件,要怎么做呢?
两种方法:
法一:
直接rm删除可以吗
这样只是在工作区进行了删除,暂存区和版本库并没有同步。
之前提到过,对工作区的修改(这里的"修改"包括:新增,修改,删除),要重新进行add和commit,才能同步到版本库。
所以:
这样就可以了。
法二:
再来介绍一个命令:
git rm 文件名
Git 会把这个文件从你的电脑(工作区)里删掉,同时把"删除这个文件"的动作更新至暂存区
所以后面只需commit一次就可以从版本库中删除这个文件了
















































