(十一)Git|青训营笔记

195 阅读11分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记

一、学习准备

1 Git安装(Ubuntu 18.04)

sudo apt install git-all

2 Git基本操作(from:菜鸟教程)

  • 常用命令:
    • git clone
    • git push
    • git add
    • git commit
    • git checkout(切换分支)
    • git pull

image.png

2.1 创建仓库命令

命令说明
git init初始化仓库
git clone拷贝一份远程仓库

2.2 提交与修改

命令说明
git add添加文件到暂存区
git status查看仓库当前的状态,显示有变更的文件
git diff比较文件的不同,即暂存区和工作区的差异
git commit提交暂存区到本地仓库(注意和git push区分)
git reset回退版本
git rm删除工作区文件
git mv移动或重命名工作区文件

2.3 提交日志

命令说明
git log查看历史提交记录
git blame <file>以列表形式查看指定文件的历史修改记录

2.4 远程操作

命令说明
git remote远程仓库操作
git fetch从远程获取代码库
git pull下载远程代码并合并
git push上传远程代码并合并

3 github账号关联

3.1 配置用户名和邮箱

  • 设置用户名 git config --global user.name "username"

  • 设置邮箱 git config --global user.email useremail@email.com

  • 查看用户名 git config user.name

  • 查看邮箱 git config user.email

用户名和邮箱地址是本地Git客户端的一个变量。用户每次提交代码都会记录用户名和邮箱。

3.2 创建SSHkey

ssh-keygen -t rsa -C "<your@email.com>"

image.png

  • 在root用户文件夹(登录用户名)下生成 .ssh文件夹,里面包含 id_rsa 和id_rsa.pub两个文件

3.3 在github中配置(gitlab同理)

(1) image.png (2)image.png (3)image.png (4)image.png

  • title随意
  • 将id_rsa.pub中的内容复制入Key框中

3.3 验证

ssh -T git@github.com

yes

image.png

二、Git的基本使用

1 Git初始化

1.1 项目初始化

mkdir git-demo 
cd git-demo 
git init

image.png

git init

git --initial-branch

  • 初始化的分支

git init --bare

  • –bare 参数,一般用来初始化一个空的目录,作为远程存储仓库

git init --template template_dir

  • –template 参数,相当于复制模版仓库,template_dir模版仓库的目录

git init --separate-git-dir git_dir

  • 相当于复制仓库git_dir(可以是工作仓库,也可以是存储仓库)中的.git目录

1.2 Git目录简介

tree .git

image.png

文件(夹)名说明
hooks包含客户端或服务端的钩子脚本(可以自定义在代码提交过程中应该做的事,比如在代码提交前检测代码格式是否符合规范)
info包含一个全局性排除文件(记录不需要git进行管理的文件)
logs保存日志信息
objects   存储所有数据内容
refs     存储指向数据(分支)的提交对象的指针
config   文件包含项目特有的配置选项
description   用来显示对仓库的描述信息
HEAD       文件指示目前被检出的分支
index     文件保存暂存区信息

2 Git配置

2.1 Git Config

  • --global
  • --system
  • --local

每个级别的配置可能会重复,但是低级别的配置会覆盖高级别的配置

2.1.1 用户名配置

  • 设置用户名 git config --global user.name "username"

  • 设置邮箱 git config --global user.email useremail@email.com

2.1.2 instead of 配置

git config --global url."https://".insteadOf git://
可以把 git:// 替换成 https:// 方便使用 https 协议

2.1.3 Git命令别名配置

git config --global alias.cin "commit --amend --no-edit"commit --amend --no-edit简化为cin

2.2 Git Remote

Remote 可以有几个,每一个通常是只读、只写或读/写,它可以理解为是远端代码托管平台的地址。Git 借助 remote 可以实现添加远程存储库、删除不再有效的远程存储库、管理各种远程分支并定义它们是否被跟踪等等。

2.2.1 添加remote

git remote add origin_ssh git@github.com:git/git.git

  • 其中的origin_ssh可以看作是别名

git remote add origin_http https://github.com/git/git.git

可以通过配置remote实现fetch和push指向不同的源

2.2.2 查看Remote

git remote --v

image.png

cat .git/config

image.png

  • 实际上,修改remote的实际结果就是修改了config文件中对应的部分,所以也可以直接修改config文件

image.png

  • 可以用-h参数查询git remote的其他具体用法

2.2.3 HTTP Remote(不推荐)

url样式:github.com/git/git.git

(1)免密配置1

image.png (2)免密配置2

image.png

2.2.4 ssh Remote

url样式:git@github.com:git/git.git

image.png (如果拉不下代码,可能是新版本windows无法使用不安全的加密方式)

可以配置多个key,但是需要在git上进行key的指定

3 代码提交

3.1 Git Add

git add:将代码从工作区提交到暂存区

touch readme.md
vim readme.md //写入Hello World!
git add .

image.png

  • 可以发现,objects文件夹中多了一个文件。
  • 可以用git cat-file -p 980a0d5f19a64b4b30a87d4206aade58726b60e3读取出文件内容

image.png

3.2 Git Commit

git commit -m "add readme"

image.png object文件夹中新增了两个文件,一个tree(a8),一个commit(4d)

image.png

4 Objects

4.1 Objects的组成

image.png commit / tree / blob在git中统称为Object。除此之外,还有个tag的object。

  • Blob--存储文件的内容
  • Tree--存储文件的目录信息
  • Commit--存储提交信息,一个Commt可以对应唯一版本的代码
  • tag--存储真正指向的Commit Object以及一些附加信息

4.2 Objects中信息的串联

(1)通过Commit寻找到Tree信息,每个Commit都会存储着对应的Tree ID;

(2)通过Tree存储的信息,获取到对应的目录树信息;

(3)从Tree中获得blob的ID,通过Blob ID获取对应的文件内容。

image.png

5 Refs

5.1 Refs/heads

Refs/heads前缀表示的是分支 image.png

refs/heads/master中存储的是对应分支的commit ID

尝试创建并切换到新分支

image.png

image.png 因此把ref当作指针,指向对应的Commit来表示当前Ref对应的版本

git checkout -b可以创建一个新分支,分支一般用于开发阶段,可以不断添加Commit进行迭代(commit本身不会变更,指向变更了)

5.2 Refs/tag

5.2.1 tag

refs/tags前缀表示的是标签

在Git中,用标签(tag)为项目的各版本提供了一个让人容易记住的有意义的名字。标签总是跟某个commit绑在一起——发布一个版本时,在版本库中打一个标签,就可以实现利用标签提取对应的历史版本。标签一般表示的是一个稳定版本,指向的Commit一般不会变更 标签的使用文档(from:廖雪峰)

使用git tag v0.0.1生成tag

image.png 查看tag的内容

image.png 指向的正是当前分支的commit object(此处的commit因为没有变动过,所以和master分支指向相同)

5.2.2 Annotation Tag

一种特殊的Tag,可以给Tag提供一些额外的信息。 执行命令git tag -a v0.02 -m"add feature1"

image.png 发现objects中多出了一个object,这个object的类型正是前面没有介绍的tag object

image.png 对比发现,

  • 不加注释的tag直接指向了当前commit;
  • 而Annotation指向了tag object。 查看tag object

image.png 发现tag object中保存了实际指向的commit object、annotation以及一些其他信息。

6 历史版本

6.1 追溯历史版本

Commit里会存有parent commit字段,通过commit的串联获取历史版本代码 执行以下命令:

vim readme.md
git add.
git commit -m "update readme"

image.png 发现 objects中增加了三个objcet,分别是treeblob以及commit

使用git log命令,获取最新的Commit ID

image.png

使用git cat-file -p命令可以在显示的结果中找到当前commit版本的parentCommit ID

image.png

6.2 修改历史版本

6.2.1 git commit --amend

通过这个命令可以修改最近一次的commitmessage信息,修改之后的commit id会变化,但是其treeparent指向不会发生变化

不是回滚版本,只是修改message信息

image.png

6.2.2 git rebase

通过git rebase -i HEAD~3 可以实现对最近三个commit的修改,比如:

  • 合并commit
  • 修改具体的commit message
  • 删除某个commit

6.2.3 filter --branch

filter --branch

该命令可以指定删除所有提交中的某个文件或者全局修改邮箱地址等操作

6.2.4 悬空object

通过git fsck --lost-found命令可以查看当前是否有悬空的Object(没有ref指向的object

image.png 通过上述操作,git commit --amend命令使得之前的那个commit id指代的代码版本已经没有作用了。

6.2.5 Git GC

  • GC

通过git gc命令,可以删除一些不需要的object,以及对object进行一些打包压缩来减少仓库的体积

  • Reflog

reflog用于记录操作日志,防止误操作之后数据丢失,通过reflog来找到丢失的数据,手动将日志设置为过期

  • 指定时间

git gc prune=now指的是修剪多久之前的对象,默认是两周前

执行以下命令

git reflog expire --expire=now --all
git gc --prune=now

image.png 观察.git目录

image.png 发现git目录中删除空悬对象,并对其他对象进行了打包

7 远端操作

7.1 Git Clone & Pull & Fetch

  • Clone

拉取完整的仓库代码到本地目录,可以指定分支,深度。

  • Fetch(不清楚远端情况)

将远端的某些分支最新代码拉取到本地,不会执行merge操作,会修改refs。remote内的分支信息,如果需要和本地代码合并需要手动操作。

  • Pull(清楚远端情况)

拉取远端分支,并和本地代码进行合并,操作等同于git fetch + git merge,也可以通过git pull --rebase 完成 git fetch + git rebase操作。可能存在冲突,需要解决。

7.2 Git push

push是将本地代码同步至远端的方式.

7.2.1 常用命令:

一般使用 git push origin master 命令。

7.2.2 冲突问题:

  • 本地的commit 记录和远端 commit 不一致,会产生冲突,如git commit --amend or git rebase命令都有可能导致这个问题。

  • 如果该分支只有自己使用,或者团队内确认可以修改历史,则可以通过git push origin master -f来完成强制推送,一般不推荐主干分支执行该操作,正常都应该解决冲突后再进行推送。

7.2.3 推送规则:

设置一些分支保护规则防止误操作(Branch protection rules)

三、Git研发流程

1 集中式工作流

(1)获取远端master分支代码;

(2) 直接在master分支完成修改;

(3) 提交前拉取最新master代码和本地代码合并使用(rebase),如果有冲突解决冲突;

(4)提交本地代码到master。

2 分支管理工作流

2.1 Git Flow

分支类型丰富,规范严格

  • Master:主干分支
  • Develop:开发分支
  • Feature:特性分支
  • Release:发布分支
  • Hotfix:热修复分支

2.2 Github Flow

Github的工作流,只有主干分支和开发分支,规则简单,基于Pull Request 往主干分支中提交代码。

团队的合作方式:

  1. owner 创建好仓库之后,其他用户通过Fork的方式创建自己的仓库,并在fork的仓库上进行开发。
  2. owner 创建好仓库之后,统一给团队内成员分配权限,直接在同一个仓库内进行开发。

接下来用github模拟github-flow的工作模式。

2.2.1 创建仓库并克隆到本地

先到自己的GitHub中创建一个仓库:github-flow-demo,并克隆到本地。(路径忘记切了...) git clone git@github.com:laochonger/github-flow-demo.git

选择ssh协议 image.png

2.2.2 本地仓库中创建文件并commit

image.png

2.2.3 git push

image.png 浏览器中查看 image.png

origin为当前项目的默认配置

image.png

2.2.4 创建一个feature分支,修改readme文件后commit并push

image.png

image.png

2.2.5 pull request

上图中GitHub自动生成了一个向main分支合入的pull request链接,复制后去浏览器打开。(也可以直接在平台上打开)

image.png

创建一个pull request

image.png

确认没问题后,merge

image.png 可以看到,已经merge成功了,回到本地仓库,切换回master分支,拉取远程master分支最新的代码。

image.png

2.2.6 Branch protection rule(配置分支保护规则)

image.png

2.3 Gitlab Flow

在主干分支和开发分支的基础上构建环境分支,版本分支,满足不同发布or环境的需要。

原则:upstream first 上游优先

只有上游分支采纳的代码才可以进入到下游分支,一般上游分支就是master。

3 代码合并

3.1 Fast-Forward

不会产生一个merge节点,合并之后保持一个线性的历史,如果target分支又了更新,则需要通过rebase操作更新source branch 后才可以合入。

image.png

3.2 Three-Way Merge

三方合并,会产生一个新的merge节点。

image.png

4 如何选择合适的工作流

没有最好,只有最合适。

针对小团队合作,推荐使用 Github 工作流即可:

  1. 尽量保证少量多次,最好不要一次性提交上千行代码
  2. 提交Pull Request 后最少需要保证有CR(Code Review)后再合入
  3. 主干分支尽量保持整洁,使用fast-forward 合入方式,合入前进行rebase