目录

1 版本管理演变

1.1 VCS出现之前

1.2 集中式VCS

1.3 分布式VCS

2 Git的安装与配置

2.1 安装Git

2.2 使用Git的最小配置

2.3 Git配置作用域

2.3.1 git config --local

2.3.2 git config --global

2.3.3 git config --system

3 创建第一个git仓库

3.1 已有项目代码

3.2 尚无项目代码

3.3 设置local作用域配置项

4 提交commit

4.1 Git工作方式概述

4.2 提交commit实例

4.2.1 实验中使用的命令

4.2.2 添加readme文件

4.2.3 添加index.html和logo

4.2.4 添加style.css

4.2.5 添加script.js

4.2.6 修改index.html & style.css

5 文件重命名

5.1 在工作目录重命名文件

5.1.1 在工作目录重命名文件

5.1.2 更新文件管理状态

5.2 使用git mv命令重命名文件

6 Git分支操作

6.1 创建分支

6.2 查看分支信息

6.2.1 git branch

6.2.2 git branch -v

6.2.3 git branch -a

7 通过git log查看版本历史

7.1 git log

7.2 git log --oneline

7.3 git log -nx

7.4 git log --all

7.5 git log --graph

8 通过图形界面工具查看版本历史

8.1 gitk基本布局

8.2 在gitk中显示所有分支

8.3 创建tag

9 Git工作原理分析

9.1 .git目录分析

9.1.1 config文件

9.1.2 HEAD文件

9.1.3 ref目录

9.1.4 objects目录

9.2 Git对象间的关系

9.2.1 Git对象关系实例

9.2.2 Git对象关系图示

9.2.3 实验:Git对象的创建

10 分离头指针

10.1 造成分离头指针状态

10.2 分离头指针状态下变更实例

10.2.1 修改文件并创建commit

10.2.2 切换分支

10.2.3 创建分支保存修改

10.3 HEAD的本质与指代

10.3.1 HEAD的本质

10.3.2 通过HEAD指向祖先提交


1 版本管理演变

VCS(Version Control System):版本控制系统,是一种记录一个或若干个文件内容变化,以便将来查阅特定修订情况的系统

1.1 VCS出现之前

1. 使用目录拷贝区分不同版本

2. 开发过程中,公共文件容易被覆盖

3. 成员沟通成本高,代码集成效率低下

1.2 集中式VCS

1. 具有集中的版本管理服务器

2. 具备文件版本管理和分支管理能力

3. 集成效率明显提高

4. 因为客户端不具备完整的版本历史,因此客户端需要时刻和服务器相连

说明:典型的集中式VCS有CVS(Concurrent Versions System)和SVN(subversion)

1.3 分布式VCS

1. 服务端和客户端都有完整的版本库

2. 脱离服务器,客户端依然可以管理版本

3. 查看历史和版本比较等多数操作,都不需要访问服务器。相较于集中式VCS,更能提高版本管理效率

说明1:典型的分布式VCS有Git和BitKeeper

说明2:Git的特点

① 最优的存储能力

② 非凡的性能

③ 开源

④ 很容易做备份

⑤ 支持离线操作

⑥ 很容易定制工作流程

2 Git的安装与配置

2.1 安装Git

1. 我们的实验环境为Ubuntu 20.04,可以使用如下命令安装Git

sudo apt-get install git-all

2. 安装完成后,可以使用如下命令查看版本信息,以验证安装是否成功

git --version

说明:在其他操作系统上安装Git,可参考安装Git

2.2 使用Git的最小配置

1. 在使用Git之前,至少要配置用户的name和email信息。如果不加配置,后续在生成commit信息时,系统仍会提示需要配置

2. 使用如下命令设置用户的name和email信息

git config --global user.name 'cheng.chen'git config --global user.email 'cheng.chen@horizon.ai'

3. 配置完成后,可以使用如下命令查看配置是否成功

git config --list

2.3 Git配置作用域

在上面的最小配置示例中,使用了--global参数,该参数用于指定当前配置项的作用域。Git共支持3个作用域

需要注意的是,所有配置最终都要落实到对应的配置文件才能生效

2.3.1 git config --local

1. 只对当前仓库有效

2. 该命令只能在已经建立的git仓库中使用

3. 对应的配置文件为git仓库/.git/config

2.3.2 git config --global

1. 对登录用户的所有仓库有效,是最常用的配置作用域

2. 对应的配置文件为~/.gitconfig

说明:我们可以查看~/.gitconfig文件,验证之前的最小配置是否记录在其中

2.3.3 git config --system

1. 对登录系统的所有用户生效

2. 对应的配置文件为/etc/gitconfig

说明1:从不同作用域配置项的存储文件位置,可以很容易不同作用域的生效范围

说明2:配置作用域的优先级

local > global > system

说明3:不同作用域配置项的查看

git config --list --localgit config --list --globalgit config --list --system# 查看所有作用域的配置项# 这里其实隐含了一个条件,就是要有读取各配置文件的权限git config --list

3 创建第一个git仓库

创建Git仓库有2种方法

3.1 已有项目代码

cd 项目代码目录git init

说明:命令执行后,会在项目代码目录创建.git目录,该目录就是Git实现版本管理的关键

3.2 尚无项目代码

git init project_name # 会在当前路径下创建和项目名称同名的目录

说明:在生成的git_learning目录中,也会创建.git目录

3.3 设置local作用域配置项

之前在global作用域设置了user.name & user.email,现在再以local作用域设置这2个配置项,目的是用于后续验证local作用域的优先级是否高于global作用域

为作区别,local作用域设置不同的user.name & user.email

git config --local user.name 'maidou'git config --local user.email 'maidoumaizi@sina.com'

说明1:在当前git仓库中查看配置项

说明2:当前git仓库配置文件内容

4 提交commit

4.1 Git工作方式概述

1. 在工作目录修改的文件需要先通过git add操作提交到暂存区

2. 暂存区中的修改记录通过git commit操作生成一次版本提交历史

说明:暂存区使用场景示例

假设实现一个功能有多种方案,

① 在工作目录实现方案1,并将其提交到暂存区

② 在工作目录继续实现方案2,如果验证后方案2更好,则将方案2提交到暂存区;如果方案1更好,则使用暂存区中的内容覆盖工作目录(从另一个角度看,就是撤销当前工作目录的修改)

4.2 提交commit实例

下面通过5次提交来演示单分支开发流程,实验中使用到的文件如下

4.2.1 实验中使用的命令

# 查看当前工作目录和暂存区的状态git status# 将工作目录中的内容提交到暂存区# git add之后可指定多个文件和目录git add# 将暂存区的内容提交为版本记录git commit# 查看版本记录git log

4.2.2 添加readme文件

说明:在当前git仓库提交commit,可见生效的是local作用域的配置,即local作用域的配置项优先级高于global作用域

4.2.3 添加index.htmllogo

4.2.4 添加style.css

4.2.5 添加script.js

4.2.6 修改index.html & style.css

说明:此处使用git add -u更新工作目录中所有已经被Git管理的文件

5 文件重命名

说明:该实例实现将工程中的readme文件重命名为readme.md

5.1 在工作目录重命名文件

5.1.1 在工作目录重命名文件

在工作目录重命名文件后,git status将显示readme文件被删除,同时新增未被Git管理的readme.md文件

5.1.2 更新文件管理状态

根据上一步git status中的提示,使用git add / rm命令更新文件管理状态

说明1:更新文件管理状态后,Git会识别出此次操作实现了文件的重命名,后续只要通过git commit提交,即可生成新的版本信息

说明2:使用当前方法,重命名文件需要执行3条命令

mvgit addgit rm

说明3:撤销本次修改

为了进行后续实验,此处需要撤销本次修改,可以使用如下命令清理当前的暂存区和工作目录

git reset --hard

需要注意的是,此时的重命名修改尚未commit,只是提交到暂存区

tips:由于git reset --hard命令会清空当前暂存区和工作目录中的修改,所以需要谨慎使用

5.2 使用git mv命令重命名文件

使用一条git mv命令可以实现同样的效果

需要注意的是,git mv命令的修改直接体现在暂存区,而不是在工作目录,不需要通过git add命令提交到暂存区

说明:使用git mv命令可以实现和之前相同的功能,但是只需要执行一条命令。此时将文件名修改提交,由于更改文件名的操作已经被加入暂存区,只需要commit即可

6 Git分支操作

6.1 创建分支

为了更好地说明git log查看版本历史的方法,此处先建立一个分支

我们以Add style.css的commit为基础创建分支,命令如下,

git checkout -b 新分支名称 对应commit编号

说明1:也可以基于已有分支创建新分支,命令如下,

git checkout -b 新分支名称 已有旧分支名称

说明2:git checkout -b命令在创建分支的同时也会切换到该分支,我们在新建的temp分支上进行修改并创建commit

说明3:使用如下命令可以基于当前commit创建新分支,但此时不会切换到新创建的分支,需要使用git checkout命令进行切换

git branch 分支名称

说明4:使用如下命令可以在已有分支之间进行切换

git checkout 分支名

6.2 查看分支信息

6.2.1 git branch

通过git branch命令可以查看当前仓库的所有分支,其中当前分支前会加星号(*)

6.2.2 git branch -v

通过git branche -v命令可以查看当前仓库的所有分支及其HEAD指向的commit信息

在当前测试环境中,各分支的HEAD指向最后一次提交的commit信息

6.2.3 git branch -a

通过git branch -a命令可以同时查看本地分支和远程分支

由于当前并未建立远程分支,所以git branch -a命令与git branch命令显示的内容相同

说明:下面给出一个拥有远程分支的仓库实例,其中红色的是远程分支

7 通过git log查看版本历史

7.1 git log

git log命令可以查看当前分支版本历史,之前已有多个实例

说明:可以在git log之后指定要查看的分支名称

在示例中,temp为当前分支,但是可以指定查看master分支的版本历史

7.2 git log --oneline

git log --oneline命令可以查看当前分支简洁的commit信息

7.3 git log -nx

此处的x是一个数字,用于指定要查看的commit个数,可以指定查看当前分支最新的x次commit信息

7.4 git log --all

git log --all命令可以查看所有分支的commit信息

7.5 git log --graph

git log --all命令会按提交顺序显示所有分支的commit信息,难以看出不同分支的源流关系,此时可以添加--graph选项,以图形化方式显示源流关系

说明:上面介绍的命令行选项可以组合使用

可见此时-n4显示的是所有分支的最近4个commit信息,而不是每个分支的最近4个

8 通过图形界面工具查看版本历史

8.1 gitk基本布局

在git仓库中运行gitk命令后,版本历史将会以图形界面的方式呈现

说明1:在Ubuntu系统中,默认并未安装gitk工具,需要用户自行安装

说明2:对于文件信息,当选择Patch时,显示的是本次commit的文件变更信息;当选择Tree时,显示的是本次commit后的文件内容

说明3:gitk commit信息说明

① Branches信息

包含该commit的所有分支

② Author & Commiter不一致的场景

当通过cherrypick操作挑选某一次的提交到指定分支时,为了尊重版权,Author & Commiter就是不同的,Author将保留原作者信息

8.2 gitk中显示所有分支

有2种方式可以在gitk中显示所有分支信息

1. 在git仓库中使用gitk --all信息启动gitk

2. 在view选项中显示所有分支

由于本地分支(local branches)、标签(tags)和远程分支(remote branches)都是reference,所以此处选择All refs,就包含了所有这些信息

说明:使用gitk --all命令启动gitk时,view选项中指定的就是All refs

8.3 创建tag

在要创建tag的commit上点击鼠标右键,可见gitk提供了多种功能选择项

我们选择Create tag选项,并输入Tag的名称与信息,即可创建Tag

可见Tag已经创建完成,点击该Tag的标签,即可显示相应的Tag信息

9 Git工作原理分析

9.1 .git目录分析

9.1.1 config文件

如上文所述,该文件为local作用域配置文件,内容如下

9.1.2 HEAD文件

1. HEAD文件表示git仓库当前正在工作的分支

2. HEAD文件内容如下,

可见HEAD文件指向refs目录中的一个引用

说明:将git仓库切换到master分支,HEAD文件指向的引用也将随之变化

9.1.3 ref目录

ref目录中包含了heads和tags两个子目录,其中,

1. heads目录对应分支,分支是一个独立的开发空间,不同分支之间互不影响

2. tags目录对应标签,标签是项目开发到一定程度的一个里程碑(e.g. 在开发到版本v1.0对应的commit上创建标签)

说明:从目录结构可以看出,分支和标签都属于引用

9.1.3.1 heads/master文件

1. 文件内容

2. 对象类型

可见master文件指向的是一个commit

说明:git cat-file命令

git cat-file命令可用于查看git仓库对象的类型、内容和大小信息,其中,

① -t选项查看对象类型(show the object type)

② -p选项查看对象内容(pretty-print the content of object based on its type)

③ -s选项查看对象大小(show the object size)

3. 对象内容

可见对象的内容,就是该commit对应的信息,即master指向maser分支的最后一个commit

9.1.3.2 heads/temp文件

1. 文件内容

2. 对象类型

3. 对象内容

可见temp指向temp分支的最后一个commit

9.1.3.3 tags/tag01文件

1. 文件内容

2. 对象类型

3. 对象内容

可见tag01指向对应标签的信息

说明:由于tag也是基于commit创建的,所以查看对应的commit类型与内容

可见对应的正是创建tag的commit

9.1.4 objects目录

1. objects目录是Git文件系统的核心内容

2. objects目录中的目录名 + 文件名构成对象的哈希值

以上图为例,目录名(00)+ 文件名(1975b3b等)就构成了所存储的Git对象的哈希值

3. Git在使用过程中,会对存储的文件进行梳理与压缩,如果有压缩文件产生,则会存储在pack目录中(这也是为何Git可以取得最优的存储性能)

9.2 Git对象间的关系

9.2.1 Git对象关系实例

Git中的三个核心对象为commit、tree、blob,下面以.git/objects目录下存储的文件系统实例,来展示Git对象间的关系

1. commit对象

① objects/00目录下存储的对象为commit

② 该commit中存储了一个tree对象

2. tree对象

① tree对象中存储了一系列tree对象和blob对象

② tree对象中存储的对象关系,与相应的git仓库目录树对应

3. blob对象

此处显示的是index.html对应的blob对象的内容,可见就是index.html文件的内容

9.2.2 Git对象关系图示

1. 每次执行git commit命令,都会创建一个commit对象

2. 一个commit对象会对应且只对应一个tree对象,该tree对象表示的是该commit对应的git仓库中所有目录和文件的快照(状态)

3. tree对象对应的是目录

4. blob对象对应的是具体的某个文件

说明:在Git中,blob对象和文件名没有关系。任何文件只要内容相同,就使用同一个blob存储,从而可以提升Git的存储性能

9.2.3 实验:Git对象的创建

实验内容:新建一个git仓库,仅包含doc/readme文件,之后创建commit。在此过程中,查看Git对象的创建过程

9.2.3.1 新建git仓库

9.2.3.2 创建目录

说明:新建的空目录不会被Git管理

9.2.3.3 创建文件

说明:此时创建的文件尚未提交到暂存区,Git不会为其创建对象

9.2.3.4 将修改提交到暂存区

说明:将修改提交到暂存区后,Git会为其创建对象

我们来查看该对象的类型与内容

可见该对象的类型为blob,内容就是readme文件的内容

9.2.3.5 创建commit

说明:创建commit后,Git创建的对象状态如下

可见共创建了4个对象,下面逐一查看这些对象的类型与内容

可见共生成了1个commit对象、2个tree对象和1个blob对象,他们的关系如下图所示

10 分离头指针

10.1 造成分离头指针状态

基于指定的commit执行checkout命令,可以不创建分支,而是造成分离头指针的状态

1. 分离头指针(detached HEAD state)的本质含义,就是目前工作在没有关联分支的状态下

2. 分离头指针状态注意事项如下,

① 可以在分离头指针状态下继续开发(e.g. 进行变更并创建commit),且不会影响其他分支

② 当切换分支时,在分离头指针状态下进行的变更会被丢弃

③ 可以新建分支,保存在分离头指针状态下进行的变更

说明1:当前分支状态

可见当前没有关联到任何分支

说明2:当前HEAD状态

由于HEAD就是指向分支的,所以当前HEAD也体现为没有关联到任何分支。作为对比,正常情况下HEAD会指向某个分支

10.2 分离头指针状态下变更实例

10.2.1 修改文件并创建commit

修改style.css文件,并创建commit

说明1:使用-am选项创建commit时,是根据工作目录中的修改直接创建,省略了将修改提交到暂存区的步骤(但是不推荐)

说明2:创建commit后,HEAD指向新创建的commit,且仍处于分离头指针状态

10.2.2 切换分支

1. 可以从分离头指针状态切换到指定分支

2. 切换时会提示需要创建新分支保存在分离头指针状态下的变更,否则修改会被丢弃

说明:通过git log命令可发现在分离头指针状态下的变更并未被Git管理

10.2.3 创建分支保存修改

可见在创建新分支后,之前在分离头指针状态下的变更已被Git管理

说明:分离头指针状态的使用场景

基于某个commit进行尝试性的变更,如果需要保存,则新建分支;如果无需保存,则直接切换到其他分支

10.3 HEAD的本质与指代

10.3.1 HEAD的本质

HEAD本质上会指向一个commit,

1. 在正常状态下,HEAD会指向分支的最后一个commit,这点在chapter 9.1.3已有验证

2. 在分离头指针状态下,HEAD会指向某个指定的commit

10.3.2 通过HEAD指向祖先提交

10.3.2.1 实验场景

假设要比较如下2个commit之间的差异,

1. 通过commit的哈希值进行比较

2. 通过HEAD的指代进行比较

之所以可以通过HEAD进行指代,就是因为HEAD本质上就是指向一个commit

10.3.2.2 ~的作用

1. ~<n>表示一个提交的第n个祖先提交,如果不指定n,那么默认为1

2. 假设有如下commit提交关系,

那么HEAD~1指向B,HEAD~2指向A

说明:~也可以按如下方式使用

HEAD~~与HEAD~2等价

10.3.2.3 ^的作用

1. ^<n>表示一个提交的第n个父提交,如果不指定n,那么默认为1

2. 假设有如下commit提交关系,即C是由B合并到A中并产生的一个新提交,

那么HEAD^1指向A,HEAD^2指向B

说明:^也可以按如下方式使用

HEAD^^与HEAD~~等价,而与HEAD^2不等价

参考资料:获取git某分支的祖先提交(HEAD^2和HEAD~2)

玩转Git三剑客01:Git基础相关推荐

  1. 玩转Git三剑客——01. 课程综述

    学习视频:玩转Git三剑客(苏玲 携程代码平台负责人)--极客时间 https://time.geekbang.org 1. 版本控制系统(Version Control System, VCS)的演 ...

  2. git进阶 | 01 - git基础操作进阶

    引言 上次写git入门教程还是2019年(Git & Github学习总结),三年期间使用最多的命令不过三条: git add -A git commit -m "" gi ...

  3. 玩转Git三剑客——04. 创建第一个仓库并配置local用户信息、05. 通过几次commit来认识工作区和暂存区...

    学习视频:玩转Git三剑客(苏玲 携程代码平台负责人)--极客时间 https://time.geekbang.org 一.建Git仓库 两种场景 1. 把已有的项目代码纳入Git管理 cd 项目代码 ...

  4. Git三剑客之基础部分

    文章目录 git三剑客 概要 一.Git基础 安装Git 配置信息 创建仓库&&local信息 简单认识工作区.暂存区 1.生成git文件 2.加入style.css 3.加入js文件 ...

  5. 《玩转git三剑客》笔记

    文章目录 Git 基础 .git目录 对象 commit tree blob Git命令 GitHub 三种Pull Request的区别 Git 基础 .gitignore中指定不需要Git管理的文 ...

  6. 「高效程序员的修炼」代码版本管理工具 Git 用起来 01 Git 基础

    如果对你有帮助,点个关注点个赞吧~ 文章目录 1. Git 基础 1.1 使用Git之前的最小配置 1.2 创建仓库 1.3 工作区和暂存区 1.4 Git中重命名文件 1.5 git log 查看版 ...

  7. 《玩转Git三剑客》

    文章目录 3.使用Git之前需要做的最小配置 建Git仓库 往仓库添加文件 git log查看版本演变历史 gitk 通过图形界面工具查看版本历史 探秘 commit tree blob的关系 树一树 ...

  8. 厉害了!寓教于乐,用玩游戏的方式学习 Git!

    作者 | mozlingyu 来源 | 少数派 用游戏的方式来学习,是一种有趣而高效的方式. 从刚接触电脑时的打字练习软件 金山打字通,到程序猿写代码的利器 Vim 都有小游戏(金山打字通游戏.VIM ...

  9. 《Git篇》01.Git看这一篇就够了

    陈老老老板 说明:在整体的复习一遍知识,边复习边总结,基础真的重要,需要注意的地方都标红了,还有资源的分享. 一起加油.关于git的文章之前写过只有指令的这个更多的是扩展知识,比svn好用太多 视频链 ...

最新文章

  1. python中将一个全部为int的list 转化为str的list
  2. Geodatabase中基于规则的拓扑关系管理机制
  3. C语言及程序设计提高例程-10 调试技术:进入函数内部去
  4. Flink AggOperator 增量聚合函数
  5. 我究竟为什么要每天埋头写代码?
  6. php sql 字段不能为空值,关于php:Sudden SQL问题-一般错误:1364字段没有默认值
  7. Numpy安装+导入出错的解决方法
  8. 库表操作 - 存储引擎
  9. [ZOJ 3607] Lazier Salesgirl
  10. myeclipse安装使用svn
  11. ue4 基于motion vector粒子优化的一些感悟
  12. 无损音乐刻录成cd有意义吗_这5个强大免费的无损音乐网站,你收藏了吗?
  13. 仿网易云PC端项目-vue
  14. 向量叉乘求三维空间中两直线(或线段)的交点
  15. 逃不开的安迪-比尔定律,在智能机器人时代该如何破解?
  16. Android 集成 Agora SDK 快速体验 RTC 版多人视频聊天|掘金技术征文
  17. 如果给video标签动态写入视频?
  18. 蚊子凭啥只咬你?科学家用 5 年造出一批“脑子发光”的蚊子,终于搞懂背后机制
  19. 为什么IT行业这么火?
  20. python中一切内容都可以称为_创业基础答案黑龙江大学

热门文章

  1. java puzzlers英文版_java puzzlers [更新至14.04.03]
  2. 九阴真经 服务器列表文件,《九阴真经》部分服务器互通升级公告
  3. java jsch shell_仅在JSch shell通道中获取特定命令的输出
  4. 计算机二级只有前十套简单,计算机二级Access上机十套试题详细解析(经典版).
  5. 7z 头部错误 数据错误_Vue项目组件数据类型错误处理
  6. 运行jar中某个类的main方法
  7. redis入门综合概要介绍
  8. 反转map的key-value
  9. 【Jetty】Jetty 的工作原理以及与 Tomcat 的比较
  10. 修改驱动器重定向显示格式