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问题,一起讨论

相关推荐
high201110 小时前
【Git】-- 版本说明
git
kaixin_learn_qt_ing11 小时前
git clone
git
sin220111 小时前
git stash
git
喝鸡汤11 小时前
一起学Git【第二节:创建版本库】
git
慢慢成长的码农11 小时前
git 同步分支操作
git
sin220111 小时前
git推送本地仓库到远程(Gitee)
git·gitee
丁总学Java13 小时前
git branch -r(--remotes )显示你本地仓库知道的所有 远程分支 的列表
git
yylの博客16 小时前
Windows通过git-bash安装zsh
windows·git·bash·zsh
丁总学Java16 小时前
(Z Shell)zsh: no matches found: ? 使用单引号包裹
git·zsh
萌狼蓝天17 小时前
【NAS】绿联NAS+极狐Gitlab+1Panel
git