我和消失的change-id之间的恩怨情仇

问题:git 提交无法自动生成change-id

        git push时报错,显示没有change-id

解决

方法1. 确保commit-msg正常拉取(未解决)

        change-id是通过hooks/commit-msg这个文件自动成的,上图的报错提示也很明显,它想让你重新拉取这个commit-msg文件来生成change-id。

1.1 重新拉取commit-msg

    # 将xxx修改为你的姓名
    gitdir=$(git rev-parse --git-dir); scp -p -P 29418 xxx@gerrit.cmss.com:hooks/commit-msg ${gitdir}/hooks/

    git commit --amend --no-edit

    # 重新提交
    git push origin HEAD:refs/for/develop

        网上绝大部分方法都是这么做,但这个方法对我不奏效,推送时仍然报没有change-id。

        替换别的有用的commit-msg、甚至替换hooks也不奏效。

        看来问题不在commit-msg文件上。

1.2. 拉项目时确保commit-msg正常拉取

git clone "ssh://xxx@gerrit.cmss.com:29418/项目名" && scp -p -P 29418 xxx@gerrit.cmss.com:hooks/commit-msg "项目名/.git/hooks/"

如clone代码时没clone下来,请把 scp -p -P 改成  scp -O -P

git clone "ssh://xxx@gerrit.cmss.com:29418/项目名" && scp -O -P 29418 xxx@gerrit.cmss.com:hooks/commit-msg "项目名/.git/hooks/"

方法2. 手动写一个change-id(未解决)

        因为change-id本质也是一串字符串,是gerrit用来标识一次变更的。

        所以我在上次提交的change-id基础上改几个数字或者字符,提交上去。

        这个方法在试了几次也不生效了。

        由于同一个项目我copy了几份,在删掉一些复制的文件夹后突然能正常提交了,不知道是否和这个原因相关。

方法3. 删除husky(解决)

        1. 拉取项目文件,正常npm  install后

         2.把项目目录下,.git/config文件中 huskyPath = .husky 删除        

        3. 删除package.json里husky相关的两行代码

可以正常提交。

看来问题就出在这个husky身上,为了弄懂原因,我也是费劲查了好久。

Husky是如何影响change-id生成的

Git hooks

        首先我们知道,Git hooks 是 Git 版本控制系统中的一种机制,它在 Git 执行特定操作(如提交、合并、推送等)之前或之后自动运行自定义脚本。这些脚本可以用于代码格式化、代码检查、测试验证、安全检查等任务,以保证代码质量。

        Git hooks 配置文件通常存储在仓库的 .git/hooks 目录中,每个钩子都对应一个特定事件。

Husky

        Husky 是一个 Git hooks 管理工具,开发者在 package.json 文件中配置 Git hooks,而不是直接在 .git/hooks 目录中写脚本。这样多人开发时,Husky配置会随着项目一起被克隆和分发,使得Git hooks更加容易维护和管理。

        对于Husky的详细工作原理,请参考文末链接。

   Husky具体要使用什么文件进行git的管理和配置,可以在.git/config文件指明。

[core]
	repositoryformatversion = 0
	filemode = false
	bare = false
	logallrefupdates = true
	symlinks = false
	ignorecase = true
    hooksPath = .husky

首先明确,.git/config下的core.hooksPath的优先级比.git/hooks高,在配置中修改了core.hooksPath指向为.husky后,将会使用.husky代替.git/hooks目录下的钩来进行检查。

.husky
├── .gitignore # 忽略 _ 目录
└── _
    └── husky.sh

husky.sh文件

来看一下husky.sh文件

#!/bin/sh
if [ -z "$husky_skip_init" ]; then
  debug () {
    # 当 HUSKY_DEBUG 存在值为1时,开启debug
    [ "$HUSKY_DEBUG" = "1" ] && echo "husky (debug) - $1"
  }

  readonly hook_name="$(basename "$0")"
  debug "starting $hook_name..."
  # 如果 HUSKY=0,则忽略hook
  if [ "$HUSKY" = "0" ]; then
    debug "HUSKY env variable is set to 0, skipping hook"
    exit 0
  fi
  # 如果存在~/.huskyrc,则执行
  if [ -f ~/.huskyrc ]; then
    debug "sourcing ~/.huskyrc"
    . ~/.huskyrc
  fi
  # 设置husky_skip_init=1,再次执行hook时不再进入该代码块
  export readonly husky_skip_init=1
  # 再次执行当前hook,其中的$0为hook路径,$@为所有参数
  sh -e "$0" "$@"
  exitCode="$?"

  if [ $exitCode != 0 ]; then
    # 打印hook执行失败信息
    echo "husky - $hook_name hook exited with code $exitCode (error)"
    exit $exitCode
  fi

  exit 0
fi

从文件中,我们可以得知如下信息:

1. 设置HUSKY_DEBUG=1开启husky的debug

# 直接在终端设置变量值,也可以在~/.bash_profile中设置为全局环境变量
HUSKY_DEBUG=1
# 执行中指定变量值
HUSKY_DEBUG=1 git commit -m "this is msg"

2. 设置HUSKY=0跳过hooks的执行,使用方法同HUSKY_DEBUG。

3. 可以通过~/.huskyrc在hook执行前执行一些命令,该文件可以自己创建。

该文件也是通过. ~/.huskyrc执行的,如果在该文件中exit 0或者exit 1都会直接结束hook,前者表示正常执行,后者表示执行失败。

husky.sh有如下的执行流程:

1. 执行hook;

2. 执行husky.sh,此时husky_skip_init=,因此执行判断内部代码。

3. husky.sh中设置husky_skip_init=1并通过sh -e "$0" "$@"再一次执行当前hook,此时因为husky_skip_init=1跳过判断内部代码,执行hooks剩余代码。

从代码上来看,这个有点绕的流程是为了获取到hook执行的结果,并在debug模式下输出。

.huskyrc文件(重点)

其中在.husky/_/husky.sh中指明:如果存在~/.huskyrc文件,则执行它。

~/.huskyrc的作用你可以理解为代替了 .git/hooks 目录下的钩子文件进行代码检查。

通过 .huskyrc 文件,可以定义各种 Git 钩子,例如 pre-commit、commit-msg 等,并指定在这些钩子触发时执行的脚本。这样,每当进行相应的 Git 操作时,Husky 会自动运行这些脚本,从而实现代码检查等功能. 

  # 如果存在~/.huskyrc,则执行
  if [ -f ~/.huskyrc ]; then
    debug "sourcing ~/.huskyrc"
    . ~/.huskyrc
  fi

看下这个逻辑

core.hooksPath = .husky 让我们去找.husky/_/husky.sh文件

 .husky/_/husky.sh 又指明起作用的是 .huskyrc文件

最后重点落到了 .huskyrc文件身上,而 ~/.huskyrc可以看到这是Linux系统的写法,它在找用户目录下的.huskyrc文件,我Windows系统铁是找不到这个文件的。

可以测试下:

  if [ -f ~/.huskyrc ]; then
    debug "sourcing ~/.huskyrc"
    . ~/.huskyrc
  fi

  # 增加测试代码如下:
  if [ ! -f ~/.huskyrc ]; then
    # 若找不到.huskyrc文件,则打印以下信息
    echo "--------------------huskyrc does not exist--------------."
  fi

在文件目录下执行该文件,发现确实找不到huskyrc文件:

$ ./husky.sh

--------------------huskyrc does not exist--------------.

此时谜底揭开,就是因为代码提交时没有找到huskyrc文件,而huskyrc文件理应包含各种自定义钩子,这些钩子当然也包含生成change-id的功能。

都是这个huskyrc的锅!

知道了原因就很好解决了,要么配置个huskyrc文件,要么直接禁用掉husky使用原来的.git/hooks进行检查(前文方法3)。

参考文档:

 Husky的详细工作原理:

Git Hooks 与 Husky 原理解析与应用 | 山月行 (shanyue.tech)

在Git项目中使用husky统一管理hooks - 个人文章 - SegmentFault 思否

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值