文章目录
- 学习目标
- Ⅰ. 初始 Git
- 💥注意事项
- Ⅱ. Git 安装
- Linux-centos安装Git
- Ⅲ. Git基本操作
- 一、创建git本地仓库 -- git init
- 二、配置 Git -- git config
- 三、认识工作区、暂存区、版本库
- ① 工作区
- ② 暂存区
- ③ 版本库
- ④ 三者的关系
- 四、添加、提交更改、查看提交日志命令
- ① 场景一
- 查看 .git 文件变化
- ② 场景二
- 五、修改文件
- ① 查看工作目录和暂存区的状态 -- git status
- ② 查看暂存区和工作区等之间的更改内容 -- git diff
- 六、版本回退 -- git reset && git reflog
- ① --mixed选项
- 如何撤销版本回退❓❓❓
- ② --hard选项
- 💥各版本回退选项的总结
- 为什么版本回退以及撤销的时候,速度那么快❓❓❓
- 七、撤销修改 -- git checkout -- [filena]
- 情况一:工作区的代码还未add
- 情况二:代码已经 add,但还未 commit
- 情况三:代码已经 add 和 commit
- 8、删除文件 -- git rm
学习目标
- 掌握
Git
企业级应用,深刻理解Git
操作过程与操作原理,理解工作区,暂存区,版本库的含义 - 掌握
Git
版本管理,自由进行版本回退、撤销、修改等Git
操作方式与背后操作原理 - 掌握
Git
分支管理,从分支创建,切换,合并,删除的整个生命周期,灵活进行各种场景下的分支管理,学习常见分支管理策略 - 掌握
Git
远程仓库与本地仓库,结合版本管理与分支管理,做到基于分支级的个人级开发 - 理解分布式版本控制系统,学习远程仓库与本地仓库的交互操作,掌握多人协作开发模式
- 学习企业级常见分支策略(
master
/release
/develop
/feature
/hotfix
等),理解不同公司,不同环境下适合的分支模型。结合案例,引入工程程师,测试人员,技术经理等角色,展现项目开发过程的全貌,深刻理解开发的整体流程,俯视Git
在其中的作用
另外还要明白,我们 平时使用的 gitee
、github
等平台,其实只是基于 git
的托管平台,相当于远程仓库,要分清楚!
Ⅰ. 初始 Git
不知道你工作或学习时,有没有遇到这样的情况:我们在编写各种文档时,为了防止文档丢失,更改失误,失误后能恢复到原来的版本,不得不复制出一个副本,比如:
“报告-v1”
“报告-v2”
“报告-v3”
“报告-确定版”
“报告-最终版”
“报告-究极进化版”
...
每个版本有各自的内容,但最终会只有一份报告需要被我们使用。
但在此之前的工作都需要这些不同版本的报告,于是每次都是复制粘贴副本,产出的文件就越来越多,文件多不是问题,问题是:随着版本数量的不断增多,你还记得这些版本各自都是修改了什么吗?
文档如此,我们写的项目代码,也是存在相同的问题!!
此时就引入了 版本控制器 的概念!
为了能够更方便我们管理这些不同版本的文件,便有了版本控制器。所谓的版本控制器,就是能让你了解到一个文件的历史,以及它的发展过程的系统。通俗的讲就是一个可以记录工程的每一次改动和版本迭代的一个管理系统,同时也方便多人协同作业。
目前最主流的版本控制器就是 Git
。Git
可以控制电脑上所有格式的文件,例如 doc
、excel
、dwg
、dgn
、rvt
等等。对于我们开发人员来说,Git
最重要的就是可以帮助我们管理软件开发项目中的源代码文件!
💥注意事项
还需要再明确一点,所有的版本控制系统,Git
也不例外,其实只能跟踪 文本文件
的改动,比如 TXT
文件,网页,所有的程序代码等等。版本控制系统可以告诉你每次的改动,比如在第 5
行加了一个单词 “Linux”
,在第 8
行删了一个单词 “Windows”
。
而 图片、视频这些二进制文件,虽然也能由版本控制系统管理,但 没法跟踪二进制文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从 100KB
改成了 120KB
,但到底改了啥,版本控制系统不知道,也没法知道。
Ⅱ. Git 安装
Git
是开放源代码的代码托管工具,最早是在 Linux
下开发的。开始也只能应用于 Linux
平台,后面慢慢的被移植到 windows
下,现在,Git
可以在 Linux
、Unix
、Mac
和 Windows
这几大平台上正常允许了。
这里就不细讲安装了,比较简单,可以上网查!
Linux-centos安装Git
安装比较简单,首先,你可以试着输入 git
,看看系统有没有安装 git
:
[liren@VM-8-7-centos ~]$ git --version
git version 1.8.3.1
如果没有出现上述内容,说明没有安装,使用 yum
指令安装:
sudo yum -y install git
其它操作系统安装也是类似的,自行查阅资料!
Ⅲ. Git基本操作
Git
的工作就是创建和保存你项目的快照及与之后的快照进行对比。对于下述出现的常见指令以及其它指令,都会在后面介绍到!
Git基本操作
图示说明:
workspace
:工作区staging area
:暂存区/缓存区local repository
:版本库或本地仓库remote repository
:远程仓库
一、创建git本地仓库 – git init
要提前说的是,仓库的本质是进行版本控制的一个文件目录。我们要想对文件进行版本控制,就必须先创建一个仓库出来,然后在这个仓库中对我们要追踪管理的文件进行管理!
💥 注意,这里说的 本地仓库
和我们后面讲的 版本库
是不一样的!
创建一个 Git
本地仓库对应的命令为 git init
,注意命令要在文件目录下执行,例如:
[liren@VM-8-7-centos gitcode]$ pwd
/home/liren/gitcode
[liren@VM-8-7-centos gitcode]$ git init
Initialized empty Git repository in /home/liren/gitcode/.git/
[liren@VM-8-7-centos gitcode]$ ls -al
total 12
drwxrwxr-x 3 liren liren 4096 Jul 9 21:38 .
drwx------ 15 liren liren 4096 Jul 9 21:38 ..
drwxrwxr-x 7 liren liren 4096 Jul 9 21:38 .git
[liren@VM-8-7-centos gitcode]$
我们发现,当前目录下多了⼀个 .git
的隐藏文件, .git
目录是 Git
来跟踪管理仓库的,不要手动修改这个目录里面的文件,不然改乱了,就把 Git
仓库给破坏了。
其中包含 Git
仓库的诸多细节,随着我们学习的深入,后面会挑重点来讲!
[liren@VM-8-7-centos gitcode]$ tree .git
.git
|-- branches
|-- config
|-- description
|-- HEAD
|-- hooks
| |-- applypatch-msg.sample
| |-- commit-msg.sample
| |-- post-update.sample
| |-- pre-applypatch.sample
| |-- pre-commit.sample
| |-- prepare-commit-msg.sample
| |-- pre-push.sample
| |-- pre-rebase.sample
| `-- update.sample
|-- info
| `-- exclude
|-- objects
| |-- info
| `-- pack
`-- refs
|-- heads
`-- tags
9 directories, 13 files
[liren@VM-8-7-centos gitcode]$
二、配置 Git – git config
当安装 Git
后首先要做的事情是设置你的 用户名称 和 邮箱地址,这是非常重要的,它相当于是我们操作 Git
的账号和密码那般重要。
添加配置命令 为:
git config [--global] user.name "Your Name" # 把 Your Name 改成你的昵称
git config [--global] user.email "email@example.com" # 把 email@example.com 改成邮箱的格式,只要格式正确即可
其中 --global
是一个可选项。如果使用了该选项,表示这台机器上所有的 Git
仓库都会使用这个配置。如果你希望在不同仓库中使用不同的 名称 或 邮箱,可以不要 --global
选项,但要注意的是,执行命令时必须要在仓库里。
查看配置命令 为:
git config -l
下面我们举个例子,给当前的仓库添加名称和邮箱:
[liren@VM-8-7-centos gitcode]$ git config -l # 查看配置
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
[liren@VM-8-7-centos gitcode]$ git config --global user.name "sharp-blade"
[liren@VM-8-7-centos gitcode]$ git config --global user.email "2916776007@qq.com"
[liren@VM-8-7-centos gitcode]$ git config -l # 查看配置,多了两个配置
user.name=sharp-blade
user.email=2916776007@qq.com
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
[liren@VM-8-7-centos gitcode]$
那我们要是想 删除对应的配置 的话,则要用以下配置指令:
git config [--global] --unset user.name
git config [--global] --unset user.email
💥注意,如果 对应的配置使用了 --global
选项,然后要删除的话,也要加上 --global
选项才能删除!
三、认识工作区、暂存区、版本库
我们先来理解下 Git
中 工作区、暂存区 和 版本库 概念:
① 工作区
工作区就是当前 Git
仓库所在的目录。
在工作区中,我们可以进行代码的修改、添加、删除等操作,并且可以在工作区中直接进行提交。提交操作 add
会将工作区中的更改内容同步到暂存区中,并将它们标记为已暂存状态。在提交时,Git
会将暂存区中的内容提交到远程仓库中,并创建一个新的提交对象。
需要注意的是,工作区和暂存区都是相对于当前分支的,因此 只有在当前分支中进行的操作才会影响它们。当切换到其他分支时,工作区和暂存区也会随之改变。
举个例子,我们和上面创建仓库的位置一样,在 /home/liren/gitcode/
目录就是我们的仓库,此时里面的文件如下所示:
② 暂存区
暂存区实际上是一个位于工作区与版本库之间的临时区域,是一个 二进制文件,包含所有在工作区中修改的文件,叫做 stage
或 index
。其 一般存放在 .git
目录下的 index
文件(.git/index
)中,所以我们把暂存区有时也叫作索引(index
)。
暂存区是位于版本库之上的一个特殊分支,用于临时存储和管理代码更改。当使用 git add
命令将文件添加到暂存区时,Git
会根据这些修改生成新的提交对象,并将它们与版本库中的提交对象关联起来。并且可以使用 git commit
命令提交更改到对应版本分支下面!
💥需要注意的是,暂存区是一个独立、临时的区域,它只存在于当前分支中。当你切换到其他分支时,暂存区也将随之改变。此外,当你的分支合并到主分支时,暂存区也会受到影响。
举个例子,我们用 tree
指令看一下还没有使用 git add
之前的版本库 .git
中对应暂存区 index
文件的位置:
另外我们也可以看到,工作区的内容也是不会显示在版本库中的,说明它们是相互独立的!
下面我们使用 git add
指令,将工作区的内容提交到暂存区中,再看看效果:
后面我们再来讲这个 objects
目录是个什么鬼!
③ 版本库
版本库(Repository
) 是一个位于工作区之外的目录,其中包含所有 Git
存储的数据,如提交对象、分支、标签等。
在工作区中有一个 隐藏目录 .git
,它不算是工作区,而是 Git
的版本库。这个版本库里面的所有文件都可以被 Git
管理起来,每个文件的修改、删除操作,Git
都能跟踪到,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
还是提醒一下,切记不要在 .git
目录下手动修改文件,不然很容易导致仓库不能用了!
下面我们使用 git commit -m
指令,将暂存区中的文件,提交到默认的主分支 master
中:
④ 三者的关系
下面这个图展示了工作区、版本库中的暂存区和版本库之间的关系:
- 图中左侧为工作区,右侧为版本库。在版本库中标记为
index
的区域是 暂存区(stage
/index
),标记为master
的是master
分支 所代表的目录树。 HEAD
实际是指向master
分支的一个"游标"。所以图示的命令中出现HEAD
的地方可以用master
来替换。- 图中的
objects
标识的区域为Git
的对象库,实际位于.git/objects
目录下,里面包含了创建的各种对象及内容。
- 在创建
Git
版本库时,Git
会为我们自动创建一个唯一的master
分支,以及指向master
的一个指针叫HEAD
。(分支和HEAD
的概念后面再说) - 当对工作区修改(或新增)的文件 执行
git add
命令时,暂存区目录树的文件索引index
会被更新。 - 当执行提交操作
git commit
时,master
分支会做相应的更新,可以简单理解为暂存区的目录树才会被真正写到版本库中。
由上述描述我们便能得知:通过新建或粘贴进目录的文件,并不能称之为向仓库中新增文件,而只是在工作区新增了文件,其实质上并没有进入到仓库中被管理。所以 必须要通过使用 git add
和 git commit
命令才能将文件添加到仓库中进行管理!!!
四、添加、提交更改、查看提交日志命令
- 添加
- 添加一个或多个文件到暂存区:
git add [file1] [file2] ...
- 添加指定目录到暂存区,包括子目录:
git add [dir]
- 添加当前目录下的所有文件到暂存区:
git add .
- 添加一个或多个文件到暂存区:
- 提交更改
- 将当前工作目录中的所有更改提交到暂存区中:
git commit -a
- 将当前工作目录中的更改提交到暂存区中,并添加一个提交消息:
git commit -m "commit message"
- 将指定文件中的更改提交到暂存区中,并添加一个提交消息:
git commit -m "commit message" filename
- 将当前工作目录中的更改提交到暂存区中,并添加一个提交消息,同时将提交记录添加到本地分支中:
git commit -m "commit message" -a -s
- 将当前工作目录中的所有更改提交到暂存区中:
- 查看提交日志
- 查看最近一次提交到最近的提交之间的所有提交记录:
git log
- 查看当前分支和远程仓库的
master
分支之间的所有提交记录:git log master..origin/master
- 查看
master
分支上的所有提交记录的详细差异:git log -p master
- 查看最近的
n
次提交记录:git log -n
- 查看所有分支的提交记录:
git log --all
- 除此之外,还可以通过设置其它不同的选项来查看不同的提交记录,例如:
git log --author=username
:查看指定作者的提交记录。git log --grep="pattern"
:查看包含指定模式的提交记录。git log --pretty=oneline
:用于将提交记录以一行的形式输出,这对于在某些情况下快速查看提交记录非常有用。git log --graph --abbrev-commit
:这两个选项一般用于查看提交日志时候用时间线的形式显示不同分支的提交情况,看起来很直观!- ……
- 查看最近一次提交到最近的提交之间的所有提交记录:
下面我们分为两个场景来使用这三个指令!
① 场景一
在包含 .git
的目录下新建一个 readme
文件,使用 git add
命令可以将文件添加到暂存区,再使用 git commit
命令将暂存区内容提交到本地仓库也就是版本库。
💥注意,git commit
后面的 -m
选项,要跟上描述本次提交的 message
,由用户自己完成,这部分内容绝对不能省略,并要好好描述,是用来记录你的提交细节,是给我们人看的。
[liren@VM-8-7-centos gitcode]$ ls -al
total 12
drwxrwxr-x 3 liren liren 4096 Jul 10 11:08 .
drwx------ 15 liren liren 4096 Jul 10 11:13 ..
drwxrwxr-x 7 liren liren 4096 Jul 10 11:08 .git
[liren@VM-8-7-centos gitcode]$ touch readme
[liren@VM-8-7-centos gitcode]$ git add readme
[liren@VM-8-7-centos gitcode]$ git commit -m 'first add file:readme'
[master (root-commit) cdc96e6] first add file:readme
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 readme
[liren@VM-8-7-centos gitcode]$
git commit
命令执行成功后会告诉我们,有一个文件被改动(就是我们新添加的 readme
文件),插入了零行内容(说明 readme
没有插入新内容)。
我们还可以多次 add
不同的文件,而只 commit
一次便可以提交所有文件,是因为需要提交的文件是通通被 add
到暂存区中,然后一次性 commit
暂存区的所有修改。如下所示:
[liren@VM-8-7-centos gitcode]$ touch file1 file2 file3
[liren@VM-8-7-centos gitcode]$ git add file1 # 添加一个文件
[liren@VM-8-7-centos gitcode]$ git add file2 file3 # 添加多个文件
[liren@VM-8-7-centos gitcode]$ git commit -m 'add 3 files'
[master 7eb10f5] add 3 files
3 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file1
create mode 100644 file2
create mode 100644 file3
[liren@VM-8-7-centos gitcode]$
截至目前为止,我们已经更够将代码直接提交至本地仓库了。我们可以使用 git log
命令,来查看下历史提交记录:
[liren@VM-8-7-centos gitcode]$ git log
commit 7eb10f50de9781d05a4a4af2134a8673352e89fa
Author: lirendada <2916776007@qq.com>
Date: Mon Jul 10 13:05:02 2023 +0800
add 3 files
commit cdc96e6d432ea74b61b4bf36de4dc19f07310eb0
Author: lirendada <2916776007@qq.com>
Date: Mon Jul 10 11:50:00 2023 +0800
first add file:readme
[liren@VM-8-7-centos gitcode]$
该命令显示从最近到最远的提交日志,并且可以看到我们 commit
时的日志消息。如果嫌输出信息太多,看得眼花缭乱的,可以试试加上 --pretty=oneline
参数:
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$
需要说明的是,我们看到的一大串类似 7eb10……2e89fa
的是每次提交的 commit id
(版本号),Git
的 commit id
不是 1,2,3……
递增的数字,而是一个 SHA1
计算出来的一个非常大的数字,用十六进制表示(当然你看到的 commit id
和我的肯定不一样,以你自己的为准)
查看 .git 文件变化
首先来看一下 .git
的目录结构,其实我们前面已经看过了
[liren@VM-8-7-centos gitcode]$ tree .git
.git
|-- branches
|-- COMMIT_EDITMSG
|-- config
|-- description
|-- HEAD
|-- hooks
| |-- applypatch-msg.sample
| |-- commit-msg.sample
| |-- post-update.sample
| |-- pre-applypatch.sample
| |-- pre-commit.sample
| |-- prepare-commit-msg.sample
| |-- pre-push.sample
| |-- pre-rebase.sample
| `-- update.sample
|-- index
|-- info
| `-- exclude
|-- logs
| |-- HEAD
| `-- refs
| `-- heads
| `-- master
|-- objects
| |-- 27
| | `-- 1d813417b08f049274d2dfda5211ec2ea2ec95
| |-- 7e
| | `-- b10f50de9781d05a4a4af2134a8673352e89fa
| |-- cd
| | `-- c96e6d432ea74b61b4bf36de4dc19f07310eb0
| |-- e6
| | `-- 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
| |-- e8
| | `-- 0ad49ace82167de62e498622d70377d913c79e
| |-- info
| `-- pack
`-- refs
|-- heads
| `-- master
`-- tags
17 directories, 23 files
下面我们来介绍其中几个重要的:
-
index
就是暂存区,我们add
之后的内容都是添加到这里的 -
HEAD
是默认指向当前分支也就是master
分支最后一次提交内容的指针:[liren@VM-8-7-centos gitcode]$ cat .git/HEAD ref: refs/heads/master
而此时的
master
分支,其实就是:[liren@VM-8-7-centos gitcode]$ cat .git/refs/heads/master 7eb10f50de9781d05a4a4af2134a8673352e89fa
这串内容就是 当前分支最新的
commit id
,这可以在上面的objects
对象文件中找到,其中7e
是目录名,相当于是房间号;而后面的那串就是更具体的提交内容文件! -
objects
为Git
的对象库,里面包含了创建的各种版本库对象及内容。当执行git add
命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,就位于.git/objects
目录下,让我们来看看这些对象有何用处:[liren@VM-8-7-centos gitcode]$ ls .git/objects/ 27 7e cd e6 e8 info pack
查找
object
时要将commit id
分成两部分,其 前两位是文件夹名称,后38
位是文件名称。找到这个文件之后,一般不能直接看到里面是什么,因为该类文件是经过sha
(安全哈希算法)加密过的文件! 好在我们可以使用
git cat-file
命令来查看版本库对象的内容:[liren@VM-8-7-centos gitcode]$ git cat-file -p 7eb10f50de9781d05a4a4af2134a8673352e89fa #-p选项表示美观的打印出来 tree 271d813417b08f049274d2dfda5211ec2ea2ec95 parent cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 author lirendada <2916776007@qq.com> 1688965502 +0800 committer lirendada <2916776007@qq.com> 1688965502 +0800 add 3 files [liren@VM-8-7-centos gitcode]$
我们一探究竟,顺便将它的父亲节点还有根节点都看看到底存放着什么:
总结一下,在本地的 git
仓库中,有几个文件或者目录很特殊:
- index:就是暂存区,
git add
后会更新该内容 - HEAD:默认指向
master
分⽀的⼀个指针 - refs/heads/master:文件里保存当前
master
分支的 最新commit id
- objects:包含了创建的各种版本库对象及内容,可以简单理解为放了
git
维护的所有修改内容
后面在学习过程中,最好能将常见的 git
操作与 .git
目录当中的结构内容变化对应起来,这样有利于我们理解 git
细节流程!
② 场景二
学习到这里,我们已经清楚了如何向仓库中添加文件,并且对于工作区、暂存区、版本库也有了一定的认识。那么我们再展示一种添加文件的场景,能加深对工作区、暂存区、版本库的理解,实例如下:
[liren@VM-8-7-centos gitcode]$ touch file4 #新增file4
[liren@VM-8-7-centos gitcode]$ touch file5 #新增file5
[liren@VM-8-7-centos gitcode]$ git add file4 #添加file4到暂存区
[liren@VM-8-7-centos gitcode]$ git commit -m 'add file4' #提交更改
[master ced585b] add file4
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file4
[liren@VM-8-7-centos gitcode]$
提交后发现打印了 1 file changed, 0 insertions(+), 0 deletions(-)
,意思是只有一个文件改变了,这时我们提出了疑问,不是新增了两个文件吗?
其实学了上面的内容之后,这里就不难理解了,git add
是将工作区文件添加到暂存区, git commit
是将暂存区的内容添加到本地仓库中。由于我们并没有使用 git add file5
,此时 file5
就不在暂存区中维护,所以我们 commit
的时候其实只是把已经在暂存区的 file4
提交了,而遗漏了工作区的 file5
。
那如何提交 file5
呢?很简单,再次 add
然后 commit file5
即可,这里就不演示了!
五、修改文件
这里要强调一下,git
追踪的其实是修改的内容,而不是整个文件!也就是说 git
不会每次都为整个文件创建 object
对象,而是只对其中修改的内容进行创建对象管理,这样子一来就能节省很大部分的空间,这也就是为什么 Git
比其它版本控制器优秀的地方!
什么是修改,比如你新增了一行,这就是一个修改,删除了一行,也是一个修改,更改了某些字符,也是一个修改,删了一些又加了一些,也是一个修改,甚至创建一个新文件,也算一个修改。
① 查看工作目录和暂存区的状态 – git status
下面我们做一些操作:向之前的 readme
文件里面增添数据,不进行 add
操作;向之前的 file5
文件中增添数据,并且进行 add
操作,但不进行 commit
操作;创建一个新文件 file6
,也向里面增添数据,不进行 add
操作:
[liren@VM-8-7-centos gitcode]$ echo 'lirendada' > readme
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
[liren@VM-8-7-centos gitcode]$ echo 'liren' > file5
[liren@VM-8-7-centos gitcode]$ git add file5
[liren@VM-8-7-centos gitcode]$ cat file5
liren
[liren@VM-8-7-centos gitcode]$ touch file6
[liren@VM-8-7-centos gitcode]$ echo 'lirendada' > file6
[liren@VM-8-7-centos gitcode]$ cat file6
lirendada
此时如何查看当前仓库的状态呢?这就得使用 git status
命令!
git status
命令用于显示工作目录和暂存区的状态。使用此命令能看到哪些修改被暂存到了,哪些没有,哪些文件没有被 Git
追踪到。git status
不显示已经 commit
到项目历史中去的信息。看项目历史的信息要使用 git log
。
并且 git status
也不会显示具体修改的内容,想要查看的话得通过 git diff
指令来查看,这个下面会讲!
在每次执行 git commit
之前先使用 git status
检查文件状态是一个很好的习惯,这样能防止你不小心提交了不想提交的东西。
② 查看暂存区和工作区等之间的更改内容 – git diff
git diff
命令用于显示提交和工作树等之间的更改,此命令比较的是 已写入暂存区和已经被修改但尚未写入暂存区 文件的区别。
主要使用方式如下所示:
git diff <file> # 比较当前文件和暂存区文件差异
git diff HEAD -- [file] # 查看版本库和工作区文件的区别
git diff <id1><id2> # 比较两次提交之间的差异
git diff <branch1> <branch2> # 在两个分支之间比较
git diff --staged # 显示暂存区和上一次提交(commit)的差异
git diff --cached # 显示暂存区和上一次提交(commit)的差异
git diff --stat # 简单查看差异,仅仅比较统计信息
下面我们以上面的 readme
文件为例,查看一下它的差异:
[liren@VM-8-7-centos gitcode]$ git diff readme
diff --git a/readme b/readme # a/readme表示比较的是当前工作目录下的,而b/readme表示比较的是仓库中的readme文件
index e69de29..ff2fbef 100644 # 这一行显示了文件内容的差异。e69de29和ff2fbef是两个文件的哈希值,用于比较它们之间的差异
--- a/readme # 显示了当前工作目录下的readme文件
+++ b/readme # 显示了仓库中的readme文件
@@ -0,0 +1 @@ # 显示了文件内容的差异。-0,0表示当前工作目录下的readme文件没有修改,+1表示仓库中的readme文件增加了一条新行
+lirendada # 显示了仓库中的readme文件的新行,即lirendada
知道了对 readme
做了什么修改后,再把它提交到本地仓库就放心多了!
下面我们对 readme
文件进行 add
操作,看看变化:
[liren@VM-8-7-centos gitcode]$ git add readme
[liren@VM-8-7-centos gitcode]$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: file5
# modified: readme
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# file6
[liren@VM-8-7-centos gitcode]$
可以看到它已经被定义为 Changes to be committed
了,下面我们继续对其进行 commit
操作:
[liren@VM-8-7-centos gitcode]$ git commit -m 'change readme'
[master c82c67b] change readme
2 files changed, 2 insertions(+)
[liren@VM-8-7-centos gitcode]$ git status
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# file6
nothing added to commit but untracked files present (use "git add" to track)
[liren@VM-8-7-centos gitcode]$
可以看到,进行 commit
之后包括 file5
也被提交更新到版本库去了,因为它们都是在暂存区中的!
而对于 file6
来说,只要我们不对其进行 add
操作,那么它就只是在工作区操作罢了!
此时我们将 file6
删除之后,会发现 git
就不再管理到它了!
[liren@VM-8-7-centos gitcode]$ git status
# On branch master
nothing to commit, working directory clean
六、版本回退 – git reset && git reflog
之前我们也提到过,Git
能够管理文件的历史版本,这也是版本控制器重要的能力。如果有一天你发现之前的工作出现了很大的问题,需要在某个特定的历史版本重新开始,这个时候,就需要版本回退的功能了。
git reset
命令用于回退版本,可以指定退回某一次提交的版本。
其语法格式如下:
git reset [--soft | --mixed | --hard] [HEAD]
要解释一下 “回退” 本质是要将 版本库
中的内容进行回退,而 工作区
或 暂存区
是否回退由命令参数决定!
下面我们来介绍一下这些参数:
--mixed
为 默认选项,使用时可以不用带该参数。该参数将暂存区的内容退回为指定提交版本内容,工作区内容保持不变。--soft
参数对于工作区和暂存区的内容都不变,只将版本库回退到某个指定版本。--hard
参数将 暂存区与工作区都退回到指定版本。切记工作区有未提交的代码时不要用这个命令!因为工作区回滚之后,你没有提交的代码就再也找不回了,所以 使用该参数前一定要慎重!!HEAD
- 常见用法:
- 可直接写成
commit id
,表示指定退回的版本HEAD
:当前版本HEAD^
:上一个版本HEAD^^
:上上一个版本HEAD^^^
:上上上一个版本- 以此类推……
- 也可以使用
~数字
表示
HEAD~0
:表示当前版本HEAD~1
:上一个版本HEAD^2
:上上一个版本HEAD^3
:上上上一个版本- 以此类推……
这样子干巴巴的说,可能比较不好理解,下面我们举 --mixed
和 --hard
选项来解释!
① --mixed选项
我们先来看看之前我们操作时留下的 git
提交日志:
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$
我们一开始创建 readme
文件的时候,它是没有数据的,而最后一次修改和提交的时候,readme
里面是有一行文本为 lirendada
,那么此时我们就有一个版本回退的要求啦,就是回到最开始的提交的那个版本,我们就能得到 readme
文本是空的,下面我们就来操作一下回退版本!
我们先用默认选项 --mixed
来测试一下:
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline # 先打印提交日志
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$ git reset --mixed cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 # 退到最开始的版本
Unstaged changes after reset:
M readme
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline # 再次打印提交日志,发现只剩最开始的版本
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$ ls # 但是可以发现此时工作区的内容是不变的!
d file1 file2 file3 file4 file5 readme
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
如何撤销版本回退❓❓❓
如果说此时我们后悔了,不想回退了,那么其实也是有办法进行撤销版本回退的,请记住,撤销版本回退的 关键点
在于要有原来版本的 commit id
,如果找不到这个 commit id
了,那么天皇老子来了也没用哈哈!
所以说我们撤销版本回退的重点就是找到 commit id
,然后方法就是 再次使用之前我们进行版本回退的指令,比如说我们使用了 git reset --mixed "旧版本commit id"
的话,那么我们也要使用 git reset --mixed "原来版本的commit id"
。
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline #打印提交日志
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$ git reset --mixed c82c67bb370034ef67d0bde191252742fcc7d6f6 #根据原来版本的commit id撤销回退
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline #再次打印提交日志,发现我们已经回到原来的版本了!
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$ ls
d file1 file2 file3 file4 file5 readme
但是有一个问题啊,如果此时我们版本回退之后,服务器不小心重启了,找不到原来的 commit id
,那该怎么办,是不是就找不到那个 commit id
了❓❓❓
其实 git
早已给我们留了后路,只需要使用 git reflog
指令,就能找到我们以前所有的版本提交信息了,如下所示:
[liren@VM-8-7-centos gitcode]$ git reflog
cdc96e6 HEAD@{0}: reset: moving to cdc96e6d432ea74b61b4bf36de4dc19f07310eb0
c82c67b HEAD@{1}: reset: moving to c82c67bb370034ef67d0bde191252742fcc7d6f6
cdc96e6 HEAD@{2}: reset: moving to cdc96e6d432ea74b61b4bf36de4dc19f07310eb0
c82c67b HEAD@{3}: commit: change readme
ac00e61 HEAD@{4}: commit: add file5
ced585b HEAD@{5}: commit: add file4
7eb10f5 HEAD@{6}: commit: add 3 files
cdc96e6 HEAD@{7}: commit (initial): first add file:readme
但是可能因为项目的代码很复杂,我们提交了很多日志,此时我们要去找到原来版本的日志,那是难上加难,所以 建议给自己留条后路,不要回退的太彻底!
从上面的信息中,可以明显看出 c82c67b
就是我们要找的原来版本的 commit id
,虽说变短了,但是依然有效,此时再次撤销版本回退:
[liren@VM-8-7-centos gitcode]$ git reset --hard c82c67b
HEAD is now at c82c67b change readme
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline #查看提交日志,发现都回来了!
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$
注意:上面出现了 --hard
选项是因为我又用了 --hard
去进行版本回退,这点不需要关心太多!
② --hard选项
这里和上面一样,还是版本回退到第一个版本,看看这次有什么不同:
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline #打印提交日志
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$ git reset --hard cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 #版本回退,三个区域都是
HEAD is now at cdc96e6 first add file:readme
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline #打印提交日志,发现只剩第一个版本
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$ ls #工作区中的文件也只剩第一个版本中存在的文件
d readme
[liren@VM-8-7-centos gitcode]$ cat readme #并且文件中的内容也回退到空之前的空了
[liren@VM-8-7-centos gitcode]$
接下来我们进行撤销版本回退:
[liren@VM-8-7-centos gitcode]$ git reset --hard c82c67bb370034ef67d0bde191252742fcc7d6f6 #进行撤销版本回退
HEAD is now at c82c67b change readme
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline #可以看到信息变成原来的版本了!
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$ ls
d file1 file2 file3 file4 file5 readme
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
[liren@VM-8-7-centos gitcode]$
💥各版本回退选项的总结
为什么版本回退以及撤销的时候,速度那么快❓❓❓
值得说的是,Git
的版本回退速度非常快,因为 Git
在内部有个指向当前分支(此处是master
)的 HEAD
指针, refs/heads/master
文件里保存当前 master
分支的最新 commit id
。当我们在回退版本的时候,Git
仅仅是给 refs/heads/master
中存储一个特定的 version
,可以简单理解成如下示意图:
版本回退前:
版本回退后:
当你使用 git reset
版本回退时,回退的版本并不会被永久删除。相反,回退命令会创建一个新的提交记录,该记录指向你回退到的旧版本。这个新提交记录会成为你现在的 HEAD
,也就是当前工作目录所在的版本。
因此,你可以通过 git reflog
命令查看你最近的操作记录,包括回退操作,以及你之前所处的版本。如果你想恢复到之前的版本,你可以使用 git checkout
命令指定之前的提交记录的哈希值或分支名,以切换到相应的版本。
需要注意的是,如果你在回退之后对旧版本所在的分支进行了修改并提交了更改,那么这些更改可能会被覆盖或丢失,因为你的回退操作会将你的分支指向旧版本,而不是新更改所在的版本。因此,在 回退之前,最好先将当前分支中的更改提交或保存到其他分支中,以防止数据丢失。
七、撤销修改 – git checkout – [filena]
如果我们在我们的 工作区 写了很长时间代码,越写越写不下去,觉得自己写的实在是看不下去,想恢复到上一个版本,此时就要进行撤销修改操作了,这和我们上面讲的版本回退是有关系的!
主要分为以下三种情况,我们一一解释!
情况一:工作区的代码还未add
此时有两种做法:
- 直接对想撤销的代码手动进行撤销修改 – 不推荐这种做法,如果代码量大的话,可能会越改越乱,背道而驰。
- 使用
git checkout -- [filename]
指令- 它可以将指定文件恢复为最近一次提交或添加到暂存区时的状态。在这种情况下,双横线(
--
)用于区分文件名和分支名或提交哈希值,并且 这个双横线不能省略,省略了的话该命令就变成其它意思了! - 需要注意的是,该命令 会覆盖工作目录中的文件,因此你应该确保你不再需要该文件中未提交的更改。
- 它可以将指定文件恢复为最近一次提交或添加到暂存区时的状态。在这种情况下,双横线(
下面我们向 readme
文件中新增文本 “hello world”,记得这个文件中本来还有一条 “lirendada” 的文本,下面来实践一下:
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
[liren@VM-8-7-centos gitcode]$ echo "hello world" >> readme #往文件中插入数据
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
hello world
[liren@VM-8-7-centos gitcode]$ git checkout -- readme #想恢复为最近一次提交或添加到暂存区时的状态
[liren@VM-8-7-centos gitcode]$ cat readme #查看文件内容,变成原来的样子
lirendada
[liren@VM-8-7-centos gitcode]$ git status
# On branch master
nothing to commit, working directory clean
情况二:代码已经 add,但还未 commit
此时依然是有两种做法:
- 利用
git reset --mixed [filename]
指令撤销暂存区的内容,然后变成情况一去解决 – 不推荐,因为用下面的方法更方便! - 利用
git reset --hard HEAD
指令,一步到位,直接版本回退到HEAD
指针所指的最近一次commit
的版本状态,此时工作区和暂存区都会回退!
下面我们向 readme
文件中新增文本 “hello world”,记得这个文件中本来还有一条 “lirendada” 的文本,然后进行 add
操作,但是不进行 commit
操作,这里只演示第二种做法:
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
[liren@VM-8-7-centos gitcode]$ echo "hello world" >> readme
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
hello world
[liren@VM-8-7-centos gitcode]$ git add readme
[liren@VM-8-7-centos gitcode]$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: readme
#
[liren@VM-8-7-centos gitcode]$ git reset --hard HEAD # 直接回退到最近一次commit的版本,工作区和暂存区都会回退
HEAD is now at c82c67b change readme
[liren@VM-8-7-centos gitcode]$ cat readme # 可以看到内容都已经回退了
lirendada
[liren@VM-8-7-centos gitcode]$ git status
# On branch master
nothing to commit, working directory clean
[liren@VM-8-7-centos gitcode]$
情况三:代码已经 add 和 commit
首先我们要明白,出现这种情况的大前提是要和远程仓库这种概念联系起来才有意义,因为一般来说,我们在公司写代码的时候,公司的仓库对于我们来说就是远程仓库,我们都是在本地先形成仓库,然后用 push
操作推送到远程仓库中去的!
如果此时说我们不小心用 push
把我们不需要的东西推送到了远程仓库中,那就真的惨了……
在这种大前提下,我们才有必要说去回退到前一个版本!其实并不难,懂了上面两种,这种就知道怎么做了:
- 使用
git reset --hard HEAD^
指令,回退到HEAD
所指的最近一次commit
版本的上一个版本,也就是HEAD^
,并且--hard
是对 工作区和暂存区都会有回退影响的,达到了我们的目的!
下面我们向 readme
文件中新增文本 “hello world”,记得这个文件中本来还有一条 “lirendada” 的文本,然后进行 add
操作,并且进行 commit
操作,然后进行回退操作:
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
[liren@VM-8-7-centos gitcode]$ echo "hello world" >> readme
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
hello world
[liren@VM-8-7-centos gitcode]$ git add readme
[liren@VM-8-7-centos gitcode]$ git commit -m 'modify readme' readme
[master 8cf3a74] modify readme
1 file changed, 1 insertion(+)
[liren@VM-8-7-centos gitcode]$ git reset --hard HEAD^ # 进行版本回退,使用--hard撤销工作区和暂存区的内容
HEAD is now at c82c67b change readme
[liren@VM-8-7-centos gitcode]$ cat readme # 可以看到版本已经回退了
lirendada
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$
8、删除文件 – git rm
删除文件其实也有指令,但是如果我们不用指令,直接删掉工作区的文件,比如下面文件中的 readme:
[liren@VM-8-7-centos gitcode]$ ls
file1 file2 file3 file4 file5 readme
[liren@VM-8-7-centos gitcode]$ rm readme #删除工作区文件
[liren@VM-8-7-centos gitcode]$ ls
file1 file2 file3 file4 file5
[liren@VM-8-7-centos gitcode]$ git checkout -- readme #尝试恢复,发现是可以的
[liren@VM-8-7-centos gitcode]$ ls
file1 file2 file3 file4 file5 readme
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
[liren@VM-8-7-centos gitcode]$
其实这是没删干净,因为我们只是删了工作区的文件,此时可能暂存区或者版本库中还有对应的文件,那这可不算是什么删除文件!
其实删除完之后,我们可以用 git status
指令就会告诉我们已经删除了什么文件,如下所示:
[liren@VM-8-7-centos gitcode]$ rm readme
[liren@VM-8-7-centos gitcode]$ git status
# On branch master
# Changes not staged for commit:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# deleted: readme
#
no changes added to commit (use "git add" and/or "git commit -a")
所以如果想真的删除的话,我们就得用 git commit
指令,将此时这个删除信息也推送到版本库中,此时才算是删除完成!
这里就不使用这种方式了,我们直接使用 git rm
指令,下面是其一些常见选项:
- 将文件从暂存区和工作区中删除:
git rm <file>
- 如果删除之前修改过并且已经放到暂存区域的话,则必须要用强制删除选项
-f
:git rm -f <file>
- 如果想把文件从暂存区域移除,但仍然希望保留在当前工作目录中:
git rm --cached <file>
使用该指令之后,我们 依然得用 git commit
指令推送到版本库中,版本库才能知道此时需要删除该文件啦:
[liren@VM-8-7-centos gitcode]$ ls
file1 file2 file3 file4 file5 readme
[liren@VM-8-7-centos gitcode]$ git rm readme #删除工作区和暂存区中该文件
rm 'readme'
[liren@VM-8-7-centos gitcode]$ ls
file1 file2 file3 file4 file5
[liren@VM-8-7-centos gitcode]$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# deleted: readme
#
[liren@VM-8-7-centos gitcode]$ git commit -m 'delete readme' #需要commit后版本库才会知道需要去删除
[master 3131533] delete readme
1 file changed, 1 deletion(-)
delete mode 100644 readme
那要是我们不小心删错文件了怎么办❓❓❓
很简单呀,此时就 转变为了上面基本操作的第七点:撤销修改
的问题 了!这里就不多解释了,具体参考上面!