第十一节:Git 的正确使用姿势与最佳实践丨青训营笔记

168 阅读8分钟

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

1. 概述

本节课程学习主要分成三个部分

  1. Git 是什么

  2. Git 命令的基本使用方式及原理

  3. Git 常用的研发流程,我们应该选择怎样的研发流程

本课程围绕这三个部分进行描述,并通过演示 Git 操作,观察 Git 目录的来理解 Git 的原理。以及通过在 Github 上进行操作演示,来带领同学们了解什么是研发流程,符合最佳实践的研发流程是什么。

2. 课前 (必修)

Git 安装

git-scm.com/book/zh/v2/…

Git 基本命令学习

学习 Git Add / Commit 等命令,需要用 Shell 的方式执行,不要直接用图形化页面

www.runoob.com/git/git-bas…

Github 账号创建

  1. 完成 Github 账号创建
  1. 配置公私钥认证
  1. 创建一个个人仓库,并在该仓库上进行基本的 clone / push 操作

3. 课中

3.1 引言

为什么要学习 Git ?

  • Git 在开源社区,协同工作中非常重要

为什么要安排这个课程 ?

  • 许多新同学,对 Git 完全不了解,或者是只知道基本命令,不了解正确的使用姿势和最佳实践

3.2 Git 是什么

3.2.1 版本控制

本地版本控制(例如RCS)

  • 依托于本地磁盘进行版本控制

集中式版本控制(例如SVN)

  • 存在一个统一的远端服务器,用于版本控制,本地不存储版本控制

分布式版本控制(例如Git)

  • 每个库都拥有所有的版本控制信息,远端服务器用于不同库之间进行版本信息同步

3.2.2 发展历史

最初版由 Liunx 创始人 Linus Torvalds 花两周时间开发而成,主要是为了用于 Linux 项目的维护

3.2.3 衍生平台

除此之外,还有 bitbucket, Coding, 码云 等一系列平台

3.3 Git 命令基本使用方式和原理

image.png

3.3.1 Git 配置

  • 项目初始化
mkdir demo
cd demo
git init
//git init 
//其他参数
//--initial-branch 初始化的分支
//--bare 创建一个裸仓库
//--template 可以通过模板来创建预先构建好的自定义git目录
  • Git Config

Git 配置,分成本地,用户,系统基本的配置

用户名配置
git config --global user.name "abc"
git config --global user.email abc@163.com
Instead of 配置
git config --global url.git@github.com:/insteadOf httpe://github.com/
Git命令别名
git config --global alias.cin "commit -- amend --no-edit"
  • Git Remote

Git Remote 配置,分成 SSH 和 HTTP 两种协议实现,不同协议有不同的免密配置方式

查看remote
git remote -v

添加remote
git remote add origin_ssh git@github.com:git/git.git
git remote add origin_http https://github.com/git/git.git

同一个Origin设置不同的push和fetch url
git remote add origin git@github.com:git/git
git remote set-url --add --push origin git@github.com:MY_REPOSITY/git
git remote -v

免密配置

内存:git config --global credential.helper 'cache --timeout=3600'

硬盘:git config --global credential.helper "store --file /path/to/credential-file"
不指定目录的情况是~/.git-credentials

将密钥信息存在指定文件中

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


  • SSH Remote

URL:git@github.com:git/git.git

免密配置

SSH可以通过公私钥的机制,将生成公钥存放在服务端,从而实现免密访问

目前的key的类型四种,分别是dsa、rsa、ecdsa、ed25519

默认使用的是rsa,由于一些安全问题,现在已经不推荐使用dsa和rsa了,优先推荐使用ed25519

ssh-keygen -t ed25519 -C "your_email@example.com" 密钥默认存在~/.ssh/id_ed25519.pub

3.3.2 代码提交

  • Git Add

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

  • Git Commit

将暂存区代码提交到 Git 存储

  • Objects commit/tree/blob在git里面都统一成为Object,除此之外还有个tag的object。

Blob:存储文件的内容

Tree:存储文件的目录信息

Commit:存储提交信息,一个Commit可以对应唯一版本的代码

3.3.3 Git 存储基本概念

  • Refs

    • Tag 仓库标签
    • Branch 仓库分支 refs的内容就是对应的commit ID

    因此把refs当做指针,指向对应的Commit来表示当前Refs对应的版本。

    不同种类的ref

    • refs/heads前缀表示的是分支

    • refs/tags前缀表示的是标签

    • Branch

      • git checkout -b 可以创建一个新分支
      • 分支一般用于开发阶段,是可以不断添加Commit进行迭代的
    • Tag

      • 标签一般表示的是一个稳定版本,指向的Commit一般不会变更
    • Annotation Tag

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

    • 获取当前版本代码
      • 通过Ref指向的Commit可以获取唯一的代码版本
    • 获取历史版本代码
      • Commit里面会存有parent commit字段,通过commit的串联获取历史版本代码
    • 修改历史版本
      • commit --amend 通过这个命令可以修改最近一次的commit信息,修改之后commit id会变
      • rebase 通过git rebase -i HEAD~3 可以实现对最近三个commit的修改:
        • 合并commit
        • 修改具体的commit message
        • 删除某个commit
      • filter --branch
        • 该命令可以指定删除所有提交中的某个文件或全局修改邮箱地址等操作
      • 悬空的Object
        • git fsck --lost-found
    • Git GC
      • 通过git gc命令,可以删除一些不需要的object
      • 会对object进行一些打包压缩来减少仓库的体积
    • Reflog
      • reflog是用于记录操作日志,防止误操作后数据丢失
      • 通过reflog来找到丢失的数据,手动将日志设置为过期
    • 指定时间
      • git gc prune=now指定的是修剪多久之前的对象
      • 默认是两周前
  • 完整的Git视图

image.png

3.3.4 代码同步

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

常用命令:一般使用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协议访问
  1. 为什么我Fetch了远端分支,但是我看本地当前的分支历史还是没有变化?
  • Fetch会把代码拉取到本地的远端分支,但是并不会合并到当前分支,所以当前分支历史没有变化

3.4 Git 研发流程

  • 常见问题
  1. 在Gerrit平台上使用Merge的方式合入代码
  2. 不了解保护分支,Code Review,CI等概念,研发流程不规范
  3. 代码历史混乱,代码合并方式不清晰
  • 不同的工作流

image.png

3.4.5 集中式工作流

围绕主分支进行开发

工作方式:

  1. 获取远端master代码
  2. 直接在master分支完成修改
  3. 提交前拉取最新的master代码和本地代码进行合并(使用rebase),如果有冲突需要解决冲突
  4. 提交本地代码到master
  • Gerrit 平台:在aosp中使用的很广

3.4.6 分支管理工作流

image.png

  • Git Flow
    • 包含物种类型分支:
      • Master:主干分支
      • Develop:开发分支
      • Feature:特性分支
      • Release:发布分支
      • Hotfix:热修复分支
  • Github Flow 只有一个主干分支,基于Pull Request往主干分支中提交代码

选择团队合作的方式

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

3.4.7 如何合并代码

  • Three Way Merge
  • Fast Forward Merge

3.4.8 选择合适的工作流

  • 少量多次提交
  • 保证 CR / CI 等流程通过后才可合入
  • 尽量保证主分支整洁

4. 课后

  1. 寻找一个开源项目进行学习,并将学习笔记整理发布到 Github
  1. 尝试向一个开源项目提交 PR