我在平时和多次面试里表达我在第一次实习中没有参与到规范的git工作流的遗憾,在那个暑假我也写了一篇git的知识总结,将过往学习到的以及我认为重要的git命令写了上去。

但我长久以来都认为学习git必须要到工作流中去,因为现代代码管理和技术管理不仅仅是一个工具,而是从远程到本地,从团队到个人的一整套工作流程,只有在团队性技术实践中我们才能接触到规模化的、生产化的代码管理,进而理解git在这当中发挥的意义。

我会从工作场景、工作流两个方面分享我在最近的实践中对git的新理解。当然,实践时间尚不长久,内容多有误解,望读者包含且指正。最后也会从git作为最流行的版本控制程序的发展历程来讲一讲我对git本身的理解。

工作场景中的常用指令组

如果你仅仅是看了几篇教程或git命令文档,请把“熟悉git工具使用”从你的简历上去掉,或者改为“了解git基本命令”,否则这会害了你。

git本地配置

你可以通过git命令或直接修改git配置文件的方式对git本地配置进行修改,如果你从公司得到一台电脑或新安装了git服务,请务必首先配置您的基本信息,以保证IDE或其他代码编辑工具获取到正确的开发者信息。

通过命令的方式:

# 查看当前git配置清单
git config --list 
# 配置全局git用户名称和邮箱,这将用于标识代码的作者信息
git config --global user.name "username"
git config --global user.email [email protected]

修改git配置文件(通常情况下全局配置文件所在位置):

  • Windows:C:\Users\username\.gitconfig
  • MacOS:/Users/username/.gitconfig~/.gitconfig
  • Linux:/home/username/.gitconfig~/.gitconfig

若有需求需要为某个项目配置独立的git信息,则应在项目的.git目录下找到相关配置并对应修改。

创建与链接远程仓库

基本操作

创建本地仓库:

# 项目目录下
git init
git add .
git add README
git commit -m '首次提交的备注信息'

首次配置远程仓库密钥并创建远程仓库:

# 在本地生成ssh密钥对
ssh-keygen -t rsa -C "[email protected]"
# 复制你的公钥到gitlab或github账户中进行配置,不讲细节了
cat ~/.ssh/id_rsa.pub
# 向本地 Git 仓库添加一个新的远程仓库配置
git remote add origin https://github.com/user/repo.git

常见场景

1.本地有项目,远程空仓库
我们在工作中常见的情形之一便是给你一个项目,然后有权限的管理者在托管平台新建空仓库,随后需首先将本地的框架或demo代码同远程仓库进行关联。

即本地已经存在代码但尚未初始化为git仓库,远程有已建立的空仓库。

进入项目目录,操作示例如下:

git init # 初始化git仓库
git checkout -b dev-branch # 签出开发分支
git add . # 添加文件到暂存区
git commit -m "first commit" # 首次提交
git remote add origin https://remote-repo-url.git # 关联到远程仓库
git push - u origin dev-branch # 推送并关联当前分支

2. 本地尚空,远程项目仓库
这是最常见也最简单的情形,即需要从公司托管平台clone已有代码到本地进行开发。

进入需要存放项目的父目录,操作示例如下:

git clone [email protected] local-project # clone ssh或https的仓库链接
git checkout -b feature-branch # 签出开发分支
git add . # 注意按需添加
git commit -m "Made some changes" # 提交代码
git push origin feature-branch # 推送并关联当前分支

合并与变基

合并(merge)和变基(rebase)都是进行分支合并处理时的选项,其特性和应用没有限制性规范,但需要根据技术团队的需求和风格进行具体选择,例如我所在的团队就倾向于在MR时进行变基,以便于保持master的清晰简洁。

对比合并(Merge)变基(Rebase)
目的将多个分支的修改整合在一起修改提交历史,使分支的提交看起来是基于另一个分支的最新提交线性开发的
提交历史呈现保留分支合并的痕迹,有明显的分支结构,可能会出现合并提交使提交历史更加线性、整洁,没有分支合并的痕迹
冲突处理方式冲突发生时,标记冲突部分,解决后使用git addgit commit完成合并冲突发生时,标记冲突部分,解决后使用git addgit rebase --continue继续变基过程,可能需要多次解决冲突
对远程分支的影响比较直观,远程分支不受本地操作影响,除非推送合并后的分支如果已推送分支到远程,变基后推送可能会导致远程分支提交历史改变,影响其他开发者

整体来分别总结两者的应用场景是这样的:

  • 合并:团队希望保留完整的分支开发历史,相对不注重被提交结果的线性历史
  • 分支:团队不关注前期开发细节,注重提交结果的线性、简洁

MR

MR即Merge Request,合并请求,实现分支的合并。在github平台下通常被称为PR(Pull Request),词语不同但其含义是一致的,都是开发者向仓库管理者提请的合并请求。

之所以要单独提出来讲一下MR,因为它在工作当中是一个非常重要的操作,是衡量开发者工作效果的重要指标之一。

开发者应当在完成自己分支功能的开发后,将功能分支向指定分支合并,即提请MR,这是企业中的仓库管理者会收到开发者的MR请求,启动MR审核程序。其在团队中的大致流程如下:

  1. 开发者创建MR
  2. MR自动流水线检查、构建测试(如果有的话)
  3. 团队或项目负责的,对该仓库有权限的同学对其进行审核
  4. 对MR的核心功能和影响进行测试
  5. 最终合并MR(变基或合并)

工作流程及其中的注意事项

我将简单梳理一个开发工作流程中的git情景,并依据自己的理解标注其中的注意事项。

1. 创建仓库和链接远程仓库

  • 注意确认公司对ssh或http的要求;
  • 特别关注仓库关联的分支,不应在master分支下进行开发或提交
  • 注意修改README

2. 提交并推送代码

  • 编写代码或提交代码前应先使用git pull将当前代码更新至分支最新状态并处理冲突
  • 经常提交代码,完成一部分修改就提交,不要一股脑交一大堆代码
  • 提交代码时注意编写清晰简洁的说明

3. 完成开发提请MR

  • 谨慎提交MR,自己审查明白先
  • 注意选择合适的审核和指派人员,其需要有相关权限
  • 及时处理其他成员对MR提出的问题并给出回应

题外话:理解git和它的发展历程密不可分

在git诞生前,就已有了成熟的版本控制应用,例如Linus在进行Linux开发时使用的Bitkeeper,它们存在专有化、集中式等问题。

Linus 在开发 git 的时候,目标是设计一个简单而强大的系统。他从一开始就采用了分布式的设计理念。在传统的集中式版本控制系统中,如 CVS 和 Subversion,存在一个中央服务器,所有的开发者都需要从这个中央服务器获取和提交代码。而 git 采用分布式模型,每个开发者的本地仓库都是一个完整的版本库,包含了项目的完整历史记录。

由此,我们在应用中着重关注git带来的独有特性或优化能力:

  1. 分布式理念:每一个开发者的本地仓库都是一份完整的仓库;
  2. 分支处理:git带来了强大而简洁的分支创建、切换和合并能力,进而引入了丰富的分支管理策略;
  3. 快照存储:git会以快照形式存储每一个文件的状态,由此带来极为高效的版本切换能力;
  4. 离线工作:由于git本地仓库的完整结构设计,开发者可以再不链接远程仓库的情况下,在本地持续开发和提交代码,进行版本管理。