likes
comments
collection
share

Git实践基础分享

作者站长头像
站长
· 阅读数 3

前言

大家好,我是加权,在37手游负责安卓SDK业务。

本文旨在介绍在工作中使用git的一些经验,让初学者能够快速理解和使用git,不会涉及高深的指令和冷门操作。希望对大家有帮助。

使用Git的目的

大家网上随便一搜就能查到git的各种优势,我就不复制粘贴了。

实际工作中,对我最有帮助的几点是

  1. 允许我犯错,能够撤销操作,恢复代码
  2. 完整的代码记录,能够了解项目代码的发展过程
  3. 分支的管理协作,避免代码混乱

而我使用git的根本目的在于,让我的项目时刻保持在一个清晰,便于维护的状态。所以我每做一个操作,都会思考下,这样做是否可以合理。

接下来,我们有必要先介绍下git的几个必须知道的概念。

基本概念

工作区域概念

  1. 工作区
    1. 工程下git管理的所有文件默认都在工作区
    2. 工作区的文件你可以随便玩,非常安全
    3. 工作区的改动通过add命令添加到暂存区
  2. 暂存区
    1. 暂存区是存放提交前的内容的地方,需要仔细留意进入暂存区的内容是否是你想要的
    2. 暂存区的内容可以提交(commit)到本地仓库
  3. 本地仓库
    1. 提交到本地仓库后,改动就会记录在案,可以针对提交记录做二次操作
    2. 提交后,二次处理提交记录时需要小心,因为操作错误后需要更复杂的方法才可以恢复,甚至不能恢复
    3. 本地仓库可以推送(push)到远程仓库,可以拉取(pul)远程仓库的内容
  4. 远程仓库:
    1. 公司代码的大本营,除了拉取代码(pull)是绝对安全,其他指令都要三思
    2. 一般情况下都会对远程仓库做权限管理,避免错误操作做成无法挽回的问题

Git实践基础分享

操作对象概念

  1. 分支(branch)
    1. 创建分支等同于创建副本,在分支内做任何操作都非常安全,不会影响主版本
    2. 通常,一个需求会对应一个分支
    3. 大部分分支都是“消耗品”,合并后会删除
  2. 头(HEAD)
    1. 是一个特殊的指针,指向你当前所在的提交上,一般来说都是指向某个分支的最新提交上,但是也可以单独指向某个提交
    2. 一般是不需要特别注意,但是做任何提交前,应该都要留意当前的头在哪里,确保操作正确
  3. 提交(commit)
    1. 当把暂存区的内容提交(动词)到仓库时,就会产生一个提交(commit,名词)
    2. 一个commit会有一个唯一的sha值,通过这个sha值就可以找回内容
    3. commit是单个操作的最小单元,大部分的二次操作都是针对commit的
    4. 在主分支上的commit可以说是永存的
    5. 不在主分支上的commit,大部分时候,只要知道sha值也可以恢复
  4. 标签(tags)
    1. 用来标记commit
    2. 常见用来标记发版节点

操作概念

  1. 检出(checkout)
    1. 切换、创建分支
  2. 提交(commit)
    1. 把暂存区的内容提交到仓库
  3. 推送(push)
    1. 把本地仓库的内容推送到远程仓库
    2. 一般都是推送单个分支
  4. 拉取(pul)
    1. 把远程仓库的内容拉取到本地仓库
    2. 需要注意,一些git工具(如source tree),可以跨分支拉取,有可能产生其他附带操作(如合并、变基)
  5. 获取(fetch)
    1. 拉取远程仓库的信息,不会对分支产生影响
  6. 合并(merge)
    1. 合并是针对分支操作的
    2. 合并有几种模式,需要注意的是快速合并不会产生commit,类似于直接复制分支,实际工作中,合并需求分支时禁用快速合并,强制产生commit会比较好
    3. 合并是有方向的,A merge B是把B分之合并到A分支,产生的commit会在A分支上
  7. 变基(rebase)
    1. 变基是针对分支操作的
    2. 简单地说,变基就是调整分支上的第一个commit的起始位置
    3. 变基的高阶操作,可以调整分支上任意一个commit,这一个功能对整理代码非常有用
  8. 遴选(cherry pick)
    1. cherry pick是针对commit的
    2. 可以理解为复制代码,一般是用来复制其他分支的commit到当前分支
    3. cherry pick对commit的细化程度有要求,如果commit内有多余的代码,通常就比较难直接cherry pick
  9. 回滚(revert)
    1. 提交一个commit的反操作,来消除commit
    2. 最合适的场景是,通过revert来移除一个已经合并的功能,对付反复修改需求的产品经理的神器
  10. 重置(reset)
    1. 把分支重置到某个commit,相当于撤销操作
    2. 注意,重置后,分支上的记录,甚至暂存区的内容,都会消失,因此需要小心操作

常用的概念基本就是这些,百看不如一练,接下来看看在实际场景中会用到哪些操作吧。

场景0:张三入职第一次拉工程

#0x00:拉工程

git clone xxxxx.git

相信聪明的大家都会了,不在赘述

#0x01:设置用户

有时候会漏了这一步,这样我们有可能看不出这代码是张三写的,那么想让他背锅的时候就比较麻烦~所以得让张三设置下用户属性。

git config user.name zhangsan
git config user.email zhangsan@gmail.com

如果是张三自己的电脑,他也可以是设置全局属性,那么就不用每次都设置了。

#0x02:拉取最新分支

通常clone仓库后,默认拉取的是master分支,张三需要确认下工程的分支规范,然后拉取最新的分支

git checkout dev
git pull

至此,张三就在本地有了最新的代码了他可以开始搬砖了

场景1:新任务

现在需求来了,我们给张三分配个需求,验下货,就给他做个登录界面吧。

那么张三就要先拉取最新的dev分支,如上一步,那么此时张三是在dev分支上了。

#0x00:创建分支

要新开任务,所以张三需要新建分支,分支名称如果能体现需求的话,在后续的处理上会有帮助,所以我们以fea前缀表示功能,login表示登录需求,创建一个fea-login分支。

git checkout -b fea-login

关于分支的规范各个团队可能不同,但是应该至少可以通过分支名区分出普通需求(feature)、更新功能(update)、移除功能(remove)、bug修复(bugfix)等类型,以便在分支合并或者回顾时快速知道分支的内容。

#0x01:提交代码

张三一顿操作之后,创建了几个新文件,此时他想先提交一次。

那么首先通过add命令,添加想提交的内容到暂存区

git add --all

这一步通过GUI工具会更加容易,比如sourceTree

Git实践基础分享 通过GUI可以清晰看到暂存区的情况,可以按行或者按区块添加改动到暂存区,比敲命令更不容易出错。

添加代码到暂存区后,张三可以提交代码了。

为了提交记录的可读性,我们要求张三每次提交时需要写上能体现提交内容的信息

git commit -m 'a-添加登录文件'

关于提交信息,相信各个团队有自己的规范和要求。我自己习惯在提交信息前添加前缀来表示这个提交的主要作用,是新增代码(a),修改代码(m),修复问题(f),移除代码(rm),测试代码(ta/tm),还是无关重要的文本优化(o)。这个习惯对我回顾提交记录时有很大帮助,大家可以参考下。

又经过一顿操作,张三终于搞定了,他准备推送分支到远程仓库,好让我们合并分支了。

// 首次提交
git push --set-upstream origin fea-login
// 普通提交
git push

到目前为止张三表现不错,看看接下来怎样~

场景2:李四更新了远端分支

就在张三准备确认推送之前,李四告诉张三,因为他开发的功能有部分也涉及登录模块,已经提交合并到dev了,有可能会影响张三的功能,所以让张三注意下,避免产生冲突。

其实这里不一定要张三处理,不过张三第一天来,还是多干一点好好表现吧。

所以张三切换回dev分支,重新拉取了dev的代码

git checkout dev
git pull

因为改动的内容比较多,张三也不确认自己改动的代码会不会和现在的dev冲突,这时张三可以选择通过变基来确认是否有冲突

// 先切换回工作分支
git checkout fea-login
// rebase到最新的dev上
git rebase dev

运气不错,顺利完成了变基,张三确认自己的代码不会和dev产生冲突,可以推送到远程仓库了。这样在合并分支时,必定不会有冲突产生。

通过变基操作,我们的分支可以好像在最新的代码的基础上开发一样,如果代码有冲突,也能够得到明确提示,在这个场景下相当有用。

但是需要注意,rebase实际会产生新的commit,和原本的分支的提交记录会有较大差异,所以如果已经推送过到远端,则需要小心操作!

场景3:合并功能提测

张三和李四都开发完毕,现在可以合并提测了,首先介绍下合并的fast-forward概念

当前分支合并到另一分支时,如果没有分歧解决,会直接移动文件指针,这个过程就是fast-forward

这样合并后的效果相当于一直在主分支上开发,被合并分支不存在。

这样虽然看起来整个分支树会很简洁,但是在多人合作的场景下并不好,因为以后回顾的时候就好像张三直接在主分支开发了登录功能,如果都使用这种模式合并的话,很容易就无法区分功能分支了。

所以,在合并分支时,我更加倾向通过no-ff参数禁用fast-forward,强制产生一个新的merge commit,这样分支合并就很清晰了。

所以张三需要做的是

// 先切换回dev上
git checkout dev
// 确保代码最新
git pull
// 合并工作分支
git merge --no-ff fea-login
// 推送到远端
git push

这样就完成了可以提测了

一般提测可能还需要新增版本号,这时张三也可以直接在dev分支上新增版本号后再提交构建。

总结

至此,张三已经可以正常处理日常的开发需求了,回顾下几个重要点

  1. 一个功能应该一个分支,并且分支名称应该符合规范
  2. 提交代码应该把控好“颗粒度”,并且应该填写符合规范的提交信息,方便review
  3. 推送分支代码前,应该先检查是否和远端有冲突,可通过rebase来处理,如果已经推送过远端需要小心操作
  4. 合并分支应该使用no-ff禁用fast-forward,产生合并commit

以上就是本文分享的全部内容了,下一篇文章我们再来分享下更多git操作。

欢迎大家在评论区说出git操作的一些问题,一起探讨~