阅读 3539

一个命名不规范引发的事故(文末有抽奖源码)

本文已申请到掘金周边礼物-两枚掘金徽章,用于评论区抽奖。通过评论的方式参与 详情

写在前面

事情是这样的今天早上看到公司的 Gitlab 有这样的一则关于 Tag 命名的规范:

不能与本项目的已有分支名称重名

好奇心的驱使之下就点开了更多关于故事的背景。

主要的过程就不赘述了。总结来说的事情的过程大致为:

  • 问题:在测试环境构建发布代码的时候,新的逻辑始终不生效。
  • 分析:使用 Gitlab 网页、API 等获取到 master 的代码均不是最新代码。
  • 原因:开发在某一次上线的节点上创建了一个名称为 master 的 tag;导致网页、API 基于 master 的操作默认选择了 tag master 而不是我们期望的 branch master
  • 结果:新增 Gitlab Server Hook 对约束 tag 命名。禁止tag命名为 master、禁止 tag 与分支重名等。

重要的事情说三遍:

分支(Branch)名称与 标签(Tag)名称不可相同

分支(Branch)名称与 标签(Tag)名称不可相同

分支(Branch)名称与 标签(Tag)名称不可相同

一些资料

问题分析

上述的问题在开发其实很容易就会发生。虽然建议、约束都有但是该有的骚操作一个也不会拉下。下面就结合一个 demo 看看究竟发生了什么?

本地代码演示

尝试在本地创建名称相同的 tag 与 branch。如下代码可以看到在切换分支的时候会有 warning 的提示。提示索引的名称是不清楚模棱两可的。

~/github/demo on  master ⌚ 18:30:42
$ git tag master

~/github/demo on  master ⌚ 18:30:48
$ git checkout master
warning: refname 'master' is ambiguous.
Already on 'master'
复制代码

那么在本地的 git 命令默认切换的是 branch 名称,如何切换到对应的 tag 名称上呢?如下可以指定具体的索引类型,指定切换到具体的 branch/tag 。

# 切换到指定的 tag
git checkout refs/tags/master

# 切换到指定的 branch
git checkout refs/heads/master

复制代码

如何删除同名分 branch/tag,可以使用 branch/tag 全称。

git branch -D refs/heads/dev
git tag -d refs/tags/dev
复制代码

总结:可以看到本地在使用 checkout 命令遇到同名的 branch tag 会出现的警告,默认会切换到分支上。如果想切换到 tag 上,可以通过指定切换的类型达到目的。

这里很容易就会想到两个问题:

  • Branch 与 Tag 的区别,为什么要有区分?

  • Branch/Tag 名称相同的情况下,Checkout 默认切换到 Tag 上?

Branch 与 Tag 的区别

可以查看 StackOverflow 上关于这方便的讨论 How is a tag different from a branch in Git

答:简单的来说不同点有以下两点:

  • branch 的特点是该分支的指针的位置随着提交不断更新,一般是存储在 refs/heads/
  • tag 的特点与分支恰恰相反,指向的 commit 不会随着新的提交去更新。一般是存储在 refs/tags/

引用 StackOverflow 上的例子来解释一下:

image.png

分支(Branch)的概念很像在阅读时候使用的书签,实时记录我们读书时刻的最新位置。而标签(Tag)很像我们在书中贴的便签,方便我们快回到某一页。

Checkout 的优先级

存在 branch 与 tag 同名的情况下使用 git checkout something 的时候为什么会优先使用 tag ?

在 Git Checkout 文档中 git-scm.com/docs/git-ch… 说明 Checkout 有两个主要用途一是用于丢弃某些提交的文件;而是切换 git 索引的位置。如果存在 branch 与 tag 名称相同的情况下,默认切换到分支并给出警告。

创建 commitId 为名称的 tag

如果我创建一个以 commit id 为名称的 branch/tag 会怎样?

这个问题就作为一个课后作业,交给各位感兴趣的小伙伴自行思考了。结合上面的分析答案应该比较明显了。

思考总结

出现这类问题的时候是我们日常中的使用习惯认为 master 应该就是默认的分支。但是忽略了 GitLab CI 部署的时候可能会优先使用 Tag 名称作为部署名称。

如下是一个关于 tag branch 同名情况下 Gitlab CI 的问题讨论。 Branch and tag with same name cause multiple problems 这里很详细的说明 Gitlab branch/tag 同名情况下会出现的问题。

所以在日常使用 Git 的时候一定要养成良好的习惯。

  • 无论是分支的命名还是标签的命名都应该避免冲突。
  • 在分支/标签命名的时候要有规范,见名知义(这一点写代码的同学应该不陌生)。
  • 一定要注意 Warning,有时候解决 Warning 就会解决一个 Bug。
  • 充分的使用工具对一些可预期的行为进行干预。如 git hook 对提交的信息做校验。

抽奖活动

本次活动抽奖规则如下:

首先非常欢迎各位大佬积极评论,也感谢大家对文章的支持。下面是抽奖规则

所有的评论需要符合掘金社区的规范。否则无法参加活动。

评论区随机抽奖,单人最多一个徽章。

若联系不到中奖者,则重新抽取。

抽奖公布时间为:9月12日。

抽奖代码实现

本次抽奖本着公平公正的原则进行抽奖,所以这里贴出JS的抽奖代码。欢迎大家纠错,详细逻辑可以查看下面的代码。

抽奖代码逻辑

    1. 调用掘金文章评论接口获取所有评论用户
    1. Math.random 实现随机获取数组元素
    1. 抽奖并确保两次获奖用户不同
    1. 控制台输出获奖用户

如何使用

打开 Chrome 的控制台,复制粘贴以下代码。控制台输出的用户即为中奖用户。

注意事项:如果你也想使用此抽奖的代码,那么你需要修改 data 中对应的数据。

function choose(choices) {
    var index = Math.floor(Math.random() * choices.length);
    return choices[index];
  }

async function getUserApi(cursor) {

    data = {
        "item_id": "7005444889106186270",
        "item_type": 2,
        "cursor": cursor.toString(),
        "limit": 20,
        "sort": 0,
        "client_type": 2608
    }
    
    obj = await fetch('https://api.juejin.cn/interact_api/v1/comment/list', {
          method: 'POST', body: JSON.stringify(data),
          credentials: "include",
          headers: {
            'Content-type': 'application/json; charset=UTF-8'
          }
        })
        .then(res => {
            obj = res.json()
            return obj
        
        })
    return obj
}
  
async function getAllCommentInfo() {
    cursor = 0
    has_more = true
    result = []
    while (has_more) {
        response = await getUserApi(cursor)
        cursor = response['cursor']
        has_more = response['has_more']
        data = response['data']
        result = [...result, ...data]
    }
    return result
}
  
async function lottery() {
    commentInfo = await getAllCommentInfo()
    userInfo = commentInfo.map(item => item.user_info.user_id + "-" + item.user_info.user_name)

    userInfoDistinct = Array.from(new Set(userInfo))
    user1 = choose(userInfoDistinct)
    user2 = choose(userInfoDistinct)
    
    while (user1 == user2) {
        user2 = choose(userInfoDistinct)
    }

    console.log("抽奖时间为:" + new Date())
    console.log("去重评论数:" + userInfoDistinct.length)
    console.log("恭喜您中奖了 " + user1)
    console.log("恭喜您中奖了 " + user2)
}

lottery()
复制代码
文章分类
后端
文章标签