如果本地Git存储库发生了更改,如何检入Bash脚本?

有些脚本在检查更改时不能正确工作。

我是这样试的:

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

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

我所做的所有这些都是为了一个版本创建脚本(我在这里的某个地方找到的)。

129635 次浏览

你所做的几乎可以工作:你应该引用$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可以在遇到单个差异时立即停止处理,因此它可能不需要检查整个工作树。

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

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

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

我是这样做的……

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

使用git status:

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

这工作得很好。它还会列出受影响的文件:

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;

下面是一组很棒的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
}

你可以从gist上复制:https://gist.github.com/sshadmand/f33afe7c9071bb725105

git status是你的朋友

切换到Git目录,以便git status工作:

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
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

基于@storm_m2138对@RyanMoon的回答(链接)的评论,我在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" }

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

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

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

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

这可以被重新转换为脚本的if-then-else形式,或者在CLI中执行在git repo文件夹中。否则,使用带有路径规范的-C选项对感兴趣的回购:

git -C ~/path/to/MyGitRepo status --porcelain

附录:

  1. 一些人建议使用-u, --untracked-file选项来避免报告想要忽略的文件的状态。注意,这伴随着一个不幸的副作用: 新添加的的文件也没有状态。该选项在某些情况下中很有用,但在使用前请仔细考虑。

这也是可行的:

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

我的观点是:

git status --porcelain | head -1

只返回一行,而不是一个长列表

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 != ""

我查阅了很多Stack Overflow的答案,但没有一个符合我的期望。也就是说,如果出现以下情况,脚本会出错:

  • 当前本地状态和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 "$(...)" ]]包装它会出错。
  • 如果当前提交的回购状态与master分支不同,git diff --exit-code master > /dev/null将出错。
  • 如果当前的master分支与origin/master分支不同,git diff --exit-code origin/master..master > /dev/null将出错。

这是有用的,例如,如果你想确保你的回购可能是安全的删除/清除。

为什么这样更好呢?

  • 如果你有新的未提交的非存储文件,只依赖git diff --exit-code ...的答案将不会出错;
  • 仅依赖git status --porcelain的答案不会告诉你你有尚未推送到远程的提交。