git 如何以编程方式(在shell脚本中)确定是否有更改?[副本]

swvgeqrz  于 2023-05-15  发布在  Git
关注(0)|答案(3)|浏览(208)

此问题已在此处有答案

How do I programmatically determine if there are uncommitted changes?(11个回答)
昨天关门了。
我试图创建一个Bash脚本,知道是否有当前工作目录的变化。我知道

$ git status

返回类似“nothing to commit”的消息。我想做的是定义一个变量为true或false。这个布尔值将告诉我是否有更改。
显然我不是bash脚本的Maven。我试过这样做

there_are_changes=$(git status | grep nothin)
echo $there_are_changes

但效果并不理想我该怎么办?

0x6upsns

0x6upsns1#

git-diff man page在此描述了两个相关选项:

--quiet
Disable all output of the program. Implies --exit-code.

--exit-code
Make the program exit with codes similar to diff(1). That is, it
exits with 1 if there were differences and 0 means no differences.

因此,一个可靠的方法是运行

git diff --quiet; nochanges=$?

shell变量nochanges将等于0(即true),如果没有变化,则1(即,false)否则。
然后,您可以在条件语句中使用nochanges的值,如下所示:

if [ $nochanges -eq 0 ]; then
    # there are no changes
else
    # there are changes
fi

或者,如果你不需要在变量中存储退出状态,你可以这样做:

if git diff --quiet; then
    # there are no changes
else
    # there are changes
fi

由于git diff是一个瓷状的Git命令,并且您希望以编程方式执行操作,因此您可能应该使用名为git diff-index的管道Git命令(它也有一个--quiet标志,但必须提供一个树型参数):

if git diff-index --quiet HEAD; then
    # there are no changes
else
    # there are changes
fi

正如下面的评论所指出的,上面概述的方法不包括未跟踪的文件。要覆盖它们,您可以使用以下代码:

if [ -z "$(git status --porcelain)" ]; then
    # there are no changes
else
    # there are changes
fi
q9yhzks0

q9yhzks02#

您可以使用-n表达式检查是否设置了变量。

#!/bin/bash
CHANGESTOCOMMIT=$(git status | grep 'Changes to be com')
UNSTAGEDCHANGES=$(git status | grep 'Changes not staged')

# If there are staged changes:
if [ -n "$CHANGESTOCOMMIT" ]; then
    echo "Changes need to be committed"
fi
if [ -n "$UNSTAGEDCHANGES" ]; then
    echo "Changes made but not staged."
fi

Git会跟踪已更改的文件,这些文件既可以暂存提交,也可以未暂存文件,因此您的脚本可能希望检查这两个选项(或不检查)。-n操作符检查变量是否已设置-如果为空,则返回false。
另一种方法是-z,如果它为空,则返回True(与-n的逻辑相反)。有关条件表达式的完整列表,请参阅Bash参考手册。

ttcibm8c

ttcibm8c3#

使用此脚本,您可以检查未暂存提交的更改。如果有更改,脚本将中止并退出。这在任何情况下都有效,并且是一个更安全的检查than Aaron D's answer,因为如果你使用另一种语言的git,检查将失败,它会说你没有未暂存的阶段,即使你实际上有。
所以用这个:

#!/bin/sh

# Check for changes not staged for commit
git diff --cached | grep -v ^$ > /dev/null

# If there are changes, exit with an error code
if [ $? -ne 0 ]; then
    echo "There are changes not staged for commit."
    exit 1
fi

# Check for changes to already staged files
git diff --cached --name-only | while read file; do
    if [ -f "$file" ]; then
        # Check if there are unstaged changes to the file
        if git diff --name-only "$file" | grep -v ^$ > /dev/null; then
            echo "There are unstaged changes to the file '$file'."
            exit 1
        else
            echo "Good to go! Commit now"
            exit 0
        fi
    fi
done

说明:
所提供的代码是一个预提交钩子,它检查未暂存提交的更改、对已暂存文件的更改以及对已暂存文件的未暂存更改。
钩子首先使用git diff --cached命令检查未提交的更改。如果有任何更改,钩子将打印一条消息,并返回一个错误代码。
如果没有未提交的变更,钩子将使用git diff --cached --name-only命令检查已提交文件的变更。如果有任何文件被修改,钩子将打印一条消息,并返回一个错误代码。
然后,钩子将检查是否有任何未暂存的更改已被修改的文件。如果有任何未暂存的更改,钩子将打印一条消息,并返回一个错误代码。
如果没有对已经暂存的文件进行更改,或者没有对已经暂存的文件进行未暂存的更改,则挂接将退出并显示成功代码。在一般文本中,钩子将检查是否有任何未提交的文件更改。如果有任何更改,钩子将打印一条消息,并返回一个错误代码。这将阻止您提交尚未暂存的更改。
下面是一个如何使用这个钩子的例子:
1.创建名为 * git/hooks/pre-commit的文件
1.将上面的代码复制到文件中
1.使文件可执行。
1.下一次你尝试提交的时候,pre-commit钩子将检查没有提交的修改,已经提交的文件的修改,以及已经提交的文件的未提交的修改。如果有任何更改,钩子将打印一条消息,并返回一个错误代码。
我实际上使用它来避免代码被推送到git,因为flutter的单元测试失败了,就像这样:

#!/bin/sh

# Check for changes not staged for commit
git diff --cached | grep -v ^$ > /dev/null

# If there are changes, exit with an error code
if [ $? -ne 0 ]; then
    echo "There are no changes or some changes are not staged for commit."
    git status
    exit 1
fi

# Check for changes to already staged files
git diff --cached --name-only | while read file; do
    if [ -f "$file" ]; then
        # Check if there are unstaged changes to the file
        if git diff --name-only "$file" | grep -v ^$ > /dev/null; then
            echo "There are unstaged changes to the file '$file'."
            exit 1
        else 
            flutter test

            # If the unit tests fail, exit with a non-zero exit code.
            if [[ $? -ne 0 ]]; then
                echo "Unit tests failed. Aborting commit."
                exit 1
            fi
        fi
    fi
done

相关问题