Git“预接收”挂钩和“git-clang-format”脚本可以可靠地拒绝违反代码风格约定的推送

2024-04-27

让我们立即从一个片段开始pre-receive我已经写过的钩子:

#!/bin/sh
##
  format_bold='\033[1m'
   format_red='\033[31m'
format_yellow='\033[33m'
format_normal='\033[0m'
##
  format_error="${format_bold}${format_red}%s${format_normal}"
format_warning="${format_bold}${format_yellow}%s${format_normal}"
##
stdout() {
  format="${1}"
  shift
  printf "${format}" "${@}"
}
##
stderr() {
  stdout "${@}" 1>&2
}
##
output() {
  format="${1}"
  shift
  stdout "${format}\n" "${@}"
}
##
error() {
  format="${1}"
  shift
  stderr "${format_error}: ${format}\n" 'error' "${@}"
}
##
warning() {
  format="${1}"
  shift
  stdout "${format_warning}: ${format}\n" 'warning' "${@}"
}
##
die() {
  error "${@}"
  exit 1
}
##
git() {
  command git --no-pager "${@}"
}
##
list() {
  git rev-list "${@}"
}
##
clang_format() {
  git clang-format --style='file' "${@}"
}
##
while read sha1_old sha1_new ref; do
  case "${ref}" in
  refs/heads/*)
    branch="$(expr "${ref}" : 'refs/heads/\(.*\)')"
    if [ "$(expr "${sha1_new}" : '0*$')" -ne 0 ]; then # delete
      unset sha1_new
      # ...
    else # update
      if [ "$(expr "${sha1_old}" : '0*$')" -ne 0 ]; then # create
        unset sha1_old
        sha1_range="${sha1_new}"
      else
        sha1_range="${sha1_old}..${sha1_new}"
        # ...
        fi
      fi
      # ...
             GIT_WORK_TREE="$(mktemp --tmpdir -d 'gitXXXXXX')"
      export GIT_WORK_TREE
             GIT_DIR="${GIT_WORK_TREE}/.git"
      export GIT_DIR
      mkdir -p "${GIT_DIR}"
      cp -a * "${GIT_DIR}/"
      ln -s "${PWD}/../.clang-format" "${GIT_WORK_TREE}/"
      error=
      for sha1 in $(list "${sha1_range}"); do
        git checkout --force "${sha1}" > '/dev/null' 2>&1
        if [ "$(list --count "${sha1}")" -eq 1 ]; then
          # What should I put here?
        else
          git reset --soft 'HEAD~1' > '/dev/null' 2>&1
        fi
        diff="$(clang_format --diff)"
        if [ "${diff%% *}" = 'diff' ]; then
          error=1
          error '%s: %s\n%s'                                                   \
                'Code style issues detected'                                   \
                "${sha1}"                                                      \
                "${diff}"                                                      \
                1>&2
        fi
      done
      if [ -n "${error}" ]; then
        die '%s' 'Code style issues detected'
      fi
    fi
    ;;
  refs/tags/*)
    tag="$(expr "${ref}" : 'refs/tags/\(.*\)')"
    # ...
    ;;
  *)
    # ...
    ;;
  esac
done
exit 0

NOTE:
不相关代码的地方会被删除# ....

NOTE:
如果您不熟悉git-clang-format, 看一看here http://llvm.org/svn/llvm-project/cfe/trunk/tools/clang-format/git-clang-format.

该钩子按预期工作,到目前为止,我没有发现任何错误,但如果您发现任何问题或有改进建议,我将不胜感激。也许,我应该对这个钩子背后的意图发表评论。嗯,它确实检查每个推送的修订版本是否符合代码风格约定,使用git-clang-format,如果其中任何一个不符合,它将为每个输出输出相关的差异(告诉开发人员应该修复什么)。基本上,我有两个关于这个钩子的深入问题。

首先,请注意,我将远程(服务器)裸存储库复制到某个临时目录,并在那里检查代码以进行分析。让我解释一下这样做的意图。请注意,我做了几个git checkouts and git resets(由于for循环)以便单独分析所有推送的修订git-clang-format。我在这里试图避免的是推送访问远程(服务器)裸存储库时出现的(可能的)并发问题。也就是说,我的印象是,如果多个开发人员尝试使用此方法同时推送到远程pre-receive安装了钩子,如果每个推送“会话”不执行,可能会导致问题git checkouts and git resets 及其存储库的私有副本。所以,简单来说,git-daemon是否有针对并发推送“会话”的内置锁管理?是否会执行相应的pre-receive严格按顺序挂钩实例还是有可能交错(这可能会导致未定义的行为)?有些东西告诉我,应该有一个内置的解决方案来解决这个问题并提供具体的保证,否则远程设备在并发推送时一般如何工作(即使没有复杂的钩子)?如果有这样的内置解决方案,那么副本就是多余的,简单地重用裸存储库实际上会加快处理速度。顺便说一句,非常欢迎任何有关此问题的官方文档的参考。

Second, git-clang-format仅处理staged(但未提交)更改与特定提交(HEAD默认情况下)。因此,您可以轻松地看到极端情况所在。是的,它与root提交(修订)。实际上,git reset --soft 'HEAD~1'无法应用于根提交,因为它们没有可以重置的父级。因此,对我的第二个问题进行以下检查:

        if [ "$(list --count "${sha1}")" -eq 1 ]; then
          # What should I put here?
        else
          git reset --soft 'HEAD~1' > '/dev/null' 2>&1
        fi

我试过了git update-ref -d 'HEAD'但这会破坏存储库git-clang-format无法再处理它了。我相信这与以下事实有关:所有这些正在分析的推送修订(包括这个根修订)实际上并不属于任何分支。也就是说,他们在detached HEAD状态。找到这个极端情况的解决方案也是完美的,这样initial提交也可以接受相同的检查git-clang-format以符合代码风格约定。

Peace.


NOTE:
对于那些寻找最新的、(或多或少)全面且经过充分测试的解决方案的人,我托管相应的公共存储库 [1 http://bitbucket.Alexander.Shukaev.name/git-hooks]。目前,两个重要的钩子依赖于git-clang-format已实施:pre-commit and pre-receive。理想情况下,同时使用它们时,您可以获得最自动化和最简单的工作流程。与往常一样,我们非常欢迎提出改进建议。

NOTE:
目前,pre-commit hook [1 http://bitbucket.Alexander.Shukaev.name/git-hooks] 要求git-clang-format.diff补丁(也是我写的)[1 http://bitbucket.Alexander.Shukaev.name/git-hooks] 应用于git-clang-format。该补丁的动机和用例示例总结在提交给 LLVM/Clang 的官方补丁审查中 [2 http://reviews.llvm.org/D15465]。希望它很快就会被上游接受并合并。


我已经设法实现第二个问题的解决方案。我不得不承认,由于 Git 文档稀少且缺乏示例,所以很难找到它。我们先看一下对应的代码改动:

# ...
clang_format() {
  git clang-format --commit="${commit}" --style='file' "${@}"
}
# ...
      for sha1 in $(list "${sha1_range}"); do
        git checkout --force "${sha1}" > '/dev/null' 2>&1
        if [ "$(list --count "${sha1}")" -eq 1 ]; then
          commit='4b825dc642cb6eb9a060e54bf8d69288fbee4904'
        else
          commit='HEAD~1'
        fi
        diff="$(clang_format --diff)"
        # ...
      done
      # ...

正如你所看到的,而不是重复做git reset --soft 'HEAD~1',我现在明确指示git-clang-format进行操作HEAD~1--commit选项(而其默认值是HEAD这在我的问题中提出的初始版本中有所暗示)。然而,这仍然不能单独解决问题,因为当我们遇到root提交这将再次导致错误,如下所示HEAD~1将不再引用有效的修订版(类似于不可能执行的操作)git reset --soft 'HEAD~1')。这就是为什么对于这个特殊情况,我指示git-clang-format对抗(魔法)4b825dc642cb6eb9a060e54bf8d69288fbee4904 hash [3 http://colinschimmelfing.com/blog/gits-empty-tree/, 4 https://stackoverflow.com/q/9765453/1743860, 5 http://git.wiki.kernel.org/index.php/Aliases#Obtaining_the_Empty_Tree_SHA1, 6 http://comments.gmane.org/gmane.comp.version-control.git/180511]。要了解有关此哈希的更多信息,请查阅参考资料,但简而言之,它指的是 Git空树对象— 没有任何上演或承诺的内容,这正是我们所需要的git-clang-format在我们的例子中进行操作。

NOTE:
你不必记住4b825dc642cb6eb9a060e54bf8d69288fbee4904用心记住,最好不要对其进行硬编码(以防万一这个神奇的哈希值将来会发生变化)。事实证明,它总是可以检索git hash-object -t tree '/dev/null' [5 http://git.wiki.kernel.org/index.php/Aliases#Obtaining_the_Empty_Tree_SHA1, 6 http://comments.gmane.org/gmane.comp.version-control.git/180511]。因此,在我上述的最终版本中pre-receive钩子,我有commit="$(git hash-object -t tree '/dev/null')"反而。

P.S.我仍在寻找第一个问题的高质量答案。顺便说一句,我在官方 Git 邮件列表上提出了这些问题,但到目前为止还没有收到答案,真是遗憾......

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Git“预接收”挂钩和“git-clang-format”脚本可以可靠地拒绝违反代码风格约定的推送 的相关文章

  • “本地存储库已过时”....我没有分支如何解决这个问题

    当我们将代码推送到远程服务器时 Xcode 显示以下警告 另请参阅随附的屏幕截图 本地存储库已过时 我没有分支或任何其他工作副本 我有同样的问题 我是这样解决的 首先进入终端中的项目目录 git init git add git stash
  • 错误:获取远程存储库“origin”时出错,返回状态代码-1:

    我在 Windows 上运行 Jenkins 当我尝试通过 jenkins 构建我的项目时 出现以下错误 git exe c core askpass true fetch tags progress
  • 樱桃选择问题:还应用了之前提交的更改

    在我的项目中 我几个月前发布了一个版本 在该版本发布之后 我在 master 分支上做了很多更改 如果我遇到上一个版本中存在的一些错误 我会在主分支上修复它们 然后将它们挑选到我在上一个版本中创建的分支 然后我可以提供一个仅包含错误修复的新
  • git push origin master 失败

    我正在尝试将现有文件夹上传到 gitHub 按照说明 我在 Windows 中输入了以下内容 git remote add origin email protected cdn cgi l email protection myname m
  • 无法通过 HTTPS 克隆私有 Github 存储库

    我在通过 HTTPS 克隆私有 GitHub 存储库时遇到问题 如果我尝试使用以下方式克隆我的存储库 git clone https github com username repository 我收到错误 fatal remote err
  • GIT Rebase 对多个 0.5GB 二进制文件致命

    这个问题本质上是重新开rebase 期间 git 崩溃 https stackoverflow com q 7692944 1286639从来没有答案 我正在尝试从我的 secc 分支进行变基 git rebase main First r
  • git 交互式变基:停止而不提交

    长话短说 有办法进去吗git rebase i停止编辑 没有提交 ID TLDR 更长的版本 背景 With git rebase i 我得到一个文本编辑器 我可以在其中定义命令列表 从pick COMMIT ID在每一行上 其中一个选项是
  • git-svn 期间“RA 层请求失败:REPORT 请求失败”

    我一直在尝试使用以下命令 Git 克隆 Google Code SVN 存储库 git svn clone stdlayout https wtorrent project googlecode com svn wtorrent git 它
  • Azure DevOps/VSTS 始终在干净的存储库上报告“DETACHED HEAD”

    Friends 我现在厌倦了 Azure DevOps VSTS Jenkins 好多了 现在仍然如此 只是我的组织想要使用 Azure DevOps 我有一个谜团需要帮助来解决 以下是我的笔记本电脑上的存储库 它没有未跟踪或未提交的更改
  • 如何只应用一种 clang-format 操作?

    我想用clang 格式调整我的评论 但仅此而已 选项是 AlignTrailingComments bool 但是当我运行以下命令时 clang format 3 6 i style AlignTrailingComments true
  • 如何解决 npm install 中的身份验证错误?

    在我的 package json 中 我有一个名为 somerepo git 的私人存储库 现在我通过 maven 在 buildserver bamboo 上运行 npm install 并收到此错误 ERROR npm ERR Comm
  • 使用 'gitbranch' 命令显示当前 git 分支

    我在处理太多分支时遇到问题 需要花费很多时间才能找到我现在正在处理的当前分支 有没有办法在使用时显示的列表顶部列出当前分支git branch命令 如果您只想要签出分支 请使用git branch show current
  • GitHub Web UI 中的“base”和“head”存储库是什么?

    GitHub 的 UI 相当不直观且考虑不周 所以这里有一个问题 什么是 头 回购 什么是 基础 回购 不知道是从哪一个抄来的 基础 和 头部 这两个词的意思是相同的 链表的 头 类似于树的 基 GitHub 有叉树和文件树 Head 和
  • 克隆存储库时出现 Git 冲突复制错误

    我使用 dropbox 作为 git 存储库 现在由于同步中的一些问题 git 中存在一些冲突的副本 我该如何消除这种冲突 由于这种冲突 我无法克隆该存储库的内容 我在克隆存储库时遇到的错误是 Git 致命 参考格式无效 refs head
  • 如何在Windows Git shell中运行./script.sh?

    也许这很尴尬 但是当我在 Git shell 中工作时 我无法在 Windows 上运行 sh 文件 也许我必须安装一些东西 但我认为 Git 会支持 bash 命令 我知道 Windows 不使用 sh 文件 我正在执行安装步骤游戏结束
  • 将新更新从原始 GitHub 存储库提取到分叉的 GitHub 存储库

    我在 GitHub 上分叉了某人的存储库 并希望使用原始存储库中的提交和更新来更新我的版本 这些是在我分叉我的副本后制作的 如何提取在源中所做的更改并将它们合并到我的存储库中 您必须将原始存储库 您分叉的存储库 添加为远程存储库 来自有关分
  • 无法使用 File delete() 方法删除 git repo 中的 .pack 文件

    对于我正在编写的这个方法 我使用 jgit 库克隆一个 git 存储库 然后对这些文件执行一些操作 最后我想删除该存储库 我遇到的问题是 当我在 pack 文件 位于 git objects pack 中 上调用 delete 方法时 它无
  • Git推送更新远程服务器信息失败

    当我尝试将新分支推送到远程源时 出现以下错误 我能够在现有分支上推送提交 并且现有分支上没有问题 git push u origin master1 Fetching remote heads refs refs tags refs hea
  • Github README.md 和 readme.md - 如何删除其中一个?

    不知何故 我最终在 github 上有了 README md 和 readme md 现在这两者相互影响 所以我的 GitHub app 完全混乱了 Github网站没有任何文件删除功能 如何删除这些文件之一 只需删除其中一个文件并提交删除
  • 子 shell 何时继承其父 shell 环境?

    什么情况下将shell的环境传递给子shell 子 shell 始终从父 shell 获取所有变量 man bash将描述所有使用子shell的情况 主要是 command command command and command 所谓环境只

随机推荐

  • 我们如何找到 C# 整数数组中的项目计数?

    我需要在 C 数组中查找类型为整数的项目计数 我的意思是 int intArray new int 10 int 0 34 int 1 65 int 2 98 intArray 的项目计数为 3 我在下面找到了 strArray 的代码 但
  • C#:模拟内存泄漏

    我想用c 编写以下代码 a 模拟内存泄漏的小型控制台应用程序 b 小型控制台应用程序 它将调用上述应用程序并立即释放它 模拟管理内存泄漏问题 换句话说 应用程序 b 将不断调用并释放应用程序 a 以模拟如何遏制 叛逆 内存泄漏应用程序 而不
  • 更新jqGrid中的数据

    我在这种情况下使用 jqGrid 网格从第一个 URL 获取 JSON 数据 如果 URL 返回正确的 JSON 网格会显示该数据 如果 URL 返回不正确的数据 则会触发 grid 的 loadError 事件 在这种情况下 我想将网格的
  • Android JSoup 示例

    我只是想知道是否有人有一个包含 JSoup 的工作实现的示例 Eclipse 项目 我试图用它从网站上获取信息 并在谷歌上到处搜索试图让它工作 但不能 如果有人可以提供帮助 我将非常感激 JSoup 真的很容易使用 看看 JSoup 食谱中
  • 将比其父级更宽的 div 居中,而不设置负左边距

    我有一个div里面有一个div 里面的 div 比它的父级宽 所以正常的过程 margin left auto margin right auto 生成一个内部 div 其中子级的左边缘与父级的左边缘对齐 当人们回答这个问题时 他们通常会采
  • Android 上的 iptables 1.4.11

    我已经从以下位置下载了 Android 内核源代码http source android com source building kernels html http source android com source building ke
  • 将 jbyteArray 转换为字符数组,然后打印到控制台

    我正在编写一个 JNI 程序 其中我的 cpp 文件获取 jbyteArray 并且我希望能够使用 printf 打印 jbyteArray 为此 我相信我必须将 jbyteArray 转换为字符数组 对于背景知识 我的 JNI 的 jav
  • 使最后一个动态添加的手风琴打开

    我正在尝试添加引导程序手风琴 https v4 alpha getbootstrap com components collapse accordion example以编程方式 以便每次单击 添加 按钮时 都会生成一个新的手风琴 并关闭前
  • 将文本文件与 C# 中的文本模式进行比较?

    我将文本文件与类似的模式进行了比较 它正在将整行写入日志 如下所示 insert into depdb fin quick code met 但我需要单独写这个depdb或者depdb fin quick code met 即 我只需要这个
  • 在下载的同时从 UnityWebRequest 获取数据?

    我有这段代码可以进行 REST 调用 public IEnumerator GetCooroutine string route string finalURL URL route UnityWebRequest www UnityWebR
  • 树视图上的 VirtualizingStackPanel 不是虚拟化

    我在这里遇到一个问题 我想在 TreeView 中显示一些项目 大约 100 000 个元素 如果我使用默认的 WPF TreeView 一切似乎都可以工作 但如果我使用自定义 TreeView 目前只有 ItemsControl 虚拟化似
  • 何时在 VBA 中使用 TextFrame 或 TextFrame2

    例如 在 Powerpoint 中 文本框对象 http msdn microsoft com en us library office bb265592 28v office 12 29 aspx 表示 Shape 对象中的文本框架 包含
  • NAudio 音调变换

    我正在使用 NAudio DLL 并且正在寻找音调变换声音的示例代码 有一个使用的例子NAudio https github com naudio NAudio用于开源中的音高变换Skype 变声器 https github com mar
  • 如何远程获取系统的网络共享和连接?

    我正在寻找一种远程获取类似于以下控制台应用程序的信息的方法 net use 净份额 网络统计 ano 但是 我需要能够在系统上运行第三方应用程序的情况下执行此操作 这有效地排除了使用 psexec 远程执行命令 因为 psexec 将作为服
  • .NET:十进制到舍入字符串

    如果我有一个decimal 如何获得带有两位小数的字符串版本 这不起作用 Math Round myDecimal 2 ToString 0 00 不要使用大括号 它们用于使用以下命令将格式化值嵌入到较长的字符串中string Format
  • Swift NSSet 和 CoreData

    我正在尝试将目标 C 和 CoreData 应用程序移动到 Swift 和 iOS 但在迭代 NSSet 对象时遇到了困难 Xcode 已生成这些类 class Response NSManagedObject NSManaged var
  • ruby 2.0.0 捆绑包在 Gemfile 上失败并显示“key: value”

    我正在尝试使用 Gemfile 更新我的 gem 但总是在同一行失败 Gemfile group doc do gem sdoc require false end Command bundle update 我总是收到这个错误 Gemfi
  • 对齐顶部两个具有不同字体大小的文本视图

    我使用约束布局 我想实现以下目标 app layout constraintBaseline toBaselineOf 属性底部对齐两个文本视图 有什么方法可以使两个顶部对齐吗 由于大小差异 常规的 app layout constrain
  • 为什么枚举可以有包私有构造函数?

    既然枚举构造函数只能由其常量调用 为什么允许它是包私有的呢 构造函数实际上不是包私有的 它是隐式的private接口方法的隐式方式public即使您不添加关键字 JLS 的相关部分 8 8 3 http docs oracle com ja
  • Git“预接收”挂钩和“git-clang-format”脚本可以可靠地拒绝违反代码风格约定的推送

    让我们立即从一个片段开始pre receive我已经写过的钩子 bin sh format bold 033 1m format red 033 31m format yellow 033 33m format normal 033 0m