如果我的本地Git存储库有更改,如何检入Bash脚本?


175

如果检查更改,有些脚本将无法正常工作。

我这样尝试过:

VN=$(git describe --abbrev=7 HEAD 2>/dev/null)

git update-index -q --refresh
CHANGED=$(git diff-index --name-only HEAD --)
if [ ! -z $CHANGED ];
    then VN="$VN-mod"
fi

是否有某种布尔检查自上次提交以来是否有更改,或者我该如何真正测试本地存储库是否有新更改?

我正在为版本创建脚本(我在这里的某个地方找到)进行所有这些操作。


3
这有什么错git status
karlphillip 2011年

4
@karlphillip:它执行了很多您实际上不需要的处理。
卡斯卡贝尔2011年

1
@karlphillip这是一个“瓷器”命令,这意味着:不适合在脚本中使用,因为输出旨在供人类读取,并且可能会更改(在版本之间或由于本地化而定)
Andrew Spencer

Answers:


199

您正在执行的操作几乎可以正常工作:$CHANGED如果它-z为空,则应报价,并测试是否为空,这意味着没有更改。您的意思是:

if [ -n "$CHANGED" ]; then
    VN="$VN-mod"
fi

来自Git的报价GIT-VERSION-GEN

git update-index -q --refresh
test -z "$(git diff-index --name-only HEAD --)" ||
VN="$VN-dirty"

看来您正在复制它,但您只是忘记了报价的细节。

当然,您也可以这样做:

if git diff-index --quiet HEAD --; then
    # No changes
else
    # Changes
fi

或者,如果您只关心“情况已更改”的情况:

if ! git diff-index --quiet HEAD --; then
    VN="$VN-mod"
fi

使用--quiet的好处是,只要遇到单个差异,Git就可以立即停止处理,因此它不必检查整个工作树。


2
嗨,那是一个问题的最佳答案之一,您只是给了我所有我需要的信息,也给了我其他需要的信息:)。我只需要最后一个,“某些内容已更改” :),您说对了,我复制了它。
kmindi 2011年

9
惊人的bash完成脚本似乎git diff --no-ext-diff --quiet --exit-code用于确定脏状态。
mjs 2012年

3
@mjs:那确实是寻找这样的东西的好地方!该--no-ext-diff选项对安全性是有好处的(如果有人配置了外部diff驱动程序),尽管该选项--exit-code不是必需的,因为它由暗示--quiet
卡斯卡贝尔2012年

4
这对我不起作用,因为它不会报告未跟踪的文件
Cookie,

1
git diff-index报告更改,即使仅文件修改时间已更改(而不更改其内容)。如果touch是文件,它将报告修改,表明运行git status将重置。git status如下使用更好。
Sampo

301

使用git status

cd /git/directory
if [[ `git status --porcelain` ]]; then
  # Changes
else
  # No changes
fi

15
最好的答案,可耻的是来自“ shell和git建筑师”的答案获得了更高的评价。
jwg

4
这非常好,因为它考虑了未版本控制的文件,并且还使用了瓷器,因此应与不同的git版本更加兼容。
杰伊德(Jayd)

24
忽略未跟踪的文件:如果[[ git status --porcelain --untracked-files=no]]; 然后
storm_m2138

4
用于检查本地更改-> if [[ $(git status --porcelain | wc -l) -gt 0 ]]; then echo CHANGED else echo NOT CHANGED locally fi
卡洛斯·萨尔托斯

3
这段代码的作用:执行git status --porcelain看看输出是否为空。如果是这样,则意味着存在变化。
bhathiya-perera

18

尽管Jefromi的回答很好,但我将其发布仅供参考。

在Git源代码中,有一个sh包含以下内容的脚本。

require_clean_work_tree () {
    git rev-parse --verify HEAD >/dev/null || exit 1
    git update-index -q --ignore-submodules --refresh
    err=0

    if ! git diff-files --quiet --ignore-submodules
    then
        echo >&2 "Cannot $1: You have unstaged changes."
        err=1
    fi

    if ! git diff-index --cached --quiet --ignore-submodules HEAD --
    then
        if [ $err = 0 ]
        then
            echo >&2 "Cannot $1: Your index contains uncommitted changes."
        else
            echo >&2 "Additionally, your index contains uncommitted changes."
        fi
        err=1
    fi

    if [ $err = 1 ]
    then
        test -n "$2" && echo >&2 "$2"
        exit 1
    fi
}

作为参考,如果我没有看错,它$1是一个字符串,命名您要运行的任务,并且$2是一个可选的包含失败时自定义错误消息的字符串。例如,将其命名为require_clean_work_tree deploy "Skipping deploy, clean up your work tree or run dev-push"
Umbrella

6

我有类似的问题,但我也必须检查添加的文件。所以我做了以下事情:

cd /local/repo
RUN=0
git diff --no-ext-diff --quiet --exit-code || RUN=1
if [ $RUN = 0 ]; then
    RUN=`git ls-files --exclude-standard --others| wc -l`
fi

if [ $RUN = 0 ]; then
    exit 0
fi

5

git status 是你的朋友

转到Git目录git status以工作:

cd c:/path/to/.git

设置变量以设置工作树,这样就不会出现“此操作必须在工作树中运行”错误:

WORKTREE=c:/path/to/worktree

git status输出捕获到Bash变量中

使用--porcelain保证标准格式和可解析的用途:

CHANGED=$(git --work-tree=${WORKTREE} status --porcelain)

如果-n(不为null),则进行更改。

if [ -n "${CHANGED}" ]; then
  echo 'changed';

else
  echo 'not changed';
fi

1
这也具有检测未跟踪文件的好处。
Luiz C.

2

这也适用:

if [ $(git status --porcelain | wc -l) -eq "0" ]; then
  echo "  🟢 Git repo is clean."
else
  echo "  🔴 Git repo dirty. Quit."
  exit 1
fi

1

这很好。它还将列出受影响的文件:

if git diff-index --name-status --exit-code HEAD;
then
    echo Git working copy is clean...;
else
    echo ;
    echo ERROR: Git working copy is dirty!;
    echo Commit your changes and try again.;
fi;

1
如果您不想看到差异git diff --no-ext-diff --quiet --exit-code也可以工作。
Alex

1

这是一组不错的Bash脚本函数,它们检查是否存在差异,将其打印给用户,并提示用户是否要在部署之前提交更改。它是为Heroku和Python应用程序构建的,但对于其他任何应用程序都不需要进行任何更改。

commit(){
    echo "Please enter a commit message..."
    read msg
    git add . --all
    git commit -am $msg
}

check_commit(){
    echo ========== CHECKING FOR CHANGES ========
    changes=$(git diff)
    if [ -n "$changes" ]; then
        echo ""
        echo "*** CHANGES FOUND ***"
        echo "$changes"
        echo ""
        echo "You have uncomitted changes."
        echo "Would you like to commit them (y/n)?"
        read n
        case $n in
            "y") commit;;
            "n") echo "Changes will not be included...";;
            *) echo "invalid option";;
        esac
    else
        echo "... No changes found"
    fi
}

deploy(){
    check_commit
    echo ========== DEPLOYING TO HEROKU ========
    git push heroku master
    heroku run python manage.py syncdb
}

您可以在以下网址上从Gists复制:https://gist.github.com/sshadmand/f33afe7c9071bb725105


0

这是我的方法...

CHANGES=`git status | grep "working directory clean"`
if [ ! CHANGES -eq "" ] then
    # do stuff here
else
    echo "You have uncommitted changes..."
fi

3
我喜欢使用git status,但是最好在脚本中使用--porcelain并将结果与​​空字符串进行比较以保持不变,因为可以保证不会在版本之间以不兼容的方式进行改变。
Paul Chernoch 2014年

0
nano checker_git.sh

贴上

#!/bin/bash

echo "First arg: $1"

cd $1

bob="Already up-to-date."
echo $bob

echo $(git pull) > s.txt
cat s.txt
if [ "$(cat s.txt)" == "$bob" ]
then
echo "up"
else
echo "not up"

fi
rm -rf st.txt

sh checker_git.sh gitpath


0

基于对@RyanMoon的答案(链接)的@ storm_m2138评论,我在中使用了以下内容Powershell

function hasChanges($dir="."){ $null -ne (iex "git -C $dir status --porcelain --untracked-files=no") }

gci -Directory | ?{ hasChanges $_ } | %{ Write-Host "$_ has changes" }
gci -Directory | ?{ hasChanges $_ } | %{ iex "git -C $_ add -u"; iex "git -C $_ commit -m"Somemthing" }

0

OP的问题现在已经超过9年了。我不知道当时man git-status说了什么,但是现在是这样说的:

--porcelain[=<version>]  
Give the output in an easy-to-parse format for scripts. This is similar to the 
short output, but will remain stable across Git versions and regardless of user 
configuration. See below for details.  

The version parameter is used to specify the format version. This is optional and 
defaults to the original version v1 format.  

这表明该--porcelain参数非常适合测试回购状态以进行更改。

关于OP的问题是:“是否有某种布尔检查自上次提交以来是否有更改,或者我该如何真正测试本地存储库是否有新更改?”

我不认为它本身bash具有布尔数据类型,但这可能足够接近:

[ -z "`git status --porcelain`" ] && echo "NULL-NO DIFFS" || echo "DIFFS EXIST"

可以将其重新生成为if-then-else脚本的表单,也可以在git repo文件夹中按CLI的原样执行。否则,请将该-C选项与指向所需存储库的路径一起使用:

git -C ~/path/to/MyGitRepo status --porcelain 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.