【问题标题】:How to check if there's nothing to be committed in the current branch?如何检查当前分支中是否没有要提交的内容?
【发布时间】:2011-02-28 07:34:59
【问题描述】:

目标是获得可以在 shell 命令中评估的明确状态。

我尝试了git status,但它总是返回 0,即使有要提交的项目。

git status
echo $?  #this is always 0

我有一个想法,但我认为这是个坏主意。

if [ git status | grep -i -c "[a-z]"> 2 ];
then
 code for change...
else
  code for nothing change...
fi

还有其他方法吗?


使用以下解决方案进行更新,请参阅 Mark Longair 的帖子

我试过了,但它会导致问题。

if [ -z $(git status --porcelain) ];
then
    echo "IT IS CLEAN"
else
    echo "PLEASE COMMIT YOUR CHANGE FIRST!!!"
    echo git status
fi

我收到以下错误[: ??: binary operator expected

现在,我正在查看这个人并尝试 git diff。

===================我希望的代码,希望更好的答案=================== ===

#if [ `git status | grep -i -c "$"` -lt 3 ];
# change to below code,although the above code is simple, but I think it is not strict logical
if [ `git diff --cached --exit-code HEAD^ > /dev/null && (git ls-files --other --exclude-standard --directory | grep -c -v '/$')` ];
then
        echo "PLEASE COMMIT YOUR CHANGE FIRST!!!"
    exit 1

else
    exit 0
fi

【问题讨论】:

  • 在更新的部分中,您似乎实际上并没有按照eckeshis answer 中的建议进行操作——正如他所说,您需要在$(git status --porcelain) 周围加上双引号。此外,如果您想在消息中添加感叹号,则需要使用单引号而不是双引号 - 即应该改为 echo 'PLEASE COMMIT YOUR CHANGE FIRST!!!'
  • 正如马克所说:你需要在$(git status --porcelain)周围加上双引号,就像我告诉你的那样!
  • 如果不包含部分答案,这个问题会更有用。
  • @9nix00 做你被告知的事情并编辑和修复上面的 shell 脚本中的错误: BUG: if [ -z $(some command) ] FIX: if [ -z "$(some命令)”]

标签: git git-status


【解决方案1】:

测试git status --porcelain 的输出是否为空的另一种方法是分别测试您关心的每个条件。例如,git status 的输出中是否存在未跟踪的文件,人们可能并不总是关心。

例如,查看是否有本地未分级的更改,可以查看以下的返回码:

git diff --exit-code

要检查是否有任何已暂存但未提交的更改,您可以使用以下返回码:

git diff --cached --exit-code

最后,如果你想知道你的工作树中是否有未被忽略的未跟踪文件,你可以测试以下命令的输出是否为空:

git ls-files --other --exclude-standard --directory

更新:您在下面询问是否可以更改该命令以排除输出中的目录。您可以通过添加 --no-empty-directory 来排除空目录,但要排除该输出中的所有目录,我认为您必须过滤输出,例如:

git ls-files --other --exclude-standard --directory | egrep -v '/$'

-vegrep 表示只输出与模式不匹配的行,并且模式匹配任何以/ 结尾的行。

【讨论】:

  • 我学习了这些技巧并遇到了问题。即使用 git ls-files --other --exclude-standard --directory 获取列表包含目录。有没有排除这些目录?
  • 是的,这就是我想要的。我更新了我的帖子以获取新的脚本代码。我认为你的建议是更严格的逻辑虽然更多的代码哈哈......并希望出现更好的答案。
  • @albfan:在git-diff man page:“使用类似于diff(1)的代码使程序退出。也就是说,如果有差异则以1退出,0表示没有差异。”
  • 只是指出,它至少从 2007 年就已经存在 13da0fc0,对于 shell 脚本非常方便,并且与旧版本的 git 完全兼容
  • --quiet(暗示--exit-code)也会使输出静音,对于那些只想要退出代码的人。
【解决方案2】:

git status 的返回值只是告诉你git status 的退出代码,而不是告诉你是否有任何修改要提交。

如果您想要更计算机可读的git status 输出版本,请尝试

git status --porcelain

有关更多信息,请参阅git status 的描述。

示例使用(脚本只是测试git status --porcelain 是否提供任何输出,不需要解析):

if [ -n "$(git status --porcelain)" ]; then
  echo "there are changes";
else
  echo "no changes";
fi

请注意,您必须引用要测试的字符串,即git status --porcelain 的输出。有关测试构造的更多提示,请参阅Advanced Bash Scripting Guide字符串比较部分)。

【讨论】:

  • 嗨,你给了一个很好的建议,我试过了,但是在脚本中,它会导致一些问题,我改进了它,如果我们使用这个 if [ -z $(git status --porcelain) ] ;它会出现一些错误,[: ??: binary operator expected I find the manual and use this if [ -z $(git status --short) ];这可以工作,谢谢!
  • 对不起,还是有问题。当提交是干净的。使用瓷器和短都可以。但是当提交不干净时。它会导致错误。 [: ??: 需要二元运算符。我想也许我们应该尝试使用 base64 对其进行编码。让我尝试!下载base64命令工具....大声笑
  • 提交不干净时会导致问题。
  • 很好的解决方案。为了增加健壮性,您可以将|| echo no 附加到命令替换中,这样如果git status 根本失败,工作区就不会被错误地报告为干净。此外,您的代码(值得称道)符合 POSIX,但由于您链接到 bash 指南,让我补充一点,如果您使用 bash 的 [[ ... ]] 而不是与 POSIX 兼容的 [ ... ],则不需要双引号命令替换(虽然它没有害处):[[ -z $(git status --porcelain) ]].
  • @eckes 几天前我开始了一个新的仓库,我添加了一个提交,我尝试编写一些 pre-commit-hook 并检查要提交的内容以及您所说的内容不起作用我的情况。
【解决方案3】:

如果你和我一样,想知道有没有:

1) 对现有文件的更改 2) 新增文件 3) 删除的文件

特别不想知道 4) 未跟踪的文件。

应该这样做:

git status --untracked-files=no --porcelain

如果 repo 是干净的,这是我退出脚本的 bash 代码。它使用未跟踪文件选项的简短版本:

[[ -z $(git status -uno --porcelain) ]] && echo "this branch is clean, no need to push..." && kill -SIGINT $$;

【讨论】:

  • +1 表示—untracked-files=no;我认为您的测试可以简化为[[ -z $(git status --untracked-files=no --porcelain) ]]git status 不应该写信给 stderr,除非出现了根本性的问题——然后你确实想看到那个输出。 (如果您希望在该事件中获得更强大的行为,请将|| echo no 附加到命令替换中,以便清洁度测试仍然失败)。字符串比较/-z 运算符可以处理多行字符串 - 不需要tail
  • 感谢@mklement0,甚至更短一点:[[ -z $(git status -u no --porcelain) ]]
  • 更正:我的较短版本实际上只是检查名为“no”的文件的状态!呸呸呸。应该是:[[ -z $(git status -uno --porcelain) ]]
  • 感谢您的跟进;这是一个微妙的错误 - 教训是带有 optional 参数的 short 选项必须将参数 直接 附加,中间不能有空格。将更正后的简短版本直接合并到您的答案中怎么样?
【解决方案4】:

可以将git status --porcelain 与简单的grep 组合起来执行测试。

if git status --porcelain | grep .; then
    echo Repo is dirty
else
    echo Repo is clean
fi

我有时将其用作简单的单线:

# pull from origin if our repo is clean
git status --porcelain | grep . || git pull origin master

-qs 添加到您的 grep 命令以使其静音。

【讨论】:

  • 优雅+1;轻微警告:如果 git status 致命失败(例如,损坏的 repo),您的测试将错误地报告 clean 工作区。一种选择是使用git status --porcelain 2>&1,但如果您将grep 与-q 一起使用,则会“吃掉”错误消息。 (处理它会失去优雅:(git status --porcelain || echo err) | grep -q .
  • 也可以写成:test -z "$(git status --porcelain)" || git pull origin master
【解决方案5】:

我会对此进行测试:

git diff --quiet --cached

或者明确一点:

git diff --quiet --exit-code --cached

地点:

--退出代码

使用类似于 diff(1) 的代码使程序退出。也就是说,如果有差异则以 1 退出,而 0 表示没有差异。

--安静

禁用程序的所有输出。暗示 --exit-code

【讨论】:

    【解决方案6】:

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

    这个片段展示了如何使用git diff-filesgit diff-index 来查明以前已知的文件是否有任何更改。但是,它不允许您查明是否已将新的未知文件添加到工作树中。

    【讨论】:

    • 这工作正常,除了新文件。我们可以添加这个。如果 ! git ls-files --other --exclude-standard --directory | grep -c -v '/$' then exit 0 else echo "please commit your new file, if you don't want to add it, please add it in git-ignore file." 1号出口
    • 只需if [ -n "$(git ls-files --others --exclude-standard)" ] 没有任何额外的管道或greping 就足以检测未跟踪的文件。
    【解决方案7】:

    我在讨论中有点晚了,但如果只是如果 git status --porcelain 不返回任何内容并且 != 0 否则您需要退出代码为 0,请尝试以下操作:

    exit $( git status --porcelain | wc -l )
    

    这将使行数成为退出代码,当行数超过 255 行时可能会出现问题。所以

    exit $( git status --porcelain | head -255 | wc -l )
    

    会考虑到这一点;)

    【讨论】:

    • 如果输出超过255行,这个基本上就是undefined了。
    • 很好,谢谢!
    【解决方案8】:

    我在脚本中使用它来拥有:

    • 0 当一切都干净时
    • 1 当有差异或未跟踪的文件时

      [ -z "$(git status --porcelain)" ]

    【讨论】:

    • 使用if ! git diff --quiet; then 更干净,性能更高(我认为)。换句话说,使用退出代码,而不是标准输出。
    • @AlexanderMills git diff --quiet 对于缓存更改的行为与 git status --porcelain 不同。
    【解决方案9】:

    不漂亮,但有效:

    git status | grep -qF 'working directory clean' || echo "DIRTY"
    

    不确定消息是否依赖于语言环境,所以可以在前面加上LANG=C

    【讨论】:

      【解决方案10】:

      除了其他解决方案之外,您还可以使用单独的命令(使用 git log ranges)在获取之后告诉您需要拉取,和/或需要推送。

      如果您需要编写这些脚本:

      [ "$(git log ..origin/main)" == "" ] || (
        echo "something new on main"
        .. pull ?
      )
      [ "$(git rev-list origin/main..)" == "" ] || (
        echo "something new local"
        .. push ?
      )
      

      更多详情this article

      【讨论】:

      • 当链接到您自己的网站或内容(或您附属的内容)时,您must disclose your affiliation in the answer 以免被视为垃圾邮件。根据 Stack Exchange 政策,在您的用户名中包含与 URL 相同的文本或在您的个人资料中提及它不被视为充分披露。
      猜你喜欢
      • 1970-01-01
      • 2021-12-07
      • 1970-01-01
      • 1970-01-01
      • 2016-05-07
      • 2013-04-24
      • 2013-03-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多