Bo2SS

Bo2SS

1 Git基础

本机测试环境:macOS 11

01 | 课程综述#

VSC:版本控制系统

  • 集中式 —— 客户端必须时刻和服务器相连
    • SVM
  • 分布式 —— 服务端和客户端都有完整的版本库
    • Git,Linus 开发
    • 基于 Git 的开源社区 —— 背景:DevOps 时代,开发运维
      • GitHub—— 全球最大
      • GitLab—— 公司常用;免费、提供了持续集成 - CI;如阿里云、点评

02 | 安装 Git#

03 | 使用 Git 之前需要做的最小配置#

## 添加name和email配置
git config [--local | --global | --system] user.name 'Your name'
git config [--local | --global | --system] user.email 'Your email'
## 查看现有配置
git config --list [--local | --global | --system]
## 区别
##  --local:本仓库
##  --global: 当前用户的所有仓库
##  --system: 本系统的所有用户
  • 作用:记录人员信息,CR(Code Review,代码审查)时也可以对应发邮件提醒

04 | 创建第一个仓库并配置 local 用户信息#

  • 创建仓库的两种方式,均会生成.git 文件夹
## 在已有项目文件夹里创建git仓库
git init
## 新建一个名为[Project Name]的git仓库
git init [Project Name]
  • 如果需要单独配置 local 用户信息,使用 --local 配置即可,该种配置优先级最高,见上一节
  • 进行一次简单的 commit❗️
## 添加文件到该git项目中,略
## 添加要commit的文件到
git add [File Name]
### PS:添加当前路径下的所有文件—— git add .
## 附带信息进行commit操作
git commit -m'Some Message'
### 查看git状态,如:哪些文件待commit,哪些未被跟踪
git status
### 查看git记录,如:commit的记录
git log

05 | 通过几次 commit 来认识工作区和暂存区#

image

  • 暂存区❗️——Git 的精髓之一
    • 使用场景:开发两套方案,第一套方案做好后先暂存,然后做第二套方案,如果第二套方案没有第一套好,可以再回到第一套
    • PS:
      • 如果要把工作区的某个 file 替换为暂存区,则 git checkout -- file
      • 如果要把工作区变更的所有文件都恢复成和暂存区的一样,则 git checkout *
  • git add -ugit add .
    • 前者:只操作已经被跟踪的文件,即将文件的修改和删除,添加到暂存区
    • 后者:还会操作文件的新建,即将文件的创建、修改和删除,添加到暂存区
    • PS: git add all/-A 针对整个仓库,不只是当前路径
  • 具体操作类似上一节 —— 一次简单的 commit

06 | 给文件重命名的简便方法#

  • 细化步骤
## 重命名
mv readme readme.md
## 添加新文件readme.md
git add readme.md
## 删除被跟踪的旧文件readme
git rm readme
## 提交
git commit -m"rename"
  • 使用 git reset --hard 回退到最新的一次提交,即清空暂存区
  • 再展示精简步骤
## 一条命令顶上面三条
git mv readme readme.md
## 提交
git commit -m"rename"
  • 实操展示

image

通过 git status 实时观察暂存区状态。

PS:第一种方式 git status 也能检测出是 renamed

07 | 通过 git log 查看版本演变历史#

## 查看简洁的单行历史
git log --oneline
## 查看最近的4条历史
git log -n4
git log -4 
## 查看所有分支的历史
git log --all
## 查看指定分支(名为BRANCH_NAME)的历史
git log BRANCH_NAME
## 查看图形化的版本历史
git log --graph
## 组合使用:查看所有分支最近4条图形化的单行历史
git log --all -n4 --graph --oneline
## 跳转到网页版的git log帮助文档
git help --web log
  • git log --all -n4 --graph --oneline 效果图

image

附加命令

  • git branch 查看本地有哪些分支, -a 会同时查看本地和远程的分支
  • git checkout -b <new_branch> []
    • 创建名为 new_brach(以 commit hash 值为 start point 的 commit 为基)的新分支
    • 为了简便,start point 可以选取 hash 值的一个片段,只要能够唯一标识 commit 即可
  • git commit -am'msg'
    • 直接将工作区和暂存区中的文件添加到版本库中,相当于使用了 add
    • ⚠️:只能提交已经被跟踪的文件,新建的文件还是要先通过 git add . 添加到暂存区

PS

  • 可以在~/.zshrc 里,通过别名设置更友好的 log 显示方式,设置好后使用 lg ... 即可
alias lg="git log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
  • 一般地,单字母的选项对应 - ,非单字母的选项是 --

08 | gitk:通过图形界面工具来查看版本历史#

  • Mac 下安装: brew install git-gui
  • 使用: gitk
  • 界面简单展示

image

  1. 选择 View-New View 后,选中 All refs 后,即可展示所有分支、Tag 信息
  2. 右键某一个 commit 有很多操作,如 Create tag

PS

  • 为什么一次 commit 既有作者 Author,又有提交人 Committer
    • 尊重版权
    • 比如 git cherry-pick 命令:将指定的 commit 应用于其他分支
    • 具体使用参考git cherry-pick 教程—— 阮一峰
  • 另推荐一款 Git 图形界面工具:Sourcetree,其实工具之间大同小异,看个人习惯

09 | 探密.git 目录#

Git 具有优秀的存储能力,不需要网络,本地也能做版本管理

image

  • 🌟4 个关键文件:HEAD、config、refs、objects,下面一一剖析
  • ❗️3 个重要对象:commit、tree、blob,PS:tag

image

  1. 关系图如上,参考GIT 对象模型——Git Community Book 中文版
  2. blob:全称 Binary Large Object,即二进制大型对象,可理解为文件对象
  3. 下一节还会深入讲解,先来看看 4 个关键文件~
  • HEAD:指向当前正在工作的分支

image

手动修改 HEAD 里的分支,效果同 git checkout

  • config:本地仓库(local)配置信息

image

主要关注 user 信息

手动修改 config 文件,效果同 git config --local

  • refs:包含 heads 和 tags 文件夹

image

  • heads 里每个分支存放的是一个 commit 的 hash 值
  • tags 里每个里程碑存放的也是一个 commit 的 hash 值
    • 也可能是一个 tag 的 hash 值,其又指向 commit
  • git cat-file :显示版本库对象的信息
    • -t :类型
    • -p :内容(直接用 cat 命令可能会显示乱码,因为这些对象需要解析)
    • 后者接唯一的 hash 值或文件名即可

PS:细心的你会发现一个 commit 里存储了一个 tree 的 hash 值,是不是和一开始的关系图串起来了,再试试查看 tree 的内容

  • objects:存放所有对象,包括 tree /blob/commit

image

  • 1)大部分文件夹📁都是以 hash 值的前 2 位字符命名,里面存放 38 位字符命名的文件
    • 由这 40 位字符组成唯一的 hash 值,指向一个对象
  • 2)tree 对象里存储了 blob 对象信息,blob 对象的内容就是某个文件的内容,如 css.x
    • tree 对象里还可以存储另一个 tree 对象信息
    • 只要文件的内容相同,在 Git 眼里它就是唯一的一个 blob
  • 3)blob 对象内容与其指向的文件内容一致
    • 一定会一致吗?不一定,和版本有关
  • PS:还有 pack 文件夹和 info 文件夹
    • 前者用于存放打包的松散的文件夹,后者与前者相配合

10 | commit、tree 和 blob 三个对象之间的关系#

上一节提到了它们仨,这一节再具体看一个 commit,加深理解

image

  • 这是它们三者的关系图,可以关注箭头的走向,参考GIT 对象模型——Git Community Book 中文版
  • 解析
    • 一个 commit 里的内容由一棵 tree 来管理,有且只有一棵
      • 存放当前 commit 里所有文件夹和文件的一个快照
    • 一棵 tree 里可以有多个子 tree 和多个 blob
    • 一个 blob 里存储的就是文件对象的具体信息
      • 文件内容一样则唯一,与文件名完全无关
  • 示例

image

commit👉tree👉blob + tree

PS: lg 是在第 7 节配置的 git log 友好显示版命令

11 | 小练习:数一数 tree 的个数#

新建的 Git 仓库,有且仅有 1 个 commit,仅仅包含 /doc/readme
请问内含多少个 tree、多少个 blob?

下面开始试验🧪

## 首先新建Git仓库
git init watch_git_object
## 进入仓库,创建doc文件夹,并添加readme
cd watch_git_object
mkdir doc
echo "hello, world" > doc/readme
## 此时观察.git/objects里有没有文件类型的文件:空
find .git/objects -type f
## 把doc添加到暂存区
git add doc/
## 再次观察:Git生成了一个blob对象,里面记录了readme的内容
find .git/objects -type f

image

  • 添加到暂存区时,就会产生 blob 对象
  • ❗️此时还没有 commit、tree 对象,下面进行 commit
## 进行commit
git commit -m'Add readme'
## 观察.git/objects里的文件:已经有4个了
find .git/objects -type f
## 逐个检查它们的类型和内容,如下图所示
git cat-file -t ***
git cat-file -p ***

image

  • 可以看出新生成了:1 个 commit、2 个 tree
  • 它们的关系是:
    • commit👉tree(commit 对应一个 tree)👉tree(doc 文件夹)👉blob(readme 文件)

12 | 分离头指针情况下的注意事项#

detached HEAD

  • 产生:切换 HEAD 到某一个 commit 上(即使是某分支最新的 commit)

image

git checkout <HASH_OF_COMMIT> ,而非某一个分支

此时就会出现 detached HEAD 情况,你可以做一些试验性操作,并进行 commit

1)如果不想保留这些 commit:可以直接切换回分支,不做其它额外的操作

2)如果想保留这些 commit:则需要在此创建一个新的分支,从而与分支挂钩

  • 接着对 readme 做一些修改,并进行提交,当切换回某个分支时

image

Git 友好提示:如果想要保留刚才的提交,可以通过 commit 的 hash 值创建一个新的分支

借助 gitk 查看此时分支的情况,可以看到,看不到刚才 commit 的影子

image

执行上述友好提示中的 git branch fix_readme 34976f8

image

前面做的提交已经与 fix_readme 分支联系起来了

  • 小结
    • 使用场景:做一些试验性尝试
    • ⚠️:当想做保留所做的提交时,要与某个分支挂钩

13 | 进一步理解 HEAD 和 branch#

  • 带着 2 个问题学习:
  1. 新建分支的时候,HEAD 会发生什么变化?(HEAD 指向)
  2. HEAD 相关的使用技巧是什么?(指代 commit,特殊标记 ^~

下面一一进行探讨:

  • 1

HEAD 可以指向具体的分支,也可以指向具体的 commit

通过 git checkout -b <NEW_BRANCH_NAME> <BASE_BRANCH_NAME/HASH_OF_COMMIT> 命令,基于某个分支或提交,创建新的分支,并切换到新分支上

image

可以发现:HEAD 从指向分离头指针,转变到,指向 fix_new 分支上

再观察 HEAD 文件的信息

image

其实,HEAD指向某个分支,而该分支指向某个特定的 commit

  • 2

既然 HEAD 最终指向一个 commit,那也可以用它来指代 commit 的 hash 值啦~

比如在使用 git diff <A> <B> 比较两个 commit 时

image

上面 3 条命令是等价的,即:

git diff 34976f8 a60a3d5git diff HEAD HEAD~git diff HEAD 'HEAD^'

⚠️:

HEAD 的 ^~ 标记都可以获取 HEAD 的祖先 commit,它们的区别可参考下图:

image

这个分支图的方向和 git log --graph 生成的图方向相反,即 A 是最小的;且结合了有 merge 分支的情况

参考What's the difference between HEAD^ and HEAD~ in Git?——StackOverflow

PS:在 zsh 下, ^ 有特殊含义,所以需要用引号包起来

学到这里,是不是更新了自己对 Git 的认识呢~是否期待 Next Part 呢?!

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.