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

时间:2011-02-28 15:15:13

标签: git

有些脚本在检查更改时无法正常工作。

我试过这样:

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

是否存在某种布尔检查,如果自上次提交以来发生了更改,或者我如何才能真正测试我的本地存储库是否有新的更改?

我正在为版本创建脚本(我在这里找到的地方)做这一切。

15 个答案:

答案 0 :(得分:222)

使用git status

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

答案 1 :(得分:159)

你正在做什么几乎可以工作:如果它是空的,你应该引用$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 :(得分:16)

虽然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
}

答案 3 :(得分: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

答案 4 :(得分:4)

git status是您的朋友

更改为git status的Git目录:

cd c:/path/to/.git

设置一个变量来设置工作树,这样你就不会得到这个操作必须在工作树中运行'错误:

WORKTREE=c:/path/to/worktree

捕获Bash变量中的git status输出

使用--porcelain保证标准格式并且可以解析:

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

如果-n(非空),我们有更改。

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

else
  echo 'not changed';
fi

答案 5 :(得分:3)

这也可行:

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

答案 6 :(得分:2)

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参数非常适合测试回购状态以进行更改。

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

我不认为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 

附录:

  1. 有人建议使用-u, --untracked-file选项来避免报告人们希望忽略的文件的状态。请注意,这带有不幸的副作用新添加的文件也不会处于状态。该选项在某些情况下非常有用,但在使用前请仔细考虑。

答案 7 :(得分: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;

答案 8 :(得分:1)

这是一组很好的Bash脚本函数,用于检查是否存在diff,将其打印给用户并提示用户是否要在部署之前提交更改。它是为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

答案 9 :(得分:1)

我的2美分:

git status --porcelain | head -1

仅返回一行而不是一长串

答案 10 :(得分:0)

我是这样做的......

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

答案 11 :(得分: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

答案 12 :(得分:0)

基于对@RyanMoon的答案(link的@ storm_m2138评论,我在$ ./bin/strspaceseppairs AB error: less than two-pairs to separate. 中使用了以下内容。

    if (len & 1) {  /* validate even number of characters */
        fputs ("error: odd number of characters in instr.\n", stderr);
        return 1;
    }
    if (len < 4) {  /* validate at least 2-pairs worth of input provided */
        puts(instr);   /* (otherwise output unchanged and exit) */
        return 0;
    }

答案 13 :(得分:0)

Ansible解决方案:

- name: Bootstrap checks
  block:
  - shell: "git status --porcelain"
    register: git_status
  - fail:
      msg: "Please clean git status: {{ git_status.stdout }}"
    when: git_status.stdout != ""

答案 14 :(得分:0)

我已经查找了数十个堆栈溢出答案,但似乎没有一个可以满足我的期望。也就是说,如果出现以下情况,脚本应出错:

  • 当前本地状态与origin/master之间存在任何差异(包括:对现有文件的更改;新的未提交和已提交的文件以及文件的删除),或者
  • master尚未提交到origin/master的提交。

最终脚本可以这样使用:

if ! (git diff --exit-code origin/master..master > /dev/null) \
  || ! (git diff --exit-code master > /dev/null) \
  || ! [[ -z "$(git status --porcelain)" ]] ; then
  echo "Your local repo has some changes that aren't pushed to origin/master ."
  exit 1
fi

说明:

  • git status --porcelain将呈现尚未提交的文件列表。如果命令返回了非空字符串,则用[[ -z "$(...)" ]]进行包装会导致错误。
  • 如果您当前的已提交回购状态不同于git diff --exit-code master > /dev/null分支,则
  • master将出错。
  • 如果您当前的git diff --exit-code origin/master..master > /dev/null分支与master不同,
  • origin/master将出错。

如果例如您要确保您的存储库可以安全地删除/清除。

为什么更好?

    如果您有新的未提交的未隐藏文件,
  • 仅依靠git diff --exit-code ...的答案不会出错;
  • 仅依靠git status --porcelain的答案不会告诉您您的提交尚未推送到远程。