4

我在git中有两个分支,其中一个分支master包含所有提交,另一个分支,例如 ,release其中包含来自第一个分支的一些精心挑选的提交master。由于提交是在 中挑选出来的release,因此它们的提交哈希值与 中的相应提交不同master,但提交消息是相同的。

现在我想找到来自 的提交master,这些提交没有被挑选到release. 请注意,由于冲突解决,精心挑选的提交的代码可能与原始提交不同。我该怎么做?是否有本机支持git

例子:

master分支:

git checkout master
git log --oneline -7

2cba4b1d (HEAD -> master) Message subject for commit 7
f54fc16f Message subject for commit 6
4d871cbd Message subject for commit 5
a83ed44c Message subject for commit 4
48d0fb73 Message subject for commit 3
931da9a6 Message subject for commit 2
8553323b Message subject for commit 1

release分支

git checkout release
git log --oneline -5

d65a04c6 (HEAD -> release) Message subject for commit 7
8aeecd92 Message subject for commit 6
2a54e335 Message subject for commit 4
99985f38 Message subject for commit 3
e76a9bb4 Message subject for commit 1

所以两个分支之间的区别将是两个带有消息主题的提交:

Message subject for commit 5
Message subject for commit 2

如果它显示提交哈希也可以:

4d871cbd Message subject for commit 5
931da9a6 Message subject for commit 2

附加说明和要求:

上面的示例以与合并提交相同的顺序返回差异。在结果中获得与原始提交日志中相同的顺序有助于在master. 如果也能实现就好了。

在我的情况下,两个分支都有线性历史,并且没有合并提交。

4

2 回答 2

1

尝试以下:

comm -12 <(git rev-list ^master release --oneline | awk '{$1=""; print $0}' | sort) <(git rev-list ^release master --oneline | awk '{$1=""; print $0}' | sort)

这应该获取可从发布但不能从 master 访问的提交并对它们进行排序。然后它将获取从 master 可访问但不能从 release 访问的提交,并对它们进行排序。基于公共排序字符串,comm应该根据消息标题告诉您,两个分支之间是否有任何公共。

我们希望对字符串进行排序,因为可能存在某些提交的顺序不完美的情况,因此comm无法正确告诉我们它们是否相同。


我在本地对其进行了测试,它应该为您提供某种形式的正确输出,但也许您有不同的用例。


现在您有了提交的标题,您可以git log查看它们并准确查看哪些提交是精心挑选的。

我们可以把这个东西放在一个脚本中,看起来像这样

#!/bin/bash

titles=$(comm -12 <(git rev-list ^release master --oneline | awk '{$1=""; print $0}' | sort) <(git rev-list ^master release --oneline | awk '{$1=""; print $0}' | sort))

IFS=$'\n' read -rd '' -a ts <<<"$titles"
for t in "${ts[@]}"; do    
    c=$(echo $t | tr -d '\n')
    git log master --oneline --grep "$c"
    # Or if you don't want to see a dialog from git log, use this below instead
    git log master --oneline --grep "$c" | grep "$c"
done
于 2021-04-09T09:51:40.110 回答
1

您的问题与我几个月前读到的关于识别重新提交的方法的另一个问题非常相似。与 一样rebasecherry-picking 是关于提取在提交中完成的更改并将它们应用于另一个提交。这些命令都没有跟踪原始提交,git 不需要区分“副本”,主要是因为它们可能会产生冲突,并且生成的提交会有所不同,如您所知。

幸运的是,git 为我们精心挑选的提交提供了很大的帮助:--cherry-pick选项。我邀请您阅读整个描述(--left/right-only也差不多),但这是有趣的部分:

当提交集受到对称差异的限制时,忽略任何引入与“另一侧”的另一个提交相同的更改的提交。

看起来很有希望,对吧?不,这是问题所在:与另一个 commit 相同的更改。如果在冲突解决后精心挑选的提交不同怎么办?Git 无法将其标记为精选,因为它们不再与补丁等效,并且此选项还不够。从最简单的情况(不是您的情况)开始,所有精选的提交都已成功应用于另一个分支,您可以通过以下方式解决:

git log --format="%h %s" --cherry-pick --oneline --left-only --no-merges master...release 

文档中对此进行了很好的解释,除了对称差异master的概念外,总而言之,它采用了所有未成功挑选的提交release

正如我所说,它并不完美,但至少我们有一个好的起点:现在我们只需要从这个列表中删除所有提交,其提交消息对应于release分支中另一个提交的提交消息,找到樱桃挑选的产生冲突的提交。这是您剩下要做的唯一可能的检查,不包括 reflog。

这里的脚本(未完全测试):

git log --format="%h %s" --cherry-pick --oneline --left-only --no-merges master...release |
while read cmt_log 
do
    cmt_msg=`echo "${cmt_log}" | awk '{ $1=""; print }'`
    git log --format=" %s" master..release | grep --fixed-string -s "${cmt_msg}" > /dev/null || echo ${cmt_log}
done

基本上,%h %s我只从字符串中保存主题(%s),然后我使用它grep来查找匹配项(如果存在),否则我将其打印到标准输出上。我--fixed-stringgrep选项中指定只是为了确保提交消息不会被解释为正则表达式,例如匹配不应该匹配的内容。

于 2021-04-09T22:39:16.330 回答