【问题标题】:Check if Git has changes programmatically检查 Git 是否以编程方式进行了更改
【发布时间】:2014-09-06 11:57:02
【问题描述】:

我想编写一个脚本,让我可以轻松更改分支以保持当前更改。

git stash
go checkout main
git stash pop

问题是存储库中当前是否没有更改。然后stash pop 将弹出以前的存储。检查 pop 是否有变化的最简单方法是什么?

【问题讨论】:

    标签: git bash


    【解决方案1】:

    使用git status

    git status --porcelain 是一种方法,尽管可能不是最好的(即最快的)。从手册页:

    --瓷器

    以易于解析的格式为脚本提供输出。这类似于 short 输出,但会在 Git 中保持稳定 版本,无论用户配置如何。详情见下文。

    使用示例:

    $ git status --porcelain
    
    M tmp/myfile.c
    
    $ git stash
    $ git status --porcelain
    $ 
    

    如果没有变化,git status --porcelain 没有输出。但是有一个缺陷 - 新文件将显示为 ?? newfile.txt,因此您可能需要对输出进行后处理才能获得所需的内容,因为新文件不会被隐藏:

    $ git status --porcelain
    ?? newfile.txt
    
    $ git status --porcelain | grep -v "^\?\?"
    $
    

    您可以使用git diff 执行类似的操作,但由于计算差异可能比枚举任何实际存储库的状态需要更长的时间,因此我不推荐它。

    【讨论】:

    • (mathspace)chris@cl:~/Projects/mathspace$ git stash 没有要保存的本地更改 (mathspace)chris@cl:~/Projects/mathspace$ echo $? 0
    • @Casebash 哎呀......我在测试它时显然做了一些奇怪的事情,因为我无法重现这种行为。对此感到抱歉。
    • @ChrisHayes 要在git status 输出中隐藏未跟踪的文件,您可以使用--untracked-files=no(或-uno),查看documentation
    【解决方案2】:

    在 Chris Hayes 建议的基础上,一种检查工作树中是否有更改文件的简单方法提供了git status --porcelain --untracked-files=no(或者-uno)和wc -l 的组合。

    这将为您提供已更改文件的数量。

    这是一个满足您需求的脚本示例:

    changed_files=$(git status --porcelain --untracked-files=no | wc -l)
    [ $changed_files -gt 0 ] && git stash
    
    < do work > 
    
    [ $changed_files -gt 0 ] && git stash pop
    

    有关git status 的更多信息,请查看documentation (respectively for wc)。

    【讨论】:

      【解决方案3】:

      git stash is actually a shell (plain sh, not bash) script,所以你可以看看它做了什么来决定是否进行存储:

      no_changes () {
              git diff-index --quiet --cached HEAD --ignore-submodules -- &&
              git diff-files --quiet --ignore-submodules &&
              (test -z "$untracked" || test -z "$(untracked_files)")
      }
      
      untracked_files () {
              excl_opt=--exclude-standard
              test "$untracked" = "all" && excl_opt=
              git ls-files -o -z $excl_opt
      }
      

      因此,您可以重复这些测试以查看 git stash 是否会做任何事情——但这实际上不是最佳选择:

      • 如果 git stash 会做某事,首先它会重复这些测试(并且他们说有一些东西要隐藏),这会使它们在这种情况下发生两次。
      • 如果“正确”的测试集发生变化,您可能会错误地预测 git stash 的行为并陷入麻烦。

      显然,你想要的是:

      1. 运行git stash,并跟踪它是否有任何作用。
      2. 在目标分支上运行git checkout
      3. 如果git stash 隐藏了某些东西,请运行git stash pop(或者可能先运行--apply --keep-index,看看是否能解决问题,然后仅在需要时才使用不使用--keep-index 的应用程序等)。

      棘手的部分是第一步。事实证明这很容易,你只需要知道how git stash works ,嗯,广泛的细节,以及关于 git 的“管道命令”的其他一些信息。您只需在git stash save 步骤之前grab the previous stash stack top if any,然后抓住新的顶部(如果有)并进行比较:

      old_stash=$(git rev-parse -q --verify refs/stash)
      git stash save [additional arguments here if desired, e.g., -q]
      new_stash=$(git rev-parse -q --verify refs/stash)
      

      如果两个 ref 命名不同的提交,或者旧 ref 为空而新 ref 不为空,则 git stash 将新的 stash 推入堆栈。如果两个 ref 都是空的,或者两个 ref 命名为 same 提交,那么 git stash 什么都不做:

      if [ "$old_stash" = "$new_stash" ]; then ...; else ...; fi
      

      或者,在你的情况下,也许更像:

      [ "$old_stash" != "$new_stash" ] && git stash pop
      

      (根据/bin/[ 的结果和shell 的内置副本,这些测试利用了两个空字符串彼此相等且不等于任何非空字符串的事实)。

      【讨论】:

        猜你喜欢
        • 2011-01-31
        • 1970-01-01
        • 1970-01-01
        • 2011-06-18
        • 2016-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多