【问题标题】:Telling if a Git commit is a Merge/Revert commit判断 Git 提交是否是合并/恢复提交
【发布时间】:2011-04-18 22:51:03
【问题描述】:

我正在编写一个脚本,需要检查特定提交是否是合并/恢复提交,我想知道是否有一个 git 技巧。

到目前为止我想出的(我绝对不想依赖这里的提交消息)是检查HASH^2,看看我是否没有收到错误,有没有更好的方法?

【问题讨论】:

    标签: git git-merge git-commit git-hash


    【解决方案1】:

    弄清楚某事是否是合并很容易。这就是与不止一个父母的所有承诺。要检查这一点,您可以这样做,例如

    $ git cat-file -p $commit_id
    

    如果输出中有多个“父”行,则您找到了一个合并。

    对于还原来说,这并不容易。通常,reverts 只是正常的提交,恰好相反地应用了先前提交的差异,有效地删除了提交引入的更改。其他没什么特别的。

    如果使用git revert $commit 创建了还原,那么 git 通常会生成一个提交消息,指示还原以及它还原的提交。但是,很有可能以其他方式进行还原,或者只是更改由git revert 生成的提交的提交消息。

    寻找那些生成的还原提交消息可能已经是您想要实现的目标的一个很好的启发式方法。如果不是,您必须实际查看其他提交,将它们的差异相互比较,查看一个是另一个的完全相反的操作。但即使这样也不是一个好的解决方案。通常,还原与它们要还原的提交的逆向略有不同,例如,以适应提交和还原之间发生的代码更改。

    【讨论】:

    • 如何得到被合并的分支?
    【解决方案2】:

    使用git cat-file 的答案是使用 git "plumbing" 命令,这通常更适合构建脚本,因为输出格式不太可能改变。使用git showgit rev-parse 的命令可能需要随着时间的推移而更改,因为它们正在使用porcelain 命令。

    我用了很久的bash函数使用git rev-list

    gitismerge () {
        local sha="$1"
        msha=$(git rev-list -1 --merges ${sha}~1..${sha})
        [ -z "$msha" ] && return 1
        return 0
    }
    

    瓷器/管道命令列表可以在顶级 git 命令的文档中找到。

    此代码使用git-rev-list 和特定的gitrevisions 查询${sha}~1..${sha},如果它存在则打印SHA 的第二个父级,如果它不存在则不打印,这是合并提交的确切定义。

    具体来说,SHA~1..SHA 表示包括可从 SHA 访问的提交,但不包括可访问 SHA~1 的提交,这是 SHA 的第一个父项

    结果存储在 $msha 中并使用 bash [ -z "$msha" ] 测试是否为空,如果为空则失败(返回 1),如果非空则通过(返回 0)。

    【讨论】:

    • 瓷器是什么意思?你到底指的是什么答案?
    • 嗨@knocte 我在我的答案中添加了一些文本,带有链接,HTH。
    • 感谢更新;还有两个问题:[ -z foo ] 实际上是做什么的?我想知道这一点,因为我有兴趣使用它,但不是在 bash 脚本中使用...另外,与cat-file 相比,您的解决方案有哪些优缺点?欢呼
    • 嗨@knocte,我改进了答案,希望涵盖了你的两个问题。代码的简洁是真正的“优势”,它只是 SHA~1..SHA 修订说明符的拼写,它将输出映射到一个非常简单的“空与非空”bash 测试。注意我还用额外的“-1”选项更新了答案,这进一步限制了“git rev-list”的输出
    • is_merge () { return $(( ! `git rev-list --no-walk --count --merges "$@"`)) }
    【解决方案3】:

    一种测试合并提交的方法:

    $ test -z $(git rev-parse --verify $commit^2 2> /dev/null) || echo MERGE COMMIT
    

    至于 git revert 提交,我同意 @rafl 的观点,最现实的方法是在提交消息中查找 revert 消息样板;如果有人更改了它,那么检测它会非常复杂。

    【讨论】:

    • test -z 究竟做了什么?这个问题不要求bashisms ...
    • 就其价值而言,“测试”不是一种 bashism——它也应该与其他 POSIX 友好的 shell 一起使用。在 Windows 上,您可以使用 msysGit(通过安装适用于 Windows 的 Git)、Cygwin 或适用于 Linux 的 Windows 子系统。
    【解决方案4】:

    以下指令将转储父哈希。需要更少的过滤...

    git show --no-patch --format="%P" <commit hash>

    【讨论】:

      【解决方案5】:

      接受的答案非常适合手动检查结果,但对于脚本编写有一个致命缺陷:提交消息本身可能包含以“父”开头的行,您可能会不小心捕捉到它,而不是元数据输出的顶部。

      更可靠的选择是:

      git show --summary <commit>
      

      并检查一行是否以Merge: 开头。这类似于 git cat-file,但它会在提交消息前加上空格,因此您可以在脚本中安全地对其进行 grep:

      git show --summary HEAD | grep -q ^Merge:
      

      这将为合并提交返回 0,为非合并提交返回 1。将 HEAD 替换为您想要测试的提交。

      示例用法:

      if git show --summary some-branch | grep -q ^Merge: ; then
          echo "some-branch is a merge"
      fi
      

      这是可行的,因为提交消息本身以 4 个空格为前缀,因此即使它包含以“Merge:”开头的行,它也会看起来像 Merge:..,并且正则表达式不会捕获它。注意正则表达式开头的^,它与行的开头相匹配。

      【讨论】:

      • 这对我来说似乎是一个非常老套的解决方案,因为如果有人在正常(非合并)提交中使用“合并”一词,那么您将得到 误报
      • @knocte 这就是正则表达式中插入符号 (^) 的用途:它在 行首 搜索合并。提交消息缩进了几个空格,所以即使包含 Merge,它也不会匹配。 diff 本身的内容(除了缩进之外)没有显示,由 --summary 标志提供。我知道它看起来很糟糕,但那是 Git :) 这个解决方案没有误报。
      • 当然,但是例如现在投票最多的答案取决于完全相同的机制,只是没有提到 grep 部分。但是, cat-file 不会缩进提交消息,因此,您最终会得到误报......无论如何,如果您习惯了 git 的瓷器部分,它只会很难看。此解决方案(以及此线程中的任何其他解决方案)非常适合管道方面。
      • 如何使用git cat-file grep?你能详细说明一下吗?
      • git cat-file 只是为您提供文本输出,您仍然需要为“父”行解析它。查看答案文本:“如果输出中有多个‘父’行,则您找到了合并。”换句话说:grep。如果提交消息有一行以“parent”开头,你就不能(轻松地)这样做。
      【解决方案6】:

      另一种查找提交父级的方法:

      git show -s --pretty=%p <commit>
      

      使用%P 进行完整哈希。这会打印出HEAD 有多少父母:

      git show -s --pretty=%p HEAD | wc -w
      

      【讨论】:

        【解决方案7】:

        我发现所有答案都很复杂,有些甚至不可靠。
        特别是如果您想对合并和常规提交执行不同的操作。

        IMO 最佳解决方案是使用第二个父表达式 ^2 调用 git rev-parse,然后检查错误:

        git rev-parse HEAD^2 >/dev/null 2>/dev/null && echo "is merge" || echo "regular commit" 
        

        这对我来说非常有效。上面的大部分例子只是一个装饰,只是丢弃了不需要的输出。

        对于 Windows cmd 这也很有效:

        git rev-parse "HEAD^2" >nul 2>nul && echo is merge || echo regular commit
        

        注意引号字符

        【讨论】:

          【解决方案8】:

          检查是否是合并提交,

          # Use the FULL commit hash because -q checks if the entire line is matched.
          git rev-list --merges --all | grep -qx <FULL_commit_hash>
          echo $?    # 0 if it's a merge commit and non-zero otherwise
          

          要检查它是否是还原提交,您必须查看其他答案。

          【讨论】:

          • ...如果您的存储库有数十万次提交,则扩展性不太好。
          【解决方案9】:

          如果以下命令的输出为 1,则表明它是一个单独的提交。如果不是,则为合并提交

          git cat-file -p $commitID | grep -o -i parent | wc -l
          

          【讨论】:

            猜你喜欢
            • 2018-11-29
            • 1970-01-01
            • 1970-01-01
            • 2015-08-29
            • 2017-07-14
            • 2016-10-10
            • 2011-03-01
            • 1970-01-01
            • 2013-10-23
            相关资源
            最近更新 更多