git获取两个commit之间发生变更的文件

Github的Actions,可以用来做哪些事儿


有同事问我在提pr过程中,有个action执行出错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Run git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/*


git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/*
changed_files=$(git diff --name-only e2734ce287daa04e40ae88edb66a63c79b7591bc 564f5015d1d7fc8229a81d36144372a3c9c63bec -- '*.go')
for file in $changed_files; do
gofmt_output=$(gofmt -l $file)
if [[ -n "$gofmt_output" ]]; then
echo "$file is not formatted correctly. Please run 'go fmt' on this file."
exit 1
fi
done
shell: /usr/bin/bash -e {0}
Error: stat service/winner/winner_raffle.go: no such file or directory
Error: Process completed with exit code 2.

这段是对新提交的代码做gofmt操作,如果gofmt的输出不为空,则不通过该workflow


git diff –name-only e2734ce287daa04e40ae88edb66a63c79b7591bc 564f5015d1d7fc8229a81d36144372a3c9c63bec – ‘*.go’ 什么意思?


这是一个Git命令,用于比较两个提交之间在指定文件类型(此处为.go文件)上的差异。

具体解释如下:

  • git diff是比较两个提交之间差异的命令。
  • --name-only选项告诉Git仅显示文件名,而不显示具体的差异内容。
  • e2734ce287daa04e40ae88edb66a63c79b7591bc564f5015d1d7fc8229a81d36144372a3c9c63bec是两个提交的哈希值或分支名称。这个命令将比较这两个提交之间的差异。
  • '*.go'是一个文件路径模式,用于指定要比较的文件类型为.go文件。只有匹配该模式的文件才会被包括在比较中。

因此,这个命令的意思是:比较提交e2734ce287daa04e40ae88edb66a63c79b7591bc和564f5015d1d7fc8229a81d36144372a3c9c63bec之间在.go文件上的差异,并仅显示文件名。


git diff这一步,会获取这两次提交之间所有改动的文件(其实被删除的文件不要获取,否则go fmt这步就报这错 stat service/xxxxx/xxxxx.go: no such file or directory了)。

可以在for里面做个判断,看看文件是否存在。

或者git diff时直接用 --diff-filter子选项, 来过滤一下D这种情况 explainshell.com

Git做代码增量发布的重要用法 - –diff-filter


gofmt -l 是什么意思?


gofmt -l 是一个用于格式化 Go 代码的命令,其中 -l 是一个选项。

具体解释如下:

  • gofmt 是 Go 语言提供的一个工具,用于格式化和美化 Go 代码的风格。
  • -lgofmt 命令的一个选项,表示以 “list” 的方式输出结果。

当运行 gofmt -l 命令时,它会扫描指定目录中的 Go 代码文件,并输出未按照 Go 语言规范进行格式化的文件列表。如果所有的文件都已按照规范进行格式化,那么不会输出任何结果。

这个命令通常用于检查代码库中是否存在未按照规范格式化的文件。开发者可以运行此命令来确保代码一致性和可读性,并及时发现需要进行格式化的代码文件。


if [[ -n “$gofmt_output” ]]; then… 什么意思?


1
2
3
4
if [[ -n "$gofmt_output" ]]; then
echo "$file is not formatted correctly. Please run 'go fmt' on this file."
exit 1
fi 什么意思?

这是一个bash脚本中的条件语句块,用于检查变量 gofmt_output 是否非空,如果非空则执行相应的操作。

具体解释如下:

  • if [[ -n "$gofmt_output" ]]; then 是一个条件语句块的开始。它检查变量 $gofmt_output 的值是否非空。
  • -n 是一个条件测试标志,用于检查字符串是否非空。
  • "$gofmt_output" 是变量 $gofmt_output 的值,由双引号括起来以处理可能包含空格或其他特殊字符的情况。
  • 如果 $gofmt_output 非空,那么条件为真,接下来的代码块会被执行。
  • echo "$file is not formatted correctly. Please run 'go fmt' on this file." 是一个输出语句,用于打印一条错误消息,指示文件 $file 没有按照正确的格式进行格式化。建议运行 go fmt 命令来格式化该文件。
  • exit 1 是一个退出命令,用于终止脚本的执行并返回一个非零的退出状态码(1),表示脚本执行失败。

因此,这段代码的意思是:如果变量 $gofmt_output 非空,那么输出错误消息并退出脚本,提示用户运行 go fmt 命令来格式化文件 $file


下面这段代码什么意思?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
name: Go FMT

on:
push:
branches:
- main
- dev
pull_request:
branches:
- main
- dev

jobs:
gofmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.19'

- name: Check Formatting of Changed Files
run: |
git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/*
changed_files=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }} -- '*.go')
for file in $changed_files; do
gofmt_output=$(gofmt -l $file)
if [[ -n "$gofmt_output" ]]; then
echo "$file is not formatted correctly. Please run 'go fmt' on this file."
exit 1
fi
done

这是一个使用 GitHub Actions 的工作流程(Workflow),用于在推送(push)或拉取请求(pull request)事件触发时,检查修改的Go文件是否符合格式要求。

具体解释如下:

  • name: Go FMT 是工作流程的名称。
  • on 部分指定了触发工作流程的事件,包括推送到 maindev 分支和拉取请求的目标分支为 maindev
  • jobs 部分定义了一个名为 gofmt 的作业。
  • runs-on: ubuntu-latest 指定了作业在 Ubuntu 环境下运行。
  • steps 是作业的执行步骤列表。

在步骤中:

  • actions/checkout@v3 使用了 actions/checkout 动作,用于检出代码库。
  • actions/setup-go@v4 使用了 actions/setup-go 动作,用于设置 Go 环境。
  • run 步骤中的代码是一个多行脚本,用于检查修改的Go文件的格式。

具体的脚本逻辑如下:

  • git fetch 命令用于获取最新的提交和分支信息。
  • changed_files=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }} -- '*.go') 获取在当前提交和上一次提交之间所修改的 .go 文件列表。
  • 使用 for 循环遍历 $changed_files 中的每个文件。
  • gofmt_output=$(gofmt -l $file) 运行 gofmt 命令检查文件的格式,并将输出结果存储在变量 $gofmt_output 中。
  • if [[ -n "$gofmt_output" ]]; then 检查 $gofmt_output 变量是否非空。
  • 如果 $gofmt_output 非空,则输出错误消息,并使用 exit 1 终止脚本的执行。

因此,这段代码的意思是:当发生推送或拉取请求事件时,检查在当前提交和上一次提交之间修改的所有 .go 文件的格式是否正确。如果发现有文件格式不正确,则输出错误消息并终止工作流程的执行。


@3 @4都是什么?


在工作流程(Workflow)的配置中,@3@4 是引用 GitHub Actions 的特定版本的语法。

  • actions/checkout@v3 表示使用 actions/checkout 动作的版本 v3。@v3 指定了该动作的版本号。
  • actions/setup-go@v4 表示使用 actions/setup-go 动作的版本 v4。@v4 指定了该动作的版本号。

这些版本号用于确保在工作流程运行时使用特定版本的动作。版本号的更新可能包含新功能、修复或改进,为了获得最佳的稳定性和功能性,建议明确指定所需的版本号。

通过指定特定版本的动作,可以确保在将来更新时不会意外引入不兼容或不预期的更改,从而保持工作流程的稳定性和可重复性。


报错: Error: stat service/winner/winner_raffle.go: no such file or directory


这个错误表明在执行 gofmt -l 命令时,找不到指定的文件 service/winner/winner_raffle.go

可能的原因和解决方法如下:

  1. 文件路径错误:请确保指定的文件路径是正确的。检查路径中是否存在拼写错误、大小写错误或其他错误。确认文件路径与实际文件路径完全匹配。

  2. 文件不存在:验证文件是否存在。确保文件 service/winner/winner_raffle.go 实际存在于指定的位置。可以通过使用命令行或文件浏览器来确认文件是否存在。

  3. 工作目录错误:检查脚本中的工作目录是否正确设置。确保脚本在正确的目录下执行,以便正确找到文件。

  4. 修改未提交:如果文件是最新修改的但尚未添加到Git提交中,gofmt 命令可能无法找到未提交的文件。请确保在运行 gofmt 命令之前将文件添加到Git提交中。

请根据具体情况检查并尝试解决上述问题,以确保指定的文件存在且路径正确。


git diff 如何能看出是新增,修改还是删除?


通过 git diff 命令的输出,可以根据行首的符号来判断是文件的新增、修改还是删除。

git diff 的输出中,每个修改的行都以一个符号开头,表示其更改类型:

  • + 表示新增的行。
  • - 表示被删除的行。
  • 空格 表示被修改的行。

例如,以下是 git diff 输出的示例:

1
2
3
4
5
6
7
8
9
10
diff --git a/file.txt b/file.txt
index abcdefg..1234567 100644
--- a/file.txt
+++ b/file.txt
@@ -1,3 +1,4 @@
Line 1
-Line 2
+Modified Line 2
+Added Line 3
Line 4

在上述示例中,可以看到:

  • - 行表示被删除的行,如 Line 2
  • + 行表示新增的行,如 Added Line 3
  • 空格行表示被修改的行,如 Modified Line 2

通过观察行首的符号,您可以确定每个行的更改类型,从而判断文件中的新增、修改和删除操作。


git 如何获取两次提交之间新增或修改了哪些文件?


要获取两次提交之间新增或修改了哪些文件,可以使用 git diff 命令来比较两个提交之间的差异。

以下是使用 git diff 命令获取两次提交之间新增或修改的文件的示例:

1
git diff --name-only <commit1> <commit2>

在上述命令中,<commit1><commit2> 是要比较的两个提交的引用,可以是提交哈希、分支名称或其他引用。

该命令的输出将显示两个提交之间差异的文件列表,只包括文件名,每个文件名占据一行。

例如,以下是获取两次提交之间新增或修改的文件的示例输出:

1
2
3
file1.txt
dir/file2.txt
file3.js

上述输出表示在两个提交之间新增或修改了 file1.txtdir/file2.txtfile3.js 这三个文件。

通过解析 git diff 命令的输出,您可以获取到两次提交之间新增或修改的文件列表。


但如果删除的话,是不是也会被涵盖进来


是的,使用 git diff 命令时,默认情况下,删除的文件也会包含在差异中。

如果您想要排除已删除的文件,可以使用 --diff-filter 参数来过滤差异的类型。

以下是使用 git diff 命令获取两个提交之间新增或修改的文件,并排除已删除的文件的示例:

1
git diff --name-only --diff-filter=AM <commit1> <commit2>

在上述示例中,--diff-filter=AM 参数指定了只包含新增(Added)和修改(Modified)的文件,并排除已删除(Deleted)的文件。

A 表示新增的文件,M 表示修改的文件,D 表示已删除的文件。

这样,输出的文件列表将只包含新增或修改的文件,而已删除的文件将被排除在外。

请注意,如果想要获取新增、修改和删除的文件列表,可以将 --diff-filter 参数设置为 ADM,即 --diff-filter=ADM。这将包含所有类型的差异文件。