「Git 的正确使用姿势与最佳实践」后端实践 | 青训营

80 阅读8分钟

本文是后端实践第一篇。总共第三篇笔记。

一、实践选题:

Git 的正确使用姿势与最佳实践:团队协作和版本控制的最佳实践;

二、实践预备知识点介绍:

git配置

三个级别配置:system、global、local

常见git配置:

git config --global user.name "liaoxingju"
git config --global user.email liaoxingju@bytedance.com
 [user]
    name = liaoxingju
    email = liaoxingju@bytedance.com

Instead of配置 git config --global url.git@github.com:.insteadOf https://github.com/

[url "git@github.com:"]
    insteadof = https://github.com/

Git命令别名配置 git config --global alias.cin "commit --amend --no-edit"

[alias]
    cin = commit --amend --no-edit

git remote

查看 Remote git remote -v

添加 Remote

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

同一个 Origin设置不同的 Push和 Fetch URL

git remote add origin FETCH_URL
git remote set-url --add -push origin PUSH_URL
git remote -v

HTTP REMOTE免密配置

  • 内存: git config --global credential.helper 'cache --timeout=3600'
  • 硬盘: git config --global credential.helper "store --file /path/to/credential-file" 将密钥信息存在指定文件中,不指定目录的情况默认是~/.git-credentials

具体格式:scheme://{scheme}://[user}:${password}@github.com

SSH REMOTE免密配置

SSH可以通过公私钥的机制,将生成公钥存放在服务端,从而实现免密访问目前的 Key的类型四种,分别是dsa、rsa、ecdsa、ed25519 默认使用的是rsa,由于一些安全问题,现在已经不推荐使用dsa和rsa 了,优先推荐使用ed25519 ssh-keygen -t ed25519 -C "your_email@example.com"密钥默认存在~/.ssh/id_ed25519.pub

Objects

.git/objects/

  • commit

  • tree+

  • blob 在git 里面都统一称为Object, 除此之外还有个tag的object(仅annotated tag,不是所有的tag都有object).

  • Blob 存储文件的内容

  • Tree 存储文件的目录信息

  • Commit 存储提交信息,一个 Commit可以对应唯一版本的代码 如何把这三个信息串联在一起呢?

1.通过Commit寻找到Tree信息,每个 Commit都会存储对应的 Tree ID. git cat-file -p 373137d6db9018d97279384fb5644e880a9c1b1b

tree 239ec593c6a2192e76c005435f748b2ad28be832 author liaoxingju liaoxingju@bytedance.com1648371702+0800 committer liaoxingju liaoxingju@bytedance.com 1648371702 +0800

add readme 2.通过 Tree存储的信息,获取到对应的目录树信息。 git cat-file -p 239ec593c6a2192e76c005435f748b2 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 readme.md 3.从tree 中获得 blob 的 ID,通过Blob ID获取对应的文件内容。 git cat-file -p e69de29bb2d1d6434b8b29ae775ad8c2e48c5391

Refs

Refs 文件存储的内容 cat .git/refs/heads/master

373137d6db9018d97279384fb5644e880a9c1b1b cat .git/refs/heads/test 373137d6db9018d97279384fb5644e880a9c1b1b refs的内容就是对应的 Commit ID 因此把ref当做指针,指向对应的Commit来表示当前 Ref 对应的版本。

不同种类的ref refs/heads前缀表示的是分支,除此之外还有其他种类的ref,比如refs/tags前缀表示的是标签。

Branch git checkout -b branchName可以创建一个新分支

分支一般用于开发阶段,是可以不断添加Commit进行迭代的

Tag 标签一般表示的是一个稳定版本,指向的Gommit一般不会变更 git tag tagName

Annotation Tag

什么是附注标签? 一种特殊的Tag,可以给Tag提供一些额外的信息。 如何创建附注标签? 通过git tag -a命令来完成附注标签的创建。

cat .git/refs/tags/v0.0.2
be7fb8574508354cd5887443552e92134c4c2486
git tag -a v0.0.2 -m "some message"

追溯历史版本

·获取当前版本代码 通过Ref 指向的Commit可以获取唯一的代码版本。 ·获取历史版本代码 Commit里面会存有parent commit字段,通过commit的串联获取历史版本代码。

修改历史版本

  1. commit --amend 通过这个命令可以修改最近的一次commit信息,修改之后commit id会变

  2. rebase 通过git rebase -i HEAD~3可以实现对最近三个commit 的修改: 1.合并 commit 2.修改具体的 commit message 3.删除某个commit

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

新增的Object 修改Commit后我们可以发现git object 又出现了变化 新增commit object 7f 但是之前的commit object 63并没有被删除


悬空的 Object:顾名思义就是没有ref 指向的 object

检查仓库中的悬空Object:git fsck --lost-found

Git GC

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

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

git reflog expire --expire=now --all

指定时间 git gc prune=now指定的是修剪多久之前的对象,默认是两周前的才删除

Git Clone & Pull & Fetch

  • Clone 拉取完整的仓库到本地目录,可以指定分支、深度。
  • Fetch 将远端某些分支最新代码拉取到本地,不会执行merge操作。会修改refs/remote 内的分支信息,如果需要和本地代码合并需要手动操作。
  • Pull 拉取远端某分支,并和本地代码进行合并,操作等同于git fetch + git merge,也可以通过git pull --rebase完成git fetch + git rebase 操作。可能存在冲突,需要解决冲突。

常用命令

一般使用git push origin master命令即可完成

冲突问题

1.如果本地的commit记录和远端的commit 历史不一致,则会产生冲突,比如 git commit --amend or git rebase都有可能导致这个问题。

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

推送规则限制

可以通过保护分支,来配置一些保护规则,防止误操作,或者一些不合规的操作出现,导致代码丢失。

常见问题

1.为什么我明明配置了Git配置,但是依然没有办法拉取代码?

  • 免密认证没有配。
  • Instead Of配置没有配
  • 配的SSH免密配置,但是使用的还是HTTP协议访问。

2.为什么我Fetch了远端分支,但是我看本地当前的分支历史还是没有变化?

Fetch 会把代码拉取到本地的远端分支,但是并不会合并到当前分支,所以当前分支历史没有变化。

三、分支管理工作流实践

Git Flow 分支类型丰富,规范严格 Github Flow 只有主干分支和开发分支,规则简单 Gitlab Flow 在主干分支和开发分支之上构建环境分支,版本分支,满足不同发布 or 环境的需要

Git Flow

·包含五种类型的分支

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

优点 如果能按照定义的标准严格执行,代码会很清晰,并且很难出现混乱。

缺点 流程过于复杂,上线的节奏会比较慢。 由于太复杂,研发容易不按照标准执行,从而导致代码出现混乱。

GitHub Flow

Github 的工作流,只有一个主干分支,基于 Pull Request往主干分支中提交代码。

选择团队合作的方式:

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

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

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

创建一个Pull Request

  1. 创建一个main主分支
  2. 创建一个 feature 分支

分支管理工作流-Gitlab Flow

Gitlab推荐的工作流是在GitFlow和Github Flow上做出优化,既保持了单一主分支的简便,又可以适应不同的开发环境。

原则: upstream first上游优先

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

代码合并

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

git merge branchName --ff-only

Three-way Merge:产生新的Merge节点

git merge branchName --no-ff