如何列出包含等效提交的分支

时间:2013-04-30 16:19:57

标签: git version-control

在先前的问题中,有人为查找包含EXACT提交的分支提供了答案:

How to list branches that contain a given commit

接受的答案强调,这仅适用于EXACT提交ID,而不适用于相同的提交。有人进一步指出,Git Cherry可以用来解决这个问题。

Git cherry SEEMS适合反向;发现提交没有推到上游。如果我不知道哪个分支创建它以及什么是上游,那么这是无用的。所以我不知道它将如何帮助解决这个问题。

有人可以解释/提供一个如何使用git cherry查找包含特定提交的“等效”的所有分支的示例吗?

4 个答案:

答案 0 :(得分:17)

在您回答哪些分支包含等效提交的问题之前,您必须确定"哪些提交是等效的"。完成后,只需在每次提交时使用git branch --contains

不幸的是,没有100%可靠的方法来确定等效的提交。

最可靠的方法是检查提交引入的变更集的补丁ID。这是git cherrygit log --cherrygit log --cherry-mark所依赖的内容。在内部,他们都呼叫git patch-id。补丁ID只是标准化变化差异的SHA1。引入相同更改的任何提交都将具有相同的修补程序ID。此外,任何引入大多数相同更改的提交只会在空格或文件中应用的行号不同时具有相同的修补程序ID。如果两个提交具有相同的补丁ID,则几乎可以保证它们是等效的 - 您几乎不会通过补丁ID获得误报。但是经常出现假阴性。每次执行git cherry-pick并且必须手动解决合并冲突时,您可能会在变更集中引入差异。即使是1个字符的更改也会导致生成不同的补丁ID。

检查修补程序ID需要按照Chronial的建议编写脚本。首先用

之类的东西计算原始提交的补丁ID

(注意 - 未经测试的脚本应该合理地接近工作)

origCommitPatchId=$(git diff ORIG_COMMIT^! | git patch-id | awk '{print $1}')

现在您将不得不搜索历史记录中的所有其他提交并计算它们的修补程序ID,并查看它们是否相同。

for rev in $(git rev-list --all)
do
   testPatchId=$(git diff ${rev}^1..${rev} | git patch-id | awk '{print $1}')
   if [ "${origCommitPatchId}" = "${testPatchId}" ]; then
      echo "${rev}"
   fi
done

现在您已拥有SHA列表,您可以将这些列表传递给git branch -a --contains

如果由于合并冲突,上述内容对您不起作用怎么办?

嗯,还有一些其他的事情你可以试试。通常,当您选择提交时,将保留提交中的原始作者姓名,电子邮件和日期字段。所以你会得到一个新的提交,但作者信息将是相同的。

因此,您可以使用

从原始提交中获取此信息
git log -1 --pretty="%an %ae %ad" ORIG_COMMIT

然后像以前一样,您必须完成历史记录中的每个提交,打印出相同的信息并进行比较。 可能会给你一些额外的匹配。

您还可以使用git log --grep=ORIG_COMMIT,它会在提交消息中找到引用ORIG_COMMIT的任何提交。

如果这些都不起作用,您可以尝试查找随镐引入的特定行,或者可以git log --grep查找提交消息中可能唯一的其他内容。

如果这听起来很复杂,那就好了。这就是为什么我告诉别人尽可能避免使用樱桃挑选的原因。 git branch --contains非常有价值且易于使用且100%可靠。其他解决方案都没有接近。

答案 1 :(得分:6)

以下似乎有效(但尚未经过多次测试)。它运行git cherry for each local git branch,如果git cherry没有将提交列为缺少分支,则打印分支名称。

# USAGE: git-cherry-contains <commit> [refs]
# Prints each local branch containing an equivalent commit.
git-cherry-contains() {
    local sha; sha=$(git rev-parse --verify "$1") || return 1
    local refs; refs=${2:-refs/heads/}
    local branch
    while IFS= read -r branch; do
        if ! git cherry "$branch" "$sha" "$sha^" | grep -qE "^\+ $sha"; then
            echo "$branch"
        fi
    done < <(git for-each-ref --format='%(refname:short)' $refs)
}

有关git cherry实际运作方式(使用git patch-id)的详细说明,请参阅Andrew C's post

答案 2 :(得分:1)

命令

使用以下Bash命令(将<COMMIT HASH>替换为您要搜索的提交哈希):

PATCH_ID=$(git show <COMMIT HASH> | git patch-id | cut -d' ' -f1) \
&& ALL_MATCHING_COMMIT_HASHES=$(git log --all -p | git patch-id | grep $PATCH_ID | cut -d' ' -f2) \
&& for HASH in $ALL_MATCHING_COMMIT_HASHES; do echo "$(git branch -a --contains $HASH) (commit $HASH)"; done 

示例输出

user@host test_cherry_picking $ PATCH_ID=$(git show 59faabb91cfc8e449737f93be8c7df3825491674 | git patch-id | cut -d' ' -f1) \
&& ALL_MATCHING_COMMIT_HASHES=$(git log --all -p | git patch-id | grep $PATCH_ID | cut -d' ' -f2) \
&& for HASH in $ALL_MATCHING_COMMIT_HASHES; do echo "$(git branch -a --contains $HASH) (commit $HASH)"; done

* hotfix (commit 59faabb91cfc8e449737f93be8c7df3825491674)
master (commit bb5fa0d16931fa1d5fa9f5e9ee5c27634fad7da8)

user@host test_cherry_picking $

描述

计算给定GIT REVISION PARAMETER的PATCH ID(例如提交的哈希值)。然后使用计算的PATCH ID查找所有提交。最后,包含这些提交的所有分支名称都将打印到控制台。

这当然只有PATCH ID对所有(樱桃挑选)提交都相同才有效。任何时候你挑选并且必须手动解决合并冲突,你可能会在变更集中引入差异。这将导致不同的PATCH ID。

答案 3 :(得分:0)

$ for i in `git rev-list --all --grep="something unique in the commit message"`; do git branch --all --contains $i; done | sort | uniq