从脚本确定 Git 工作目录是否干净

bre*_*son 154 git shell-script

我有一个rsync以 Git 工作目录作为目标运行的脚本。我希望脚本根据工作目录是否干净(没有更改提交)而具有不同的行为。例如,如果输出git status如下,我希望脚本退出:

git status
Already up-to-date.
# On branch master
nothing to commit (working directory clean)
Everything up-to-date
Run Code Online (Sandbox Code Playgroud)

如果目录不干净,那么我希望它执行更多命令。

如何在 shell 脚本中检查上述输出?

Tho*_*man 235

解析 的输出git status是一个坏主意,因为输出旨在是人类可读的,而不是机器可读的。无法保证在未来版本的 Git 或不同配置的环境中输出将保持不变。

UVVs 注释在正确的轨道上,但不幸的是git status,当有未提交的更改时,返回代码不会更改。它,然而,提供的--porcelain选项,这将导致输出git status --porcelain在一个易于解析格式脚本来进行格式化,仍将是跨版本的Git稳定,无论用户配置的。

我们可以使用空输出git status --porcelain作为没有要提交的更改的指示符:

if [ -z "$(git status --porcelain)" ]; then 
  # Working directory clean
else 
  # Uncommitted changes
fi
Run Code Online (Sandbox Code Playgroud)

如果我们不关心工作目录中未跟踪的文件,我们可以使用--untracked-files=no选项忽略那些:

if [ -z "$(git status --untracked-files=no --porcelain)" ]; then 
  # Working directory clean excluding untracked files
else 
  # Uncommitted changes in tracked files
fi
Run Code Online (Sandbox Code Playgroud)

为了使其在没有输出到 的情况下实际导致git status失败的情况下更加稳健stdout,我们可以将检查细化为:

if output=$(git status --porcelain) && [ -z "$output" ]; then
  # Working directory clean
else 
  # Uncommitted changes
fi
Run Code Online (Sandbox Code Playgroud)

还值得注意的是,虽然git status在工作目录不干净时没有给出有意义的退出代码,但git diff提供了--exit-code选项,这使得它的行为类似于diff实用程序,即1在存在差异和0没有发现差异时以状态退出。

使用它,我们可以检查未暂存的更改:

git diff --exit-code
Run Code Online (Sandbox Code Playgroud)

并已上演但未提交的更改:

git diff --cached --exit-code
Run Code Online (Sandbox Code Playgroud)

虽然git diff可以通过适当的参数报告子模块中未跟踪的文件--ignore-submodules,但不幸的是,似乎没有办法让它报告实际工作目录中未跟踪的文件。如果工作目录中未跟踪的文件是相关的,git status --porcelain则可能是最好的选择。

  • 呃,即使存在未为提交和未跟踪文件暂存的更改,`git status --porcelain` 也会以代码 0 退出。 (9认同)
  • @AlexanderMills:我观察到了同样的情况。但随后检查了`if [ -z` 在做什么。`-z` 表示如果以下字符串为空,则 if 评估为 `true`。换句话说,如果这个 `git status --porcelain` 没有产生任何字符串,那么这个 repo 就是干净的。如果没有,它会列出修改/添加/删除的文件,不再是空字符串。`if` 然后评估为 `false`。 (5认同)
  • 如果您只想要退出代码,请使用“git diff --quiet --exit-code” (5认同)
  • 我发现“git diff --quiet”(根据手册页也暗示了“--exit-code”)如果有更改则返回“256”,如果不在 git 树中则返回“33024”,以及其他各种高数字不同的错误条件。我想知道是否可以通过不同版本的 git 来依赖值“256”? (2认同)

小智 39

用:

git diff-index --quiet HEAD
Run Code Online (Sandbox Code Playgroud)

返回码反映了工作目录的状态(0 = 干净,1 = 脏)。未跟踪的文件将被忽略。

  • 当前目录中有未跟踪的文件时返回 0。 (13认同)
  • 如果文件已被触摸/覆盖但在其他方面与索引相同,则需要先运行“git update-index --refresh”,然后再运行“git diff-index HEAD”。更多信息:/sf/ask/2436558001/ (3认同)

ori*_*zil 6

Andr\xc3\xa9\'s优秀答案的小扩展。

\n

未跟踪的文件将被忽略。

\n
git update-index --really-refresh\nif git diff-index --quiet HEAD\nthen\n  GIT_MODS="clean"\nelse\n  GIT_MODS="dirty"\nfi\n
Run Code Online (Sandbox Code Playgroud)\n

如果你想避免在 stdout 中放入东西,你可能需要添加>> /dev/null或类似的就行了update-index

\n

  • 访问 `$?` 不如直接在命令上使用 `if`:`if ! git diff-index --quiet HEAD; 那么`。然而,这种方法并不是 100% 可靠,如果您不首先运行 git update-index --really-refresh ,就会出现潜在的误报“脏”结果。要查看此操作的实际情况,请“触摸”现有提交的文件以仅更新其日期,然后您将看到来自“diff-index”的非零返回代码,即使实际上没有任何更改。 (5认同)

Cam*_*son 5

如果您只想要 0 或 1 进程退出代码,那么您可以在块之外运行测试if-then

#!/bin/bash

[ -z "$(git status --porcelain)" ]

Run Code Online (Sandbox Code Playgroud)

或者

#!/bin/bash

test -z "$(git status --porcelain)"

Run Code Online (Sandbox Code Playgroud)

例子:

$ test -z "$(git status --porcelain)"
$ echo $?
0

$ echo 'hello world' > fish.txt
$ test -z "$(git status --porcelain)"
$ echo $?
1
Run Code Online (Sandbox Code Playgroud)