Git实践进阶分享

前言

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

本文旨在介绍在工作中使用git的一些经验,分享下我自己日常开发中git的高频场景。希望对大家有帮助。

场景0:找回历史commit

git reflog

git的一个重要作用就是记录文件变化,正常情况下应该能看到文件所有时间内的修改历史,让我们可以随时回退修改。不过在实际工作中,总会有意外发生,导致历史丢失。比如误删除了本地未提交的分支。

这时候,我们可以使用reflog命令来查看被删掉的commit,然后通过reset/cherry pick恢复。

张三接到需求,需要给工程的user模块增加昵称和缓存逻辑,张三效率爆表,一下就完成了,提交记录如下

突然,因为不明原因,产品说昵称和缓存不要了,张三也是比较熟悉git的,所以他直接使用git reset --hard f948cc5命令来回退代码,回退后,提交记录如下

可见这时的提交记录已经没有昵称和缓存的痕迹了,没有任何问题。

这时,因为不明原因,产品又希望把昵称和缓存加回来,张三不可能又重新写一次代码,但是在日志里面又找不到之前昵称和缓存的提交记录了,这时,就可以通过git reflog命令来查看操作历史,如下图

通过记录我们就可以看到之前消除掉的昵称和缓存的提交,然后通过git reset ---hard 5aa4345来恢复昵称和缓存的代码了。

那么假如产品只是想加回来昵称,还是继续砍掉缓存呢,那么我们可以使用git cherry-pick e5bb629来只恢复昵称的提交。

通过这个示例我们还可以看到清晰、有意义的提交日志 非常有帮助。假如提交日志都是无明确意义的说明,那么即使有git reflog这样的工具,想找回目标内容也不是一件简单的事。

虽然reflog是找回历史的强力工具,但也不是万能的,有些情况它仍然无能为力:

  1. 非本地操作的记录
    1. git reflog能管理的是本地工作区操作记录,所以其他机器上的记录是无法找回的
  2. 未commit的内容
  3. 太久远的内容
    1. git reflog保留的记录有一定时间限制(默认 90 天),超时的会被自动清理。另外如果主动执行清理命令也会提前清理掉。

记录SHA1

由于reflog的限制,超出一定时间的commit记录,也会被删除,导致无法找到记录。

例如,我们发了一个特殊的小版本,没有合并到主分支,经过一段时间后,这个特殊小版本的分支被清理掉了。过了N久,突然需要用到这个特殊的小版本,这时候通过reflog可能已经找不到提交记录了,也就很难恢复代码了。

为了应对这种情况,我们可以记录提交的SHA1到发版文件里面,那么即使reflog已经无记录,我们也有机会找回commit。

实际中,我们可以使用git rev-parse --short HEAD来记录发版时的SHA1,并写入到发版文件中。

需要注意的是,如果记录的commit在仓库中无任何引用,是有可能被gc彻底删除的,那么即使我们有SHA1也没用了。

但是记录这个SHA1仍是一个比较好的实践,当用到的时候可以节省非常多的时间,而且几乎没有成本,何乐而不为呢。

场景1:不同模块的重合功能

在多人协作中,常常会遇到需求之间有依赖的情况。那么怎样才能保证开发效率的同时,可以保持提交记录的逻辑性呢,我们来看案例。

张三和李四这次接到需求,产品需要给用户增加一个vip标识,当用户是vip的时候,登录后有酷炫的效果动画,同时支付的时候会有特殊的弹窗提示。那么按照功能划分,涉及用户模块,登录模块和支付模块,并且登录模块和支付模块依赖用户模块的vip标识。

按模块熟悉程度分工,张三负责用户模块和登录模块,李四负责支付模块,这时候李四支付相关的功能需要依赖张三负责的用户模块中的vip标识,这时候他们有两种选择。

cherry pick

如果重合功能的代码量比较低,可以压缩到一个commit,那么可以

  1. 张三新建分支,快速开发vip标识功能,提交推送到远端,然后续集开发自己的分支
  2. 李四新建分支,直接cherry pick张三提交的commit,然后继续开发自己的分支
  3. 所有功能开发完毕后合并

这种方式适合重合部分较简单的场景,缺点是代码很早就推送到远端,后续无法自由修改commit。

rebase

当重合功能的代码开发较复杂的时候,可以先开发,然后联调时rebase

  1. 张三新建vip标识功能分支,开发
  2. 李四新建分支,同步开发,使用到vip标识时留空
  3. 张三开发完毕vip标识功能,推送到远端,并继续新建分支开发登录模块功能
  4. 李四将本地分支rebase到vip标识功能分支,联调
  5. 所有功能开发完毕后合并

这种方式的缺点,因为本质上是按依赖关系按顺序开发,所以有可能会阻塞开发,影响整体效率,解决这个问题比较依赖李四的能力,如果能较好地留空,进行同步开发,理论上是不怎么会影响效率的。

优点是通过分支和rebase进行功能同步,提交逻辑更加清晰,重合功能的分支也留有更多修改空间。

场景2:修改提交历史

我们一直提到,提交记录需要合适的颗粒度,可读的提交日志,能够体现代码、需求的变更,而做到这几点并不容易,特别是一次提交就不再更改,在实际开发中几乎无法做到,所以就需要有手段能够修改提交历史,让我们可以调整提交历史,让它们更符合上述要求。

rebase -i

rebase -i 的意思是互动式rebase,使用该命令时,git会打开编辑器,提供指定的提交信息,让我们可以修改这些提交信息,常见操作

  1. 调换commit的顺序
  2. 修改commit的提交日志(r)
  3. 删除commit(d)
  4. 合并commit(f)

调换commit顺序

虽然我们说提交commit得有逻辑,不过实际工作中,经常会出现写着A需求的时候,看到一个遗留问题,不改吧,可能就忘了,那就顺手改了吧,然后,不提交吧,就一直在那里,影响其他git操作,提交吧,又跟A需求没关系。

这时候我们就可以先提交,然后最后再通过rebase -i来调换提交顺序,来让这个和A需求无关的提交移动到最后。

实际操作只需要移动对应的commit即可。

修改commit日志

使用git越久,就会越发现清楚明了的提交日志作用很大,所以值得花时间打磨描述,通过rebase -i,可以修改任意提交的日志。

  1. rebase -i
  2. 修改指定提交的前缀pick,改为r
  3. 保存退出编译器,git会再次打开编辑器显示指定提交的日志
  4. 修改日志,并保存退出

通过git commit --amend可以修改最近一次的提交日志

删除commit

需求在发版之前总是处于薛定谔状态,所以删除commit也是家常便饭了

  1. rebase -i
  2. 直接删除指定commit的行
  3. 保存退出编译器

合并commit

在实际开发中,大部分功能我们都很难一步到位,不再修改,比如,开发到最后,才想起补方式注释;比如开发到一半才发现刚才的提交中有BUG,这时候补充提交固然可以,但是也让提交记录变得有点零碎,这时候就可以使用rebase -i合并这些commit,让代码记录看起来是"一步到位"的。

  1. rebase -i
  1. 移动需要被合并commit到目标commit的下方
  2. 修改需要被合并commit的前缀pick,改为f
  1. 保存退出编译器

最终,补充提交的内容就会合并到之前的提交,就好像一开始就提交了所有内容一样,完美~

注意:推送到远端后就不能再使用rebase,否则会导致本地和远端不一致

以上就是本次要分享的所有内容啦,欢迎大家在评论区说出你遇到的git问题,一起讨论

相关推荐
研究是为了理解2 小时前
Git Bash 常用命令
git·elasticsearch·bash
DKPT3 小时前
Git 的基本概念和使用方式
git
Winston Wood6 小时前
一文了解git TAG
git·版本控制
喵喵先森6 小时前
Git 的基本概念和使用方式
git·源代码管理
xianwu5437 小时前
反向代理模块
linux·开发语言·网络·git
binishuaio10 小时前
Java 第11天 (git版本控制器基础用法)
java·开发语言·git
会发光的猪。11 小时前
如何在vscode中安装git详细新手教程
前端·ide·git·vscode
stewie612 小时前
在IDEA中使用Git
java·git
晓理紫21 小时前
使用git lfs向huggingface提交较大的数据或者权重
git
我不是程序猿儿1 天前
【GIT】sourceTree的“当前分支“,“合并分支“与“检出分支的区别
git