前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一次git事故

一次git事故

作者头像
重归混沌
发布2020-04-26 12:51:32
3290
发布2020-04-26 12:51:32
举报
文章被收录于专栏:重归混沌重归混沌

在开发过程中,我们的版本管理方式是,一版本一分支。之所以这样,是因为随着开发的进行,版本随时会分叉(这里分叉是指,两个版本都需要后续开发,但是对同一模块的功能需要不一样的微调)。

随着分叉之后的持续开发,就会导致多个分支之间差别越来越大。因此,如果所有版本都添加同样功能或修改同一个Bug时,是不可以采用git merge的方式来进行的。因为很难找到他相同的父节点。这时patch会是一个很好的工具。

而这次事故正是git patch功能使用不当引起的,下面来模拟出一个完整的事故现场。

在最开始我们有一段原始代码如下,可以明显看到,在第18行代码中,将dst错打成了src。

代码语言:javascript
复制
void foo(std::vector<int> &src, std::vector<int> &dst, int id)
{
        for (auto iter = src.begin(); iter != src.end(); )
        {
                if (*iter == id)
                {
                        iter = src.erase(iter);
                }
                else
                {
                        ++iter;
                }
        }
        for (auto iter = dst.begin(); iter != dst.end(); )
        {
                if (*iter == id)
                {
                        iter = src.erase(iter);
                }
                else
                {
                        ++iter;
                }
        }
        dst.push_back(id);
        return ;
}

以此次commit为节点,分切出分支ver1和ver2。

然后在ver1分支上修改上述错误并使用git commit提交,由于也许有很多并行版本都有这个问题,一个一个去改很消耗时间还容易错。因此可以使用`git formatch-patch HEAD~1`来制作一个patch文件,我们得到的patch文件内容如下:

代码语言:javascript
复制
From 3c3a434d131c8cea38eb77b7b0f4681b78ae4172 Mon Sep 17 00:00:00 2001
From: findstr <findstr@sina.com>
Date: Sun, 4 Mar 2018 15:43:43 +0800
Subject: [PATCH] bugfix
 
---
 a.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
 
diff --git a/a.c b/a.c
index 241c07f..1157ab4 100644
--- a/a.c
+++ b/a.c
@@ -15,7 +15,7 @@ void foo(std::vector<int> &src, std::vector<int> &dst, int id)
        {
                if (*iter == id)
                {
-                       iter = src.erase(iter);
+                       iter = dst.erase(iter);
                }
                else
                {
--
2.4.6

切到ver2分支后,先手动将18行修改提交一次,再使用`git am 0001-bugfix.patch`来重复修复这个Bug。

预期中,执行完git am之后,只有两种情况。一是这个文件完全没有变化,二是会出现conflict。

然而,事实并没有想象中的那么美好,执行完git am之后,第7行的src被改成了dst。

以上基本就是整个事故的全部还原过程。

这种事故很难发现,一旦发现却很容易就知道原因。

分析一下patch文件,就会立即发现,整个patch行为是靠以下7行代码来定位的。

代码语言:javascript
复制
{
                if (*iter == id)
                {
-                       iter = src.erase(iter);
+                       iter = dst.erase(iter);
                }
                else
                {

恰巧,由于在git am之前,我手动修改了这一行,导致在执行git am时,不可能会匹配到这一块出错的代码。更巧的是,git可以使用个patch中的代码块匹配到第4行的代码,即然匹配成功了,git自然就会将修改应用。

从这个事故中,可以得到几点启示。

  1. patch并不是100%可靠的,执行之后最好查看一下结果

2. 大扩号另起一行,对版本管理工具不友好:D

3. DRY原则 不但对人适用,对版本管理工具同样适用

ps. 如果实在没有办法,就尽量扩大git diff输出的代码块大小,`git config –global diff.context 30`即可把代码块增加致30行

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-07-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 重归混沌 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档