Git Cherry似乎是为了反向操作而设计的,用于找到未推送到上游的提交。如果我不知道是哪个分支创建了它,以及什么是上游,那么这个功能就没什么用了。所以我不明白它如何帮助解决这个问题。
有人能解释一下/提供一个使用git cherry来找到包含特定提交的'等效'的所有分支的示例吗?
在回答哪些分支包含等效提交的问题之前,您需要确定“哪些提交是等效的”。一旦确定了这一点,您只需在每个提交上使用git branch --contains
即可。
不幸的是,没有100%可靠的方法来确定等效提交。
最可靠的方法是检查提交引入的变更集的补丁 ID。这就是git cherry
、git log --cherry
和git log --cherry-mark
所依赖的东西。在内部,它们都调用了git patch-id
。补丁 ID 只是规范化差异的 SHA1。引入相同变更的任何提交都将具有相同的补丁 ID。此外,引入大部分相同变更的任何提交(仅在空格或文件中应用的行号方面存在差异)都将具有相同的补丁 ID。如果两个提交具有相同的 Patch ID,则几乎可以保证它们是等效的-您几乎永远不会通过补丁 ID 获得虚假正面结果。然而,虚假阴性经常发生。每当您执行git cherry-pick
并手动解决合并冲突时,您可能会引入变更集中的差异。即使更改了一个字符,也会导致生成不同的补丁 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 的提交消息的任何提交。
如果以上都不起作用,您可以尝试查找使用 pickaxe 引入的特定行,或者使用 git log --grep
查找在提交消息中可能是唯一的其他内容。
如果这听起来很复杂,那么确实如此。这就是为什么我告诉人们尽可能避免使用 cherry-pick。 git branch --contains
非常有价值、易于使用且100%可靠。没有其他解决方案能够接近。
git cherry
命令对每个本地的git分支进行检查,并在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)
}
请查看Andrew C的帖子,了解 git cherry
实际工作原理的精彩解释(使用git patch-id
)。
git-cherry-contains 0adbcd refs/remotes/origin/
。 - odinho - Velmontcherry-contains = "!f(){ local sha=$(git rev-parse --verify \"$1\") || return 1; local refs=${2:-refs/heads/}; local branch; git for-each-ref --format='%(refname:short)' $refs | while IFS= read -r branch; do if ! git cherry \"$branch\" \"$sha\" \"$sha^\" | grep -qE \"^\\+ $sha\"; then echo \"$branch\"; fi; done; };f"
- Andy使用以下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修订参数(例如提交的哈希值)的PATCH ID。然后找到所有具有计算PATCH ID的提交。最后将包含这些提交的所有分支名称打印到控制台中。
当然,只要PATCH ID对于所有(cherry-pick)提交相同,此方法才有效。每次进行cherry-pick并手动解决合并冲突时,都可能引入变更集中的差异。这会导致不同的PATCH ID。
git show <COMMIT_HASH>
不会产生相同的补丁 ID 输出。根据 https://dev59.com/9Ggu5IYBdhLWcg3wEzDP#45373500 的建议,我尝试使用 git diff-tree -p
作为替代方案,并获得了确定性的相同结果。 - Chris Cleeland$ for i in `git rev-list --all --grep="something unique in the commit message"`; do git branch --all --contains $i; done | sort | uniq
git rev-list
和git patch-id
来确定。你可能还想解析git cherry-pick
在提交消息中留下的注释,因为 patch-id(也是git cherry
的基础)并不完美,如果你解决了任何冲突,它将会失效。 - Chronialgit cherry
也不行)。在这种情况下,使用差异查看器的git log
是一个选项:https://stackoverflow.com/a/46127413/1959808 - 0 _