我可以运行 `git status` 并将输出通过 `grep` 管道处理,但我觉得应该有更好的方法。
更新:
其他使用瓷器的方法假设你在bash中,这不是跨shell或跨平台兼容的。
这个方法在任何地方都适用:git add . && git diff --quiet && git diff --cached --quiet
看起来它可以捕捉到我需要的每一种情况(包括未跟踪的文件和具有未暂存修改的git子模块,而
git add .
不会暂存)
楼主Daniel Stutzbach在评论中指出这个简单的命令git diff-index
对他有效:
git update-index --refresh
git diff-index --quiet HEAD --
git status --porcelain=v1 2>/dev/null | wc -l
进行测试,使用porcelain
选项。git diff-index
之前,需要先运行git update-index --refresh
,否则diff-index
会错误地报告树的状态为脏)git diff-index --quiet HEAD -- || echo "untracked"; // do something about it
而
git diff-index HEAD ...
在没有提交的分支上会失败(例如新初始化的存储库)。 我找到的一个解决方法是git diff-index $(git write-tree) ...
haridsv
在评论中指出,对于一个新文件,git diff-files
无法检测到差异。git add
,然后使用git diff-index
来查看是否有任何内容添加到索引中,然后再运行git commit
。
而6502在评论中报告说:git add ${file_args} && \ git diff-index --cached --quiet HEAD || git commit -m '${commit_msg}'
我遇到的一个问题是,
git diff-index
会告诉我有差异,但实际上除了文件的时间戳之外并没有差异。
运行一次git diff
就解决了这个问题(令人惊讶的是,git diff
实际上会改变沙盒的内容,这里指的是.git/index
)
如果git在docker中运行,这些时间戳问题也可能会出现。
原始答案:
“以编程方式”意味着永远不要依赖瓷器命令。
始终依赖管道命令。
另请参阅 "使用Git检查脏索引或未跟踪文件" 以获取替代方案(如git status --porcelain
)
你可以从新的"require_clean_work_tree
函数"中汲取灵感,这个函数是我们说话时编写的 ;)(2010年10月初)
require_clean_work_tree () {
# Update the index
git update-index -q --ignore-submodules --refresh
err=0
# Disallow unstaged changes in the working tree
if ! git diff-files --quiet --ignore-submodules --
then
echo >&2 "cannot $1: you have unstaged changes."
git diff-files --name-status -r --ignore-submodules -- >&2
err=1
fi
# Disallow uncommitted changes in the index
if ! git diff-index --cached --quiet HEAD --ignore-submodules --
then
echo >&2 "cannot $1: your index contains uncommitted changes."
git diff-index --cached --name-status -r --ignore-submodules HEAD -- >&2
err=1
fi
if [ $err = 1 ]
then
echo >&2 "Please commit or stash them."
exit 1
fi
}
git diff-index --quiet HEAD
。 - Daniel Stutzbachgit status --help
手册中指出:
--porcelain
以易于解析的格式输出内容,适用于脚本。这类似于短格式输出,但不受Git版本和用户配置的影响,保持稳定。有关详细信息,请参阅下文。 - Ed Randall虽然其他解决方案非常全面,但如果你想要一个真正快速而简单的方法,可以尝试像这样:
[[ -z $(git status -s) ]]
它只是检查状态摘要中是否有任何输出。
如果[[ -n $(git status -s) ]],那么... fi
- aarongit status -s -uall
命令来包括未被追踪的文件。 - barfuingit status
默认为 all
。从 git status -h
:-u, --untracked-files[=<mode>]
显示未跟踪的文件,可选模式:all、normal、no。(默认值:all)
- calebwoofgit diff --exit-code
会在有任何更改时返回非零值;git diff --quiet
则没有输出。由于您想要检查工作树和索引,所以请使用
git diff --quiet && git diff --cached --quiet
或者
git diff --quiet HEAD
git add
将它们暂存:git add . && git diff --quiet && git diff --cached --quiet
git diff --cached --quiet
命令将捕获那些已经通过 git add .
暂存的未跟踪文件。而 git diff --quiet
命令仍然需要用于捕获具有未暂存更改的 git 子模块,因为 git add .
不会暂存具有修改的 git 子模块。git status --porcelain
),这意味着这些方法在跨平台上不起作用。例如,它们在 Windows PowerShell 中无法工作。&&
的命令在 macOS、Linux 和 Windows 上几乎都适用。这对于 JavaScript 项目的 package.json
文件中的跨平台 NPM 脚本尤其有用。git diff --quite HEAD
只会告诉你工作树是否干净,而不是索引是否干净。例如,如果在 HEAD~ 和 HEAD 之间更改了 file
文件,在执行 git reset HEAD~ -- file
后,即使索引中存在已暂存的更改 (工作树 == HEAD,但索引 != HEAD),它仍将返回 0。 - Chris Johnsengit diff --quiet && git diff --cached --quiet
未能检测到新(未跟踪)文件。 - 4LegsDrivenCatgit add . && git diff --cached --quiet
怎么样? - undefinedgit add . && git diff --cached --quiet
怎么样? - undefinedgit add . && git diff --quiet && git diff --cached --quiet
似乎可以捕捉到我需要的每种情况(包括未跟踪的文件,以及具有未暂存修改的git子模块,git add .
不会暂存)。有没有它捕捉不到的情况? - undefined在@Nepthar's answer的基础上进行扩展:
if [[ -z $(git status -s) ]]
then
echo "tree is clean"
else
echo "tree is dirty, please commit changes before running this"
exit
fi
$(git status -s "$file")
然后在 else
子句中执行 git add "$file"; git commit -m "your autocommit process" "$file"
。 - toddkaufmanngit status -s
改为 git status --porcelain ; git clean -nd
,那么垃圾目录也会被显示出来,而这些目录在 git status
中是看不见的。 - ecmanautgit status --porcelain=v1
并以编程方式解析输出。如果存在未提交的更改,则输出为空,否则不为空。[ -z "$(git status --porcelain=v1 2>/dev/null)" ] && echo "No uncommitted changes."
如果在git仓库之外运行,它仍将显示没有未提交的更改
。
--porcelain
提供了可机器解析的输出。--porcelain=v1
固定了可机器解析的输出版本,以便您的脚本在未来的git
更新中不会出现问题。截至我写这篇文章时,您可以查看https://git-scm.com/docs/git-status获取有关其他版本选项(例如--porcelain=v2
)的信息。您可以使用版本v1
之外的版本进行更高级别的脚本编写。2>/dev/null
是为了使git status
在任何情况下(即在git仓库之外运行时)都能无声地失败。git status ...
将返回退出代码128
,如果它不在git仓库内部。如果您想要第三个选项而不是“未提交的更改”或“没有未提交的更改”,则可以明确检查此退出代码。受这个答案启发。您可以使用grep
命令来查找git status --porcelain=v1
输出的行。每行的前两个字符指示特定文件的状态。在使用grep命令后,通过将输出导入到wc -l
中计算行数来计算该状态的数量。
您可以通过这种方式编写一些更高级的行为,或者选择符合“未提交更改”条件的内容。
例如,如果在git存储库中运行此脚本,则会打印一些信息。
#!/bin/sh
GS=$(git status --porcelain=v1 2>/dev/null) # Exit code 128 if not in git directory. Unfortunately this exit code is a bit generic but it should work for most purposes.
if [ $? -ne 128 ]; then
function _count_git_pattern() {
echo "$(grep "^$1" <<< $GS | wc -l)"
}
echo "There are $(_count_git_pattern "??") untracked files."
echo "There are $(_count_git_pattern " M") unstaged, modified files."
echo "There are $(_count_git_pattern "M ") staged, modified files."
fi
--porcelain
选项:"以易于解析的脚本格式提供输出。这类似于短输出,但将在 Git 版本和用户配置无关的情况下保持稳定。" - Myridiumzsh
进行了测试,对我来说它可以正常工作。你具体在终端输入了什么? - Myridiumgit status --porcelain=v1 2>/dev/null
命令的输出结果吗?你可以删除敏感信息。 - Myridium如果工作区没有任何修改,则称之为“干净的”。
git ls-files \
--deleted \
--modified \
--others \
--exclude-standard \
-- :/
不返回任何内容。
--deleted
检查工作目录中已被删除的文件--modified
检查工作目录中已被修改的文件--others
检查工作目录中已添加的文件--exclude-standard
忽略通常的 .gitignore
, .git/info/exclude
... 规则-- :/
包括所有路径,如果不在仓库根目录中运行,则需要此参数如果工作目录干净,输出将为空。
git clean -d
命令可以成功删除它们。 - ESkrigit clean
对工作树有所影响,则工作树不干净。双关语意在其中。 - ESkrigit ls-files
可以胜任。当然,你也可以使用 git clean -dn -- :/ | grep '.' || echo clean
,但这不是一个管道命令。 - CervEdgit diff-index --cached --quiet HEAD -- && true || false
- undefined我创建了一些实用的 git 别名,以列出未暂存和已暂存的文件:
git config --global alias.unstaged 'diff --name-only'
git config --global alias.staged 'diff --name-only --cached'
那么您可以轻松地完成以下操作:
[[ -n "$(git unstaged)" ]] && echo unstaged files || echo NO unstaged files
[[ -n "$(git staged)" ]] && echo staged files || echo NO staged files
PATH
路径下创建一个叫做git-has
的脚本,这样可以使它更易读:#!/bin/bash
[[ $(git "$@" | wc -c) -ne 0 ]]
git has unstaged && echo unstaged files || echo NO unstaged files
git has staged && echo staged files || echo NO staged files
git config --global alias.untracked 'ls-files --exclude-standard --others'
git config --global alias.ignored 'ls-files --exclude-standard --others --ignored'
import git
git.Repo(path).is_dirty(untracked_files=True)
如果仓库不干净,则返回 True
LOGLEVEL=DEBUG
,您将看到它使用的所有Popen命令来运行git diff
。 - Jasongit diff-index --quiet HEAD --
#!/bin/bash
set -e
echo -n "Checking if there are uncommited changes... "
trap 'echo -e "\033[0;31mFAILED\033[0m"' ERR
git diff-index --quiet HEAD --
trap - ERR
echo -e "\033[0;32mAll set!\033[0m"
# continue as planned...
注意:此命令会忽略未跟踪的文件。
git add
和git clean
来解决问题。 - sanmai在Linux Ubuntu上的bash终端中测试。
git status
的输出...并告诉你:
这里有一个很好的答案:Unix & Llinux: Determine if Git working directory is clean from a script。我的答案基于此。
我们将使用--porcelain
选项与git status
,因为它旨在由脚本解析!
从man git status
(重点添加)中获取:
--porcelain[=<version>]
以易于解析的格式为脚本提供输出。这类似于短输出,但将在Git版本和用户配置不受影响的情况下保持稳定。有关详细信息,请参见下文。
参数
version
用于指定格式版本。这是可选的,默认为原始版本v1格式。
所以,做这个:
if output="$(git status --porcelain)" && [ -z "$output" ]; then
echo "'git status --porcelain' had no errors AND the working directory" \
"is clean."
else
echo "Working directory has UNCOMMITTED CHANGES."
fi
第一部分,if output=$(git status --porcelain)
如果git status --porcelain
命令有错误,则会失败并跳转到else
语句块。第二部分,&& [ -z "$output" ]
测试output
变量是否包含空的(长度为0)字符串。如果是,那么git status
是干净的,没有更改。
通常我偏好的用法,然而,是使用-n
(非零)否定测试,而不是-z
(零)并像这样操作:
if output="$(git status --porcelain)" && [ -n "$output" ]; then
echo "'git status --porcelain' had no errors AND the working directory" \
"is dirty (has UNCOMMITTED changes)."
# Commit the changes here
git add -A
git commit -m "AUTOMATICALLY COMMITTING UNCOMMITTED CHANGES"
fi
更细粒度的编写第一个代码块的方法如下:
if ! git_status_output="$(git status --porcelain)"; then
# `git status` had an error
error_code="$?"
echo "'git status' had an error: $error_code"
# exit 1 # (optional)
elif [ -z "$git_status_output" ]; then
# Working directory is clean
echo "Working directory is clean."
else
# Working directory has uncommitted changes.
echo "Working directory has UNCOMMITTED CHANGES."
# exit 2 # (optional)
fi
git status
命令错误或拼写错误。
2. git status
是干净的(没有未提交的更改)。
3. git status
是脏的(你有未提交的更改)。'git status' had an error
,只需将--porcelain
选项拼错为--porcelainn
或其他内容,你将在最后看到此输出。
'git status' had an error: 0